1+ void sink (const char *);
2+ void sink (int );
3+
4+ struct S {
5+ void (*f)(const char *);
6+
7+ void apply (char * p) {
8+ f (p);
9+ }
10+
11+ void (*get ())(const char *) {
12+ return f;
13+ }
14+ };
15+
16+ void calls_sink_with_argv (const char * a) {
17+ sink (a);
18+ }
19+
20+ extern int i;
21+
22+ class BaseWithPureVirtual {
23+ public:
24+ virtual void f (const char *) = 0;
25+ };
26+
27+ class DerivedCallsSink : public BaseWithPureVirtual {
28+ public:
29+ void f (const char * p) override {
30+ sink (p);
31+ }
32+ };
33+
34+ class DerivedDoesNotCallSink : public BaseWithPureVirtual {
35+ public:
36+ void f (const char * p) override {}
37+ };
38+
39+ class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
40+ public:
41+ void f (const char * p) override {
42+ sink (p);
43+ }
44+ };
45+
46+ class DerivedDoesNotCallSinkDiamond2 : virtual public BaseWithPureVirtual {
47+ public:
48+ void f (const char * p) override {}
49+ };
50+
51+ class DerivesMultiple : public DerivedCallsSinkDiamond1 , public DerivedDoesNotCallSinkDiamond2 {
52+ void f (const char * p) override {
53+ DerivedCallsSinkDiamond1::f (p);
54+ }
55+ };
56+
57+ template <typename T>
58+ class CRTP {
59+ public:
60+ void f (const char * p) {
61+ static_cast <T*>(this )->g (p);
62+ }
63+ };
64+
65+ class CRTPCallsSink : public CRTP <CRTPCallsSink> {
66+ public:
67+ void g (const char * p) {
68+ sink (p);
69+ }
70+ };
71+
72+ class Derived1 : public BaseWithPureVirtual {};
73+
74+ class Derived2 : public Derived1 {
75+ public:
76+ void f (const char * p) override {}
77+ };
78+
79+ class Derived3 : public Derived2 {
80+ public:
81+ void f (const char * p) override {
82+ sink (p);
83+ }
84+ };
85+
86+ class CRTPDoesNotCallSink : public CRTP <CRTPDoesNotCallSink> {
87+ public:
88+ void g (const char * p) {}
89+ };
90+
91+ int main (int argc, char *argv[]) {
92+ sink (argv[0 ]);
93+
94+ sink (reinterpret_cast <int >(argv));
95+
96+ calls_sink_with_argv (argv[1 ]);
97+
98+ char *** p = &argv;
99+
100+ sink (*p[0 ]);
101+
102+ calls_sink_with_argv (*p[i]);
103+
104+ sink (*(argv + 1 )); // flow [NOT DECTED by AST]
105+
106+ BaseWithPureVirtual* b = new DerivedCallsSink;
107+
108+ b->f (argv[1 ]); // flow [NOT DETECTED by IR]
109+
110+ b = new DerivedDoesNotCallSink;
111+ b->f (argv[0 ]); // no flow [FALSE POSITIVE by AST]
112+
113+ BaseWithPureVirtual* b2 = new DerivesMultiple;
114+
115+ b2->f (argv[i]); // flow [NOT DETECTED]
116+
117+ CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
118+ crtp_not_call_sink.f (argv[0 ]);
119+
120+ CRTP<CRTPCallsSink> crtp_calls_sink;
121+ crtp_calls_sink.f (argv[0 ]); // flow [NOT DETECTED]
122+
123+ Derived1* calls_sink = new Derived3;
124+ calls_sink->f (argv[1 ]); // flow [NOT DETECTED by AST]
125+
126+ static_cast <Derived2*>(calls_sink)->f (argv[1 ]); // flow [NOT DETECTED]
127+
128+ dynamic_cast <Derived2*>(calls_sink)->f (argv[1 ]); // flow [NOT DETECTED by IR]
129+ }
0 commit comments