I forgot to send the daily report yesterday, so this one covers the work done 
on both days
AIM : 

- make the analyzer call the function with the updated call-string 
representation ( even the ones that doesn’t have a superedge )
- make the analyzer figure out the point of return from the function called 
without the superedge
- make the analyser figure out the correct point to return back in the caller 
function
- make enode and eedge representing the return call
- test the changes on the example I created before
- speculate what GCC generates for a vfunc call and discuss how can we use it 
to our advantage

—

PROGRESS  ( changes can be seen on "refs/users/arsenic/heads/analyzer_extension 
“ branch of the repository ) :

- Thanks to the new call-string representation, I was able to push calls to the 
call stack which doesn’t have a superedge and was successfully able to see the 
calls happening via the function pointer.

- To detect the returning point of the function I used the fact that such 
supernodes would contain an EXIT bb, would not have any return superedge and 
would still have a pending call-stack. 

- Now the next part was to find out the destination node of the return, for 
this I again made use of the new call string and created a custom accessor to 
get the caller and callee supernodes of the return call, then I extracted the 
gcall* from the caller supernode to ulpdate the program state, 

- now that I have got next state and next point, it was time to put the final 
piece of puzzle together and create exploded node and edge representing the 
returning call.

- I tested the changes on the the following program where the analyzer was 
earlier giving a false negative due to not detecting call via a function pointer

```
#include <stdio.h>
#include <stdlib.h>

void fun(int *int_ptr)
{
    free(int_ptr);
}

int test()
{
    int *int_ptr = (int*)malloc(sizeof(int));
    void (*fun_ptr)(int *) = &fun;
    (*fun_ptr)(int_ptr);

    return 0;
}

void test_2()
{
  test();
}
```
( compiler explorer link : https://godbolt.org/z/9KfenGET9 
<https://godbolt.org/z/9KfenGET9> )

and results were showing success where the analyzer was now able to 
successfully detect, call and return from the function that was called via the 
function pointer and no longer reported the memory leak it was reporting 
before. : )

- I think I should point this out, in the process I created a lot of custom 
function to access/alter some data which was not possible before.

- now that calls via function pointer are taken care of, it was time to see 
what exactly happen what GCC generates when a function is dispatched 
dynamically, and as planned earlier, I went to  ipa-devirt.c ( devirtualizer’s 
implementation of GCC ) to investigate.

- althogh I didn’t understood everything that was happening there but here are 
some of the findings I though might be interesting for the project :- 
        > the polymorphic call is called with a OBJ_TYPE_REF which contains 
otr_type( a type of class whose method is called) and otr_token (the index into 
virtual table where address is taken)
        > the devirtualizer builds a type inheritance graph to keep track of 
entire inheritance hierarchy
        > the most interesting function I found was 
“possible_polymorphic_call_targets()” which returns the vector of all possible 
targets of polymorphic call represented by a calledge or a gcall.
        > what I understood the devirtualizer do is to search in these 
polymorphic calls and filter out the the calls which are more likely to be 
called ( known as likely calls ) and then turn them into speculative calls 
which are later turned into direct calls.

- another thing I was curious to know was, how would analyzer behave when 
encountered with a polymorphic call now that we are splitting the superedges at 
every call. 

the results were interesting, I was able to see analyzer splitting supernodes 
for the calls right away but this time they were not connected via a 
intraprocedural edge making the analyzer crashing at the callsite ( I would 
look more into it tomorrow ) 

the example I used was : -
```
struct A
{
    virtual int foo (void) 
    {
        return 42;
    }
};

struct B: public A
{
  int foo (void) 
    { 
        return 0;
    }
};

int test()
{
    struct B b, *bptr=&b;
    bptr->foo();
    return bptr->foo();
}
```
( compiler explorer link : https://godbolt.org/z/d986ab7MY 
<https://godbolt.org/z/d986ab7MY> )

—

STATUS AT THE END OF THE DAY :- 

- make the analyzer call the function with the updated call-string 
representation ( even the ones that doesn’t have a superedge ) (done)
- make the analyzer figure out the point of return from the function called 
without the superedge (done)
- make the analyser figure out the correct point to return back in the caller 
function (done)
- make enode and eedge representing the return call (done)
- test the changes on the example I created before (done)
- speculate what GCC generates for a vfunc call and discuss how can we use it 
to our advantage (done)


Thank you
- Ankur

Reply via email to