Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

memcpy a void pointer to a union

Tags:

c

unions

Code:

union foo
{
    char c;
    int i;
};

void func(void * src)
{
    union foo dest;
    memcpy(&dest, src, sizeof(union foo));   //here
}

If I call func() like this:

int main()
{
    char c;
    int i;
    func(&c);
    func(&i);
    return 0;
}

In the call func(&c), the size of c is less than sizeof(union foo), which may be dangerous, right?

Is the line with memcpy correct? And if not, how to fix it?

What I want is a safe call to memcpy that copy a void * pointer to a union.


A little background: this is extracted from a very complicated function, and the signature of func() including the void * parameter is out of my control. Of course the example does nothing useful, that's because I removed all the code that isn't relevant to provide an example with minimum code.

like image 521
Yu Hao Avatar asked Sep 02 '13 07:09

Yu Hao


People also ask

Can you memcpy to a void pointer?

Yes it works. It behaves the same as looping character pointers over that number of bytes.

How do I convert a void pointer to an int?

After declaration, we assign the address of 'a' variable to the pointer 'ptr'. Then, we assign the void pointer to the integer pointer, i.e., ptr1 without any typecasting because in C, we do not need to typecast while assigning the void pointer to any other type of pointer.

What is memcpy function in C?

memcpy() function in C/C++ The function memcpy() is used to copy a memory block from one location to another. One is source and another is destination pointed by the pointer. This is declared in “string. h” header file in C language. It does not check overflow.


2 Answers

In the call func(&c), the size of c is less than sizeof(union foo), which may be dangerous, right?

Right, this will lead to undefined behaviour. dest will likely contain some bytes from memory areas surrounding c, and which these are depends on the internal workings of the compiler. Of course, as long as you only access dest.c, that shouldn't cause any problems in most cases.

But let me be more specific. According to the C standard, writing dest.c but reading dest.i will always yield undefined behaviour. But most compilers on most platforms will have some well-defined behaviour for those cases as well. So often writing dest.c but reading dest.i makes sense despite what the standard says. In this case, however, reading from dest.i will still be affected by unknown surrounding variables, so it is undefined not only from the standards point of view, but also in a very practical sense.

There also is a rare scenario you should consider: c might be located at the very end of allocated memory pages. (This refers to memory pages allocated from the operating system and eventually the memory management unit (MMU) hardware, not to the block-wise user space allocation done by malloc and friends.) In this case, reading more than that single byte might cause access to unmapped memory, and hence cause a severe error, most likely a program crash. Given the location of your c as an automatic variable in main, this seems unlikely, but I take it that this code snippet is only an example.

Is the line with memcpy correct? And if not, how to fix it?

Depends on what you want to do. As it stands, the code doesn't make too much sense, so I don't know what correct reasonable application you might have in mind. Perhaps you should pass the sizeof the src object to func.

like image 73
MvG Avatar answered Sep 23 '22 07:09

MvG


Is the line with memcpy correct? And if not, how to fix it?

you should pass the size of memory pointed by void pointer so you can know src has this much size so you just need to copy this much of data...

Further more to be safe you should calculate the size of destination and based on that you should pass size so illegal access in reading and writing both can be avoided.

like image 34
Jeegar Patel Avatar answered Sep 21 '22 07:09

Jeegar Patel