Different sizes of data and function pointers on a machine -- void*return type of malloc, calloc, an


M

Myth__Buster

In reference with the below code,

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

int f(void)
{
printf("\n In f . . . \n");
}

int main(void)
{
int (*p)(void) = malloc(sizeof(int (*)(void)));

return 0;
}

I would like to question about the return type of malloc(calloc, and realloc).

Assume that the above code runs on a machine wherein the data pointers and function pointers are of different sizes. Then, what malloc returns is a function pointer but after casting it to void* while returning(Or, after assigning it to a void* variable internally and returning its value).

Now, isn't malloc giving us the truncated address in the above context? Consider the same question applicable to calloc and realloc when used in such a context.

Cheers,
Raghavan Santhanam
 
Ad

Advertisements

J

James Kuyper

In reference with the below code,

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

int f(void)
{
printf("\n In f . . . \n");
}

int main(void)
{
int (*p)(void) = malloc(sizeof(int (*)(void)));

"The pointer returned if the allocation succeeds is suitably aligned so
that it may be assigned to a pointer to any type of object ..."
(7.22.3p1). Note carefully that this only applies to pointers to object
types, not function types.

The code above converts a pointer to void into a pointer to a function
type. The behavior of this code is well-defined if malloc() fails,
because 6.3.6.2p4 says "Conversion of a null pointer to another pointer
type yields a null pointer of that type." However, the behavior of this
code is undefined if malloc() returns a non-null pointer "by omission of
any explicit definition of the behavior" (4p2). The only other
conversion defined by the standard that involves function pointer types
is the conversion from one function pointer type to another (6.3.6.3p8),
which doesn't apply here.
return 0;
}

I would like to question about the return type of malloc(calloc, and
realloc).

All three functions behave the same, as far as the issue raided by your
message is concerned.
Assume that the above code runs on a machine wherein the data
pointers and function pointers are of different sizes. Then, what
malloc returns is a function pointer ...

That's incorrect - what gave you that idea? The rest of your message
depends upon that misconception, so I'll just stop here.
 
M

Myth__Buster

malloc always returns a data pointer. You can ask it to return a data
pointer to some memory area that is big enough to hold a function
pointer, but it will still be a data pointer.

Maybe the situation would be less confusing to you if you first
declare a struct with a single member that is a function pointer, then
use malloc to return a data pointer pointing to one such struct.

Yeah, had thought of it earlier(struct-approach being feasible due to data pointer involvement). But, wanted to accomplish the same with a malloc callby passing the sizeof a function pointer. So, malloc's documentation should include a note on this, isn't it?
 
J

James Kuyper

Yeah, had thought of it earlier(struct-approach being feasible due to data pointer involvement). But, wanted to accomplish the same with a malloc call by passing the sizeof a function pointer. So, malloc's documentation should include a note on this, isn't it?

I think you've got some confusion about something, possibly about levels
of indirection. Could you give an example of what you wanted to do with
such a pointer? I noticed that your original message contained a
definition for a function named f, which was not used in any way within
your code - I suspect that has something to do with your question, but
I'm not sure what.
 
M

Myth__Buster

"The pointer returned if the allocation succeeds is suitably aligned so
that it may be assigned to a pointer to any type of object ..."
(7.22.3p1). Note carefully that this only applies to pointers to object
types, not function types.

The code above converts a pointer to void into a pointer to a function
type. The behavior of this code is well-defined if malloc() fails,
because 6.3.6.2p4 says "Conversion of a null pointer to another pointer
type yields a null pointer of that type." However, the behavior of this
code is undefined if malloc() returns a non-null pointer "by omission of
any explicit definition of the behavior" (4p2). The only other
conversion defined by the standard that involves function pointer types
is the conversion from one function pointer type to another (6.3.6.3p8),
which doesn't apply here.


All three functions behave the same, as far as the issue raided by your
message is concerned.


That's incorrect - what gave you that idea? The rest of your message
depends upon that misconception, so I'll just stop here.

Well, am aware of the possible implications of converting a void* into a function pointer. But, the initialization of function pointer p is present only for the completeness of the code. For the question being discussed, let's consider the code as under :

#include <stdlib.h>
int main(void)
{
(void)malloc(sizeof(int (*)(void))); // Ignore the usability of this statement, possible
// memory-leaks, and any other trivial factors involved
// which are irrelevant to the question being discussed.
return 0;
}

Now, would like to reiterate myself - malloc() returns a void*(data pointeras always known) even when we have allocated memory for a function pointeron a machine wherein data and function pointers are of different sizes. This behavior of malloc appears to me as improper and hence I am questioning its generality of returning a void*(data pointer) always. Shouldn't there be a note in malloc's documentation regarding such usage?

Cheers,
Raghavan Santhanam
 
E

Eric Sosman

Yeah, had thought of it earlier(struct-approach being feasible due to data pointer involvement). But, wanted to accomplish the same with a malloc call by passing the sizeof a function pointer. So, malloc's documentation should include a note on this, isn't it?

Wouldn't that be sort of like "Warning: May Contain Nuts" on
a bag of peanuts?

Aiming a function pointer at allocated memory (at any data object,
for that matter) is non-portable, as you've observed. But filling the
allocated memory with something that can be called like a function is
also non-portable. Seems to me that anyone playing such games already
needs a good deal of non-portable knowledge about the implementation:
He's purchased his packet of peanuts, on purpose.
 
Ad

Advertisements

B

Ben Bacarisse

Myth__Buster said:
Yeah, had thought of it earlier(struct-approach being feasible due to
data pointer involvement). But, wanted to accomplish the same with a
malloc call by passing the sizeof a function pointer. So, malloc's
documentation should include a note on this, isn't it?

No, there is no problem with what you say you want to do, just how you
are doing it.

malloc(sizeof (int (*)(void)))

is fine. It allocates enough room for a pointer to a function, but what
it returned is a pointer to that space. I.e. the correct way to store
the result is either as a void * (which is not often that useful) or as
a pointer to a pointer to a function:

int (**p)(void) = malloc(sizeof (int (*)(void)));

It's an mistake to try to convert what comes back from malloc into a
pointer to a function. Even if you could so this safely (and you might
on some forgiving systems) the space you allocate should be for a
function, not a pointer to one.

So, if you want to allocate space for a pointer to a function, go right
ahead, as above. If you want to allocate space for a function (and thus
get a pointer to one from malloc) you are out of luck in standard C. It
might be possible to get round some of the problems on some systems, but
that's another matter.

Note that the comp.lang.c approved what to write malloc calls helps here
(like it helps inmost cases). The patter being:

T *p = malloc(sizeof *p);

You can write the allocation like this:

int (**p)(void) = malloc(sizeof *p);

Had you tried to other possibility:

int (*p)(void) = malloc(sizeof *p);

you should expect an error message -- something along the lines of:

warning: invalid application of 'sizeof' to a function type

So, after all that, what do you want -- to allocate space for a function
pointer, or to allocate space for a function?
 
M

Myth__Buster

Wouldn't that be sort of like "Warning: May Contain Nuts" on
a bag of peanuts?

Aiming a function pointer at allocated memory (at any data object,
for that matter) is non-portable, as you've observed. But filling the
allocated memory with something that can be called like a function is
also non-portable. Seems to me that anyone playing such games already
needs a good deal of non-portable knowledge about the implementation:
He's purchased his packet of peanuts, on purpose.

The programmer might be well aware of this inability of malloc in returninga function pointer. However, shouldn't there be a relevant note under malloc's documentation for the sake of clarity and completeness of malloc's behavior?

Cheers,
Raghavan Santhanam
 
J

James Kuyper

On 06/25/2012 03:28 PM, Myth__Buster wrote:
....
Well, am aware of the possible implications of converting a void* into a function pointer. But, the initialization of function pointer p is present only for the completeness of the code. For the question being discussed, let's consider the code as under :

#include <stdlib.h>
int main(void)
{
(void)malloc(sizeof(int (*)(void))); // Ignore the usability of this statement, possible
// memory-leaks, and any other trivial factors involved
// which are irrelevant to the question being discussed.
return 0;
}

Now, would like to reiterate myself - malloc() returns a void*(data pointer as always known) even when we have allocated memory for a function pointer on a machine wherein data and function pointers are of different sizes. This behavior of malloc appears to me as improper and hence I am questioning its generality of returning a void*(data pointer) always. Shouldn't there be a note in malloc's documentation regarding such usage?

That depends upon what the problem is that you're talking about, which I
do not yet understand. If it is a problem with the specification of
malloc() provided by the C standard, then by definition the
documentation of malloc() already mentions it, if only implicitly. If
it's a problem with a particular implementation of malloc(), I agree
with you that the implementation's documentation for malloc() should be
modified to mention it.

Could you provide an example of code that would cause problems due to
the impropriety you perceive? The above code has no problems worse than
a memory leak. malloc() allocates enough space to store a pointer to a
function type, even if that space is larger than would be needed to
store a pointer to an object type. The function pointer itself has an
object type, and malloc() returns a void* pointer that can be converted
to pointer to a function pointer of that type, which is itself a data
pointer, and therefore, on such an implementation, has a different size.

Let me provide my own example, based upon yours, which may clarify the
issue for you:

#include <stdlib.h>
int f(void) {
printf("f() will return 1.\n");
return 1;
}

int main(void)
{
int (**p)(void) = malloc(sizeof *p);
if(p)
{
printf("p() returned %d\n", (*p)());
free(p);
}
return 0;
}

Now, *p has a pointer-to-function type: int (*)(void). p itself has a
pointer-to-data type: int (**)(void). On a machine such as you describe,
sizeof p would be different from sizeof *p. If all pointers on that
machine have only one of those two sizes, then sizeof(void*), the size
of the pointer that is returned by malloc(), will certainly be the same
as sizeof p, not sizeof *p. I get the impression that you consider this
problematic. Could you provide an explanation or at least an example of
how you think this could be problematic?

Note: under modern C rules, (*p)() could also have been written as
simply p(), without change in meaning. This is a syntactic convenience,
but potentially confusing. In this context I thought I should avoid any
unnecessary potential confusion.
 
E

Eric Sosman

[...]
Yeah, had thought of it earlier(struct-approach being feasible due to data pointer involvement). But, wanted to accomplish the same with a malloc call by passing the sizeof a function pointer. So, malloc's documentation should include a note on this, isn't it?

Wouldn't that be sort of like "Warning: May Contain Nuts" on
a bag of peanuts?

Aiming a function pointer at allocated memory (at any data object,
for that matter) is non-portable, as you've observed. But filling the
allocated memory with something that can be called like a function is
also non-portable. Seems to me that anyone playing such games already
needs a good deal of non-portable knowledge about the implementation:
He's purchased his packet of peanuts, on purpose.

The programmer might be well aware of this inability of malloc in returning a function pointer. However, shouldn't there be a relevant note under malloc's documentation for the sake of clarity and completeness of malloc's behavior?

If the programmer is "well aware" that function pointers and data
pointers are incommensurate, what purpose would the note serve? How
would you word such a note? "NOTE: You already know this?"

Programs exist (I have maintained -- and debugged! -- a few)
that allocate memory, fill it with magic values, aim a function
pointer at it, and perform a call through the pointer. I suggest
that anyone writing such code is already keenly aware that it is
non-portable, also keenly aware of specific characteristics of his
C implementation that are not part of the C language. He already
knows whether his system's function pointers are bare addresses or
more structured "function descriptors," he knows about special
prologue and epilogue sequences that wrap the instructions, he
knows about cache-coherency incantations that must be performed
between filling the memory and calling its content, and so on, and
so on.

But perhaps I'm missing something, some other purpose for aiming
a function pointer at data. What do you intend to *do* with the data?
 
K

Keith Thompson

Myth__Buster said:
In reference with the below code,

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

int f(void)
{
printf("\n In f . . . \n");
}

int main(void)
{
int (*p)(void) = malloc(sizeof(int (*)(void)));

return 0;
}

The above code is invalid; it contains a constraint violation, and any
conforming compiler must at least emit a diagnostic for it.

malloc() returns a result of type void*. You're attempting to use that
result to initialize an object of type int(*)(void), i.e., a
pointer-to-function type.

Initialization imposes the same type requirements as simple assignment.

Section 6.5.16.1 of N1570 lists the valid combinations of types for a
simple assignment; the list does not include this case.

There's an implicit conversion from void* to any pointer-to-object
type. There is no such implicit conversion from void* to any
pointer-to-function type.
I would like to question about the return type of malloc(calloc, and
realloc).

Assume that the above code runs on a machine wherein the data pointers
and function pointers are of different sizes. Then, what malloc
returns is a function pointer but after casting it to void* while
returning(Or, after assigning it to a void* variable internally and
returning its value).

Now, isn't malloc giving us the truncated address in the above
context? Consider the same question applicable to calloc and realloc
when used in such a context.

If you make the conversion explicit, using a cast, then I believe there
is no constraint violation:

int (*p)(void) = malloc(sizeof(int (*)(void)));

However the standard says nothing about the behavior of a conversion
from void* to a pointer-to-function type, so the behavior is undefined
by omission. The standard says nothing about "truncating" pointer
values; it simply doesn't define the result or behavior of the
conversion.

The authors of gcc apparently interpret the standard differently; with
"-std=c99 -pedantic", gcc 5.7 warns:

warning: ISO C forbids conversion of object pointer to function pointer type [-pedantic]

I'll post to comp.std.c and see if I can get this clarified.

What is your code intended to do? If you're trying to allocate space
for a single function pointer, then you need a
pointer-to-pointer-to-function to point to it.
 
Ad

Advertisements

M

Myth__Buster

No, there is no problem with what you say you want to do, just how you
are doing it.

malloc(sizeof (int (*)(void)))

is fine. It allocates enough room for a pointer to a function, but what
it returned is a pointer to that space. I.e. the correct way to store
the result is either as a void * (which is not often that useful) or as
a pointer to a pointer to a function:

int (**p)(void) = malloc(sizeof (int (*)(void)));

It's an mistake to try to convert what comes back from malloc into a
pointer to a function. Even if you could so this safely (and you might
on some forgiving systems) the space you allocate should be for a
function, not a pointer to one.

So, if you want to allocate space for a pointer to a function, go right
ahead, as above. If you want to allocate space for a function (and thus
get a pointer to one from malloc) you are out of luck in standard C. It
might be possible to get round some of the problems on some systems, but
that's another matter.

Note that the comp.lang.c approved what to write malloc calls helps here
(like it helps inmost cases). The patter being:

T *p = malloc(sizeof *p);

You can write the allocation like this:

int (**p)(void) = malloc(sizeof *p);

Had you tried to other possibility:

int (*p)(void) = malloc(sizeof *p);

you should expect an error message -- something along the lines of:

warning: invalid application of 'sizeof' to a function type

So, after all that, what do you want -- to allocate space for a function
pointer, or to allocate space for a function?

Well,

Yeah, I know, that's the usual pattern - when we allocate a certain chunk of memory for an object of type T, we would be storing the respective malloc's return value in an object of type T*. No questions on that beginner's aspect.

In my question being discussed, we are allocating space for a function pointer which might *not* be of same size as that of a data pointer on some machines. No questions on the allocation. It's fine and clear to me. But, the data pointer(void*) being returned by malloc will be improper to access theallocated space for the function pointer. And hence, I would like to see arelevant note under malloc's documentation.

Of course, I would like to allocate space for a function pointer using malloc without any dependency on any third-variable such as struct variable, etc, and use it thereafter(regarding the usage, that will be another story. Iam interested in getting a proper pointer in the first place from malloc).And yeah, in the realms of C, allocating space for a function is meaningless as we know sizeof a function makes no sense. :)

Cheers,
Raghavan Santhanam
 
P

Paul N

In reference with the below code,

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

int f(void)
{
    printf("\n In f . . . \n");

}

int main(void)
{
    int (*p)(void) = malloc(sizeof(int (*)(void)));

    return 0;

}

I would like to question about the return type of malloc(calloc, and realloc).

Assume that the above code runs on a machine wherein the data pointers and function pointers are of different sizes. Then, what malloc returns is a function pointer but after casting it to void* while returning(Or, after assigning it to a void* variable internally and returning its value).

Now, isn't malloc giving us the truncated address in the above context? Consider the same question applicable to calloc and realloc when used in such a context.

I'm not sure what you're trying to do. Is your idea to make a copy of
f and then stomp all over the code of the copy so that it does
something different from f itself? Or are you simply wanting to call
already-existing functions?

If you are really trying to re-write a function, then you will need to
know a lot about how your particular system works. For instance, you
will need to know how big the function is, which I don't think
standard C can tell you.

If, instead, you simply have several functions and you want to use a
function pointer to call them, then it's probably easiest just to use
a variable of type pointer-to-function and not mess about with malloc
at all.

Hope that helps.
Paul.
 
I

Ian Collins

On 06/26/12 08:14 AM, Myth__Buster wrote:

Please wrap your lines!
Well,

Yeah, I know, that's the usual pattern - when we allocate a certain chunk of memory for an object of type T, we would be storing the respective malloc's return value in an object of type T*. No questions on that beginner's aspect.

In my question being discussed, we are allocating space for a function pointer which might *not* be of same size as that of a data pointer on some machines. No questions on the allocation. It's fine and clear to me. But, the data pointer(void*) being returned by malloc will be improper to access the allocated space for the function pointer. And hence, I would like to see a relevant note under malloc's documentation.

What would that achieve? malloc returns a void* and a void* is not
compatible with a function pointer. Would you add a note for every
function that returns something incompatible with something else?
 
J

James Kuyper

On 06/25/2012 04:14 PM, Myth__Buster wrote:
....
In my question being discussed, we are allocating space for a
function pointer which might *not* be of same size as that of a data
pointer on some machines. No questions on the allocation. It's fine
and clear to me. But, the data pointer(void*) being returned by
malloc will be improper to access the allocated space for the
function pointer. ...

The function pointer itself has an object type, and you've instructed
malloc() to allocate enough memory to hold it for you. The data pointer
returned by malloc() will be perfectly usable for accessing the memory
you've allocated for the function pointer. Why do you think otherwise?

....
... regarding the usage, that
will be another story. I am interested in getting a proper pointer in
the first place from malloc ...

Don't worry about getting a proper pointer in the first place from
malloc() - if what you're trying to do makes any sense, and if it makes
sense to use malloc() as part of the solution to your problem, then I
guarantee you that the pointer returned by malloc() will be proper.
Telling us what you want to do with this pointer after you've allocated
might help us figure out why you think otherwise.
 
M

Myth__Buster

What would that achieve? malloc returns a void* and a void* is not
compatible with a function pointer. Would you add a note for every
function that returns something incompatible with something else?

Achievement : Clarity and completeness of malloc's behavior in malloc's documentation. More appropriately, a word of caution similar to this - In C, malloc when used to directly allocate memory for function pointers(without any third-variable's allocation such as encompassing struct variable, etc) on machines wherein the data and function pointers are of different sizes, the return data pointer wouldn't be a proper pointer with which the entire memory allocated for function pointer would have been allocated. Hence, careshould be exercised before the allocated memory could be used. (On similarlines, the applicable alternative approaches can be mentioned therein to accomplish the same and thereby help the reader/programmer).

Cheers,
Raghavan Santhanam
 
Ad

Advertisements

M

Myth__Buster

*Completed my sentences.

Achievement : Clarity and completeness of malloc's behavior in malloc's documentation. More appropriately, a word of caution similar to this - In C,malloc when used to directly allocate memory for function pointers(withoutany third-variable's allocation such as encompassing struct variable, etc)on machines wherein the data and function pointers are of different sizes,the return data pointer wouldn't be a proper pointer with which the entirememory allocated for function pointer could be accessed. Hence, care should be exercised before the allocated memory could be used. (On similar lines, the applicable alternative approaches can be mentioned therein to accomplish the same and thereby help the reader/programmer).

Cheers,
Raghavan Santhanam
 
I

Ian Collins

Achievement : Clarity and completeness of malloc's behavior in malloc's documentation.

Should it also caution that the return type of malloc is incompatible
with int? with char? with ...
 
K

Keith Thompson

Myth__Buster said:
Well, am aware of the possible implications of converting a void* into
a function pointer. But, the initialization of function pointer p is
present only for the completeness of the code. For the question being
discussed, let's consider the code as under :

#include <stdlib.h>
int main(void)
{
(void)malloc(sizeof(int (*)(void)));
// Ignore the usability of this statement, possible
// memory-leaks, and any other trivial factors involved
// which are irrelevant to the question being discussed.
return 0;
}

Now, would like to reiterate myself - malloc() returns a void*(data
pointer as always known) even when we have allocated memory for a
function pointer on a machine wherein data and function pointers are
of different sizes. This behavior of malloc appears to me as improper
and hence I am questioning its generality of returning a void*(data
pointer) always. Shouldn't there be a note in malloc's documentation
regarding such usage?

The expression

sizeof(int (*)(void))

yields a value of type size_t. The particular value is likely to be 4
or 8 on many typical systems.

malloc() only sees this value as its parameter; it doesn't know or care
that it happens to be the size of a function pointer. So you might as
well have written:
(void)malloc(4);
or
(void)malloc(8);

malloc will attempt to allocate that many bytes of memory, and will
return a void* value that points to it (or a null pointer if the
allocation fails).

If you like, you can then use that allocated memory as an object of
pointer-to-function type. There's nothing problematic about that. A
function pointer is just another data type, like an object pointer, an
integer, a floating-point object, or a struct object.

But if you want to use malloc() to allocate an object of some type, you
need to convert the result to a pointer to that type. Your original
code didn't do that correctly; it attempted to convert the result of
malloc() to a pointer-to-function type rather than to a
pointer-to-pointer-to-function type.

A typedef might make this a bit clearer:

typedef void (*func_ptr)(void);
...
func_ptr *p = malloc(sizeof *p);

p is a pointer to a pointer to function.

Another thing that you might *think* you can do is to set a function
pointer to point to space allocated by malloc():

func_ptr wrong = malloc(some_size);

For this to work, some_size would probably have to indicate the size of
the function. (That's assuming function pointers are implemented as
pointers to the function's code, which is not specified; a function
pointer might instead point to some kind of descriptor, for
example). You'd also need some way to initialize the newly allocated
memory so it acts like a function. This can be done on some systems, but
it's *extremely* system-specific.

What I *think* you're trying to do is allocate a single
pointer-to-function object using malloc() (that's the closest thing to
the code you showed us that makes any sense). But it's not clear *why*
you're doing this. If you're only allocating space for a single pointer
object, why not just declare the object directly?
 
Ad

Advertisements

J

James Kuyper

On 06/25/2012 04:53 PM, Myth__Buster wrote:
....
Achievement : Clarity and completeness of malloc's behavior in
malloc's documentation. More appropriately, a word of caution similar
to this - In C, malloc when used to directly allocate memory for
function pointers(without any third-variable's allocation such as
encompassing struct variable, etc) on machines wherein the data and
function pointers are of different sizes, the return data pointer
wouldn't be a proper pointer with which the entire memory allocated
for function pointer would have been allocated.

I still don't understand why you think there's a problem, which
inherently implies that I don't understand what the problem is that you
think there is. However, that is not an accurate description of any
problem that malloc() actually possesses.
 

Top