pointer to function being casted as a struct?

D

dmjcunha

Hi, I am studying a code but I am having difficulties...
Here it is:

struct drm_driver_descriptor
{
const char *name;
const char *driver_name;
struct pipe_screen* (*create_screen)(int drm_fd);
const struct drm_conf_ret *(*configuration) (enum drm_conf conf);
};

extern struct drm_driver_descriptor driver_descriptor;

typedef void (*func_pointer)(void);

static INLINE func_pointer
pointer_to_func( void *p )
{
union {
void *p;
func_pointer f;
} pf;
pf.p = p; /*pf.f has no attribution*/
return pf.f;
}

dd = (const struct drm_driver_descriptor *) pointer_to_func(dlsym(library, "driver_descriptor"); /*here how could pointer_to_func which returns func_pointer which is not attributed to anything be casted to struct drm_driver_descriptor?*/

And latter there is code like: dd->create_screen(...);
How could it be so?
Thanks in advance.
 
J

James Kuyper

Hi, I am studying a code but I am having difficulties...
Here it is:

struct drm_driver_descriptor
{
const char *name;
const char *driver_name;
struct pipe_screen* (*create_screen)(int drm_fd);
const struct drm_conf_ret *(*configuration) (enum drm_conf conf);
};

extern struct drm_driver_descriptor driver_descriptor;

typedef void (*func_pointer)(void);

static INLINE func_pointer
pointer_to_func( void *p )
{
union {
void *p;
func_pointer f;
} pf;
pf.p = p; /*pf.f has no attribution*/
return pf.f;
}

dd = (const struct drm_driver_descriptor *)
pointer_to_func(dlsym(library, "driver_descriptor");
/*here how could pointer_to_func which returns func_pointer which is
not attributed to anything be casted to struct drm_driver_descriptor?*/

I'm not sure what you mean by "attributed to anything".
That code contains no casts; it uses a union to reinterpret memory.

There is a function named dlsym() that is provided as part of POSIX.
I'll presume that you're talking about either that function or a close
equivalent. C itself does not guarantee that sizeof pf.p == sizeof pf.f,
and makes no promises that loading pf.f with a function pointer value
leaves pf.p with a valid void* value, or vice versa. However, POSIX
requires that dlsym's return value be usable in that fashion, which
requires that those things be true, even though the C standard allows
them to not be true.

In particular, the internals of dlsym could be something as follows:

void *dlsym(void *handle, const char *symbol)
{
union {
void *p;
func_pointer f;
} pf;
// Use handle to locate the function or object identified by
// symbol.
if(handle_invalid || symbol_not_found)
return NULL;
if(symbol_refers_to_a_function)
pf.f = an_expression_pointing_to_that_function;
else
pf.p = an_expression_pointing_to_that_object;
return pf.p;
}

Note: in the actual code, pf need not be a union, and the equivalent of
the if() statement is actually probably a simple memcpy(&pf,
somewhere_else, sizeof pf), which works fine, only because POSIX
guarantees it works fine.

Do you understand, given what POSIX guarantees about the compatibility
of pointers to functions and objects, why the above code could produce
results compatible with the way the code you are reading was written?
 
B

Barry Schwarz

Hi, I am studying a code but I am having difficulties...
Here it is:

struct drm_driver_descriptor
{
const char *name;
const char *driver_name;
struct pipe_screen* (*create_screen)(int drm_fd);
const struct drm_conf_ret *(*configuration) (enum drm_conf conf);
};

extern struct drm_driver_descriptor driver_descriptor;

typedef void (*func_pointer)(void);

static INLINE func_pointer
pointer_to_func( void *p )
{
union {
void *p;
func_pointer f;
} pf;
pf.p = p; /*pf.f has no attribution*/

What do you mean by no attribution? pf.f has type pointer to function
taking one argument (of type pointer to void) and not returning any
value (sometimes expressed as returning void). As a result of this
assignment, it also has a value. What that value is and whether it is
valid or not is system dependent. Given that pf.f and pf.p may have
different sizes, all we can say is that corresponding bits which are
common to both have the same value.

If pf.p is shorter than pf.f, the extra bits in pf.f are
indeterminate. If the opposite, then the extra bits in pf.p are
ignored in the return statement that follows. Even if they are the
same size, there is no guarantee that the bit pattern of the parameter
p (which is what is stored in pf.p) are a legal pattern when evaluated
as the value of a pointer to function (which is the type of pf.f used
in the return statement). It could be trap representation.
return pf.f;
}

dd = (const struct drm_driver_descriptor *) pointer_to_func(dlsym(library, "driver_descriptor"); /*here how could pointer_to_func which returns func_pointer which is not attributed to anything be casted to struct drm_driver_descriptor?*/

Since this statement has unbalanced parentheses, you probably typed it
in manually. You should really use cut and paste to preserve the
accuracy of the code in question.

What do you mean by attributed? From the code in this statement, it
appears that dlsym returns a pointer value. That value is either a
pointer to void (in which case it is passed directly to
pointer_to_func) or a pointer to some object type (in which case it is
implicitly converted to pointer to void and the converted value passed
to pointer_to_func). In both cases, pointer_to_func receives a void*
value and returns a pointer to function value. The cast operator then
converts that pointer to function value to pointer to structure value.
AT NO TIME IS THE POINTER VALUE CONVERTED TO A STRUCT VALUE. The
pointer value is converted from one type of pointer to another type of
pointer. This particular conversion between a function to pointer and
a function to object is something the standard does not describe.
Consequently, unless your system documents what this conversion is,
the code is relying on unspecified (or possibly undefined) behavior.

The sample you provided makes no sense since the conversion could be
performed much more simply with
dd = (const struct drm_driver_descriptor *)
dlsym(library, "driver_descriptor");
There is no need for an intermediate conversion to a function pointer
when converting between to types of object pointers.
And latter there is code like: dd->create_screen(...);
How could it be so?

How could what be so? dd is a pointer to structure. create_screen is
a member of that structure. Somewhere in the code you did not show
that member is assigned a value (the address of a function). This
code simply calls that function. The -> operator is the correct tool
to access the member of a structure when you have the address of that
structure.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top