-1

I am asking myself why this piece of code works well when I haven't allocated memory for fptr. I would expect that it has rather an Undefined Behavior because of doing memcpy without allocating memory for fptr or?

struct conf *pconf = NULL; 
void (*fptr)(char *, struct conf **);
void *temp = dlsym(dlptr, "config_run_all"); 
memcpy(&fptr, &temp, sizeof fptr); 
fptr("test.conf", &pconf);
user3329849
  • 9
  • 1
  • 2
  • 2
    I am confused by the question; why do you say you haven't allocated memory for `fptr`? It's a variable; it is by definition a storage location. – Eric Lippert Mar 26 '14 at 14:41
  • 1
    This is undefined behaviour, just not for the reason you think it is. If I recall correctly, a void pointer is allowed to be larger than a function pointer and therefore you might not be copying the right bits into `fptr`. – Eric Lippert Mar 26 '14 at 14:50
  • 1
    @EricLippert Unfortunately, using the POSIX function `dlsym` requires you to use behavior that is undefined according the C standard. But casting is better than `memcpy`. – interjay Mar 26 '14 at 15:04

3 Answers3

3

You have allocated memory for fptr:

void (*fptr)(char *, struct conf **);`

This declares fptr as a pointer to function.

The memcpy() assigns the value from temp into fptr, making it so that fptr points to the function that temp points to.

What would be problematic would be omitting the & from the memcpy(); then you'd be trying to copy to memory when fptr has not been set to point to anything.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • What about the fact that he's copying a `void *` into a function pointer? I think it's problematic since these pointer types are not necessarily the same size. – Filipe Gonçalves Mar 26 '14 at 14:55
  • @FilipeGonçalves: We had the same thought at the same time; see the comments above. – Eric Lippert Mar 26 '14 at 15:18
  • @EricLippert yea, I just read it. And then I saw interjay's comment, which kind of explains the rationale behind the code. But still, I'd prefer to cast. – Filipe Gonçalves Mar 26 '14 at 15:21
  • 1
    @FilipeGonçalves: The situation is complicated as POSIX 2013 removed the explicit guarantee that pointers to functions and pointers to objects have the same size. As I understand it, they've added the burden to the `dlsym()` function. I have documentation on it, but I've not yet assimilated it. Some pointers: _Change Number: XSH/TC1/D5/0017 [74] [...] Section: 2.12.3 Pointer Types Delete Section 2.12.3: [...] Rationale: Austin Group Defect Report(s) applied: 74. See http://austingroupbugs.net/view.php?id=74 The full text of TC1 [as] document U130 at http://www.opengroup.org/bookstore_ – Jonathan Leffler Mar 26 '14 at 17:24
2

Your code is basically equivalent to:

struct conf *pconf = NULL; 
void (*fptr)(char *, struct conf **) = (void (*)(char*, struct conf**)) dlsym(dlptr, "config_run_all"); 
fptr("test.conf", &pconf);

witout temp.

ldav1s
  • 15,885
  • 2
  • 53
  • 56
2

The clue is in the memcpy invocation.

memcpy(&fptr, &temp, sizeof fptr); 

You are copying to the address of the pointer, not dereferencing it. This is overwriting the memory of the pointer variable itself, not what it points to (which is nothing).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user2675345
  • 531
  • 3
  • 12