Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to pass an intptr_t to a function that expects an int?

More specifically, if I have the following function pointer type:

typedef void (*callback_type) (intptr_t context, void* buffer, size_t count);

can I safely and without "undefined behavior" do:

callback_type func_ptr = (callback_type)write;
intptr_t context = fd;

func_ptr(context, some_buffer, buffer_size);

?

Where write() is the system call (EDIT: has the signature ssize_t write(int fd, const void *buf, size_t count);, thus takes an int as the first argument), and fd is an int file descriptor. I assume the answer would be the same for C and C++, so I am tagging both.

like image 801
lvella Avatar asked Apr 06 '13 16:04

lvella


2 Answers

No

That won't be portable because you are passing a parameter that will be a different size in the common LP64 paradigm.

Also, you aren't dereferencing the function pointer with the correct type, and the results of that are undefined.

Now, as you seem to have concluded, the function pointer will work as expected and the only practical problem is going to be: how will write(2) interpret the intptr_t first parameter?

And the actual run-time problem is that, on LP64, you are passing a 64-bit value to a 32-bit parameter. This might misalign the subsequent parameters. On a system with register parameters it would probably work just fine.

like image 117
DigitalRoss Avatar answered Nov 03 '22 21:11

DigitalRoss


Let's have a look at C standard.

C11 (n1570), § 6.3.2.3 Pointers

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.

C11 (n1570), § 6.7.6.3 Function declarators (including prototypes)

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.

C11 (n1570), § 6.2.7 Compatible type and composite type

Two types have compatible type if their types are the same.

Conclusion:

void (*) (intptr_t context, void* buffer, size_t count);

cannot be converted to:

void (*) (int context, void* buffer, size_t count);
like image 24
md5 Avatar answered Nov 03 '22 21:11

md5