AIM For Today: - Make the anlalyzer evaluate the vfunc calls by creating enodes and eedges representing the call.
- Make the analyzer not treat such calls as call to "unknown function" --- PROGRESS : - After the analyzer sucessfully found which funcitons to call ( thanks to functions from ipa-devirt.c ), All that was left was it to create enodes and eedges for analyzeing such calls for which I took the same aproach I used to detect and analyzer calls via function pointers. - now the analyzer was sucessfully decting and analyzing the calls via functions pointers, but due to some reason it was still not giving out analysis reports for such calls. - After a bit of digging, I found out that analyzer was also treating such calls as " call to unknown funcitons " and in case of such calls, analyzer plays safe by resetting all of the state-machine state for the values that are reachable by the function call, to avoid false reports. ( it was also mentioned in a previous discussions <https://gcc.gnu.org/pipermail/gcc/2021-April/235335.html> on the list) - I fixed the porblem by simply updating exploded_node::on_stmt () by setting the value of "unknown_side_effects" ( a boolean which is set true when analyzer thinks executing a gimple stmt would cause some side effects, and acts conservatively for such cases ) to "false" when gimple call stmt is a polymorphic call. Some thing like this, at the end of the definition of exploded_node::on_stmt (): - File: {src-dir}/gcc/analyzer/engine.cc 1246: /* If the statmement is a polymorphic call then assume 1247: there are no side effects. */ 1248: gimple *call_stmt = const_cast<gimple *>(stmt); 1249: if (gcall *call = dyn_cast<gcall *> (call_stmt)) 1250: { 1251: function *fun = this->get_function(); 1252: cgraph_edge *e = cgraph_node::get (fun->decl)->get_edge (call); 1253: if ((e && e->indirect_info) && (e->indirect_info->polymorphic)) 1254: unknown_side_effects = false; 1255: } 1256: 1257: on_stmt_post (stmt, state, unknown_side_effects, &ctxt); 1258: 1259: return on_stmt_flags (); - After this the analyzer was working as expected for virtual function calls on all of the examples I created. - Let's take example of the following program ( the same program which was mentioned in proposal, for which analyzer was giving out a false positive ) File: test.cpp 01: #include <cstdlib> 02: 03: struct A 04: { 05: virtual int foo (void) 06: { 07: return 42; 08: } 09: }; 10: 11: struct B: public A 12: { 13: int *ptr; 14: void alloc () 15: { 16: ptr = (int*)malloc(sizeof(int)); 17: } 18: int foo (void) 19: { 20: free(ptr); 21: return 0; 22: } 23: }; 24: 25: int test() 26: { 27: struct B b, *bptr=&b; 28: b.alloc(); 29: bptr->foo(); 30: return bptr->foo(); 31: } 32: 33: int main() 34: { 35: test(); 36: } 37: ( godbolt link of the above code (https://godbolt.org/z/n17WK4MxG) ) for the same porgram, the analyzer now generates the following warning message : warning: double-‘free’ of ‘b.B::ptr’ [CWE-415] [-Wanalyzer-double-free] 20 | free(ptr); | ~~~~^~~~~ ‘int test()’: events 1-2 | | 25 | int test() | | ^~~~ | | | | | (1) entry to ‘test’ |...... | 28 | b.alloc(); | | ~~~~~~~~~ | | | | | (2) calling ‘B::alloc’ from ‘test’ | +--> ‘void B::alloc()’: events 3-4 | | 14 | void alloc () | | ^~~~~ | | | | | (3) entry to ‘B::alloc’ | 15 | { | 16 | ptr = (int*)malloc(sizeof(int)); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (4) allocated here | <------+ | ‘int test()’: events 5-6 | | 28 | b.alloc(); | | ~~~~~~~^~ | | | | | (5) returning to ‘test’ from ‘B::alloc’ | 29 | bptr->foo(); | | ~~~~~~~~~~~ | | | | | (6) calling ‘B::foo’ from ‘test’ | +--> ‘virtual int B::foo()’: events 7-8 | | 18 | int foo (void) | | ^~~ | | | | | (7) entry to ‘B::foo’ | 19 | { | 20 | free(ptr); | | ~~~~~~~~~ | | | | | (8) first ‘free’ here | <------+ | ‘int test()’: events 9-10 | | 29 | bptr->foo(); | | ~~~~~~~~~^~ | | | | | (9) returning to ‘test’ from ‘B::foo’ | 30 | return bptr->foo(); | | ~~~~~~~~~~~ | | | | | (10) calling ‘B::foo’ from ‘test’ | +--> ‘virtual int B::foo()’: events 11-12 | | 18 | int foo (void) | | ^~~ | | | | | (11) entry to ‘B::foo’ | 19 | { | 20 | free(ptr); | | ~~~~~~~~~ | | | | | (12) second ‘free’ here; first ‘free’ was at (8) | - Sorry no patch for the following changes available right now as there is still a bit of cleaning and refining left to do in it ( will post the patch with tomorrow's report ) - That being said, I also want to test the working of this patch with a few more examples of vfunc calls to check for a possible loophole. --- STATUS AT THE END OF THE DAY :- - Make the anlalyzer evaluate the vfunc calls by creating enodes and eedges representing the call. ( done ) - Make the analyzer not treat such calls as call to "unknown function" ( done ) Thank you - Ankur