Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it safe to pass function pointers around and compare them just like normal object's pointers?

Here is the thing, I have several functions,

void foo() {}
void bar() {}

And I want to pass these functions around just like ordinary objects' pointers,

int main()
{
    void (*fptr1)() = foo;
    void (*fptr2)() = fptr1;
    void (*fptr3)() = bar;

    if (fptr1 == foo)
        printf("foo function\n");
    if (fptr2 == foo)
        printf("foo function\n");
    if (fptr3 == foo)
        printf("foo function\n")
}

Can I use these function pointers this way? And I wrote a program to test it, seems like ok. Furthermore, I think, not like ordinary objects which may lie in stack or heap, functions reside in text segment (right?), so when I refer to foo, does it give me the physical address at which function foo lies in the text segment?

FOLLOW UP

If I indeed work with DLL, consider this: first, a function ptr fptr is assigned a function,

ReturnType (*fptr)(ArgType) = beautiful_func;

Two scenarios here,

1) if beautiful_func is not in DLL, then it is safe to use this fptr.

2) if it is in DLL, then later, I think it would be unsafe to use fptr, because it now may refer to a totally different function which is not fptr was born for, right?

like image 924
Alcott Avatar asked Nov 28 '12 07:11

Alcott


1 Answers

You can check if two function pointers are equal just by simply == them, as they are just normal pointers. That's obvious.

However, when you are say "compare", check what you really have in your mind:

  • are you interested in detecting that you are given a different "thing"
  • or are you interested in detecting that you are given different function?

comparing pointers (not only function pointers! it applies to all of them) is a bit risky: you are not checking the contents (logical identity), but just the location ("physical" identity). Most of the time it really is the same, but sometimes, beware, you stumble upon copies.

It is obvious that if you create an array with numbers 1,2,3,4 and then allocate another array and copy the contents there, then you get two different pointers, right? But the array may be SAME for you, depending on what you need it for.

With function pointers the problem is just the same, and even more: you don't actually know what the compiler/linker has done with your code. It might have opitmized few things, it might have merged some not-exported functions together if it noticed them equal, it might have copied or inlined others.

Especially that may happen when working with bigger separate "subprojects". Imagine you wrote a sorting function, then include it with subproject A, and subproject B, compile/build everything, then link and run. Will you end with one sort functions or two? Hard question until you actually check and tailor the linkage options properly.

This is a bit more complex than with arrays. With arrays, you got different pointer if the array was different. Here, the same function may have many different addresses. It might be especially noticeable when working with templates in C++, but that again depends on how well the linker did his job.. Oh, great example: DLLs. With three DLLs based on similar code, they almost have guaranteeded to have three copies of everything they were statically linked to.

And when talkig about DLLs... You know that they can load/unload additional code into your memory, right? This means that when you load a DLL, at some address XYZ a function appears. Then you unload it, and it goes away. But when you now load different DLL? Of course the OS is allowed to reuse the space, and it is allowed to map a newly loaded DLL into the same area as previous one. Most of the time you will not notice it, as newly loaded DLL will be mapped into different region, but it may happen.

This means that while you can compare the pointers, the only answer you get is: are the pointers same or not?

  • if they not same, then you SIMPLY DON'T KNOW; different function pointer does not mean that the function is different. It may be so, it will be so in 99% of cases, but does not have to be different

  • if they are same:

    • if you are NOT loading/unloading the various dynamic libraries large number of times, you might assume that nothing changes and you may be sure got the same function/object/array as before

    • if you are working with unloadable dynamic modules, you'd better not assume that at all, unless you are absolutely sure that none of the pointers comes from a DLL that will be unloaded in future. Note that it some libraries use dynamic libraries for "plugin-like" functionality. Be careful with pointers from them, and watch for plugin load/unload notifications. Your function may change when a dynamic library is unloaded.

EDIT TO FOLLOWUP:

Unless you (or some library you use) ever unload the DLL, then your pointer-to-function-that-targets-a-DLL is safe to use.

Once the DLL is loaded, the only evil thing that can change the meaning of address that this DLL has taken is unloading the dynamic module.

If you are sure that:

  • (1) either your pointer-to-function does not target a function from dynamic module (points to statically-linked code only)
  • (2) or it targets a dynamic module, but that dynamic module is never unloaded (ok: until program quits or crashes)
  • (3) or it targets a dynamic module, and you precisely know which one, and that dynamic module is sometimes unloaded during the runtime, but your code gets some 'prior notification' about that fact

then your pointer to function is safe to store and use and compare, provided that you add some safety measures:

  • for (1), no safety measures are needed: the functions will not get replaced
  • for (2), no safety measures are needed: the functions will not get until program quits
  • for (3), safety measures are needed: you must listen to those notifications, and once you get notified about DLL being unloaded, you must immediatelly forget all pointers that target DLL. You are still safe to remember any other. You are still safe to re-remember it when it gets loaded again.

If you suspect that your pointer-to-function does targets a function from dynamic module that will be unloaded at some point of time before program quits, and:

  • you don't actually know which DLL is pointed by that pointer
  • or that DLL will be unloaded at any point without any notice

then your pointer to function is unsafe to use at all. And by at all I mean AT ALL in any way. Dont store it, as it may instantly evaporate immediately.

like image 137
quetzalcoatl Avatar answered Oct 29 '22 22:10

quetzalcoatl