Counting pointers to functions

Hi all,

I'm trying to write an LLVM pass which would determine whether there is any
pointer which ever points to a function. I couldn't figure out if there is
any existing pass which does something of the kind (maybe some analysis pass
which I'm not aware of?).

Of course, I could just iterate over all values, and check whether they
point to functions (as in a similar recent post). However, this will not
always be sufficient - for example, consider the following C code:

#include "stdio.h"

int foo(){
  printf ("Reached function foo\n");
  return 0;
}
int bar(){
  printf("Reached function bar\n");
  return 1;
}

int main(){
  int (*f_ptr)() = &foo;
  (*f_ptr)();
  int diff = (int)&bar- (int)&foo;
  f_ptr = (int (*)()) ( (int)f_ptr + diff);
  (*f_ptr)();
  
  return 0;
  
}

This code changes f_ptr from pointing at the function foo to pointing at the
function bar, by explicitly advancing the pointer by the difference in
memory addresses between them.

What can I do to catch that kind of behavior?

Thanks for the help (as usual),
Guy

Hi all,

I'm trying to write an LLVM pass which would determine whether there is any
pointer which ever points to a function. I couldn't figure out if there is
any existing pass which does something of the kind (maybe some analysis pass
which I'm not aware of?).

DSA (part of the poolalloc project: https://llvm.org/svn/llvm-project/poolalloc/trunk) is a unification-style points-to analysis that also does call graph construction. In short, it can figure out to which functions a function pointer can point (although I'm not sure how well it does this; points-to analysis is conservative).

That said, read below:

Of course, I could just iterate over all values, and check whether they
point to functions (as in a similar recent post). However, this will not
always be sufficient - for example, consider the following C code:

#include "stdio.h"

int foo(){
  printf ("Reached function foo\n");
  return 0;
}
int bar(){
  printf("Reached function bar\n");
  return 1;
}

int main(){
  int (*f_ptr)() =&foo;
  (*f_ptr)();
  int diff = (int)&bar- (int)&foo;
  f_ptr = (int (*)()) ( (int)f_ptr + diff);
  (*f_ptr)();
  
  return 0;
  
}

This code changes f_ptr from pointing at the function foo to pointing at the
function bar, by explicitly advancing the pointer by the difference in
memory addresses between them.

What can I do to catch that kind of behavior?

I am not a language lawyer, but I believe this is considered undefined behavior in C. In C, it is illegal to create a pointer that points within one memory object and advance it past the bounds of one memory object and into another memory object. I can't see taking a function pointer and "walking it" from one function into another to be legal.

-- John T.

Nah, this is legal (if you ignore the integer overflow); it's just
computing a-b+b, and all the arithmetic is done on integers. Granted,
I'm not sure what the issue is; it's completely obvious if you look at
the either the original code or the IR that this code uses the address
of bar, and it's impossible for an analysis like this to be perfectly
precise.

-Eli