memcpy broken?

P

Peter Pichler

A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

Using our own function like this:

void MemCopy(void* dest, void* src, size_t sz)
{
unsigned char* t = dest;
unsigned char* s = src;

while (sz--)
*t++ = *s++;
}

DOES work. To us, the system memcpy looks broken. Any other opinions on
why the memcpy version wouldn't work?

Thanks for any ideas,

Peter
 
A

Alexei A. Frounze

Peter Pichler said:
A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

I don't know why it can be not working... Is it the only standard C library
function that looks like not working?
Is the memcpy function inlined or not?
Also, what if you change sizeof t to sizeof(t)?
Do you #include <string.h>?
If you use gcc, what's the corresponding asm output (use the -S switch to
translate .c source into asm source).

Alex
 
P

Peter Pichler

Alexei said:
Do you #include <string.h>?

Gotcha! To be honest, I don't know. It didn't occur to me to ask,
assuming that the colleague knew what he was doing. I will have to check
on Monday.

Peter
 
M

Michael Mair

Peter said:
A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

Using our own function like this:

void MemCopy(void* dest, void* src, size_t sz)
{
unsigned char* t = dest;
unsigned char* s = src;

while (sz--)
*t++ = *s++;
}

DOES work. To us, the system memcpy looks broken. Any other opinions on
why the memcpy version wouldn't work?

Apart from Alexei A. Frounze's reply:
It can go wrong if the memory areas overlap -- only memmove() is
guaranteed to work with overlapping source and destination storage.
Your implementation of MemCopy() could, e.g., deal with s = t+1.

Cheers
Michael
 
P

Peter Pichler

Michael said:
Apart from Alexei A. Frounze's reply:
It can go wrong if the memory areas overlap -- only memmove() is
guaranteed to work with overlapping source and destination storage.
Your implementation of MemCopy() could, e.g., deal with s = t+1.

I had thought about that. I don't think it applies here, though. We pass
THING to the function, not its address, thus copying it to a temporary
storage. Overlapping is unlikely to happen. Thanks for the idea anyway.

Peter
 
A

Alexei A. Frounze

....
I had thought about that. I don't think it applies here, though. We pass
THING to the function, not its address, thus copying it to a temporary
storage. Overlapping is unlikely to happen. Thanks for the idea anyway.

Btw, do you enable all warnings (for gcc: -Wall)? Any suspicious warnings?

Alex
 
J

Joe Wright

Peter said:
A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

Using our own function like this:

void MemCopy(void* dest, void* src, size_t sz)
{
unsigned char* t = dest;
unsigned char* s = src;

while (sz--)
*t++ = *s++;
}

DOES work. To us, the system memcpy looks broken. Any other opinions on
why the memcpy version wouldn't work?

Thanks for any ideas,

Peter
The original was..

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

...which is flawed because &t is the address of the function parameter,
not the real THING.

The sizeof t is also problematic if THING is other than a struct type.

Before you and your colleague agree among yourselves that Standard C
functions like memcpy() might be broken and you should tell c.l.c about
it, take a break, a deep breath and look at your code. memcpy() is at
least thirty years old. It works.
 
R

Richard Tobin

Joe Wright said:
The original was..

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

..which is flawed because &t is the address of the function parameter,
not the real THING.

But the parameter will be a copy of the real THING, so why would that
matter?
The sizeof t is also problematic if THING is other than a struct type.

There's a problem if t is a pointer and he means to copy what t points
to rather than t itself.

-- Richard
 
M

Mark F. Haigh

Peter said:
A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

1. Make sure you #include <string.h> and compile with all available
warnings enabled. Lack of a memcpy prototype (coupled with no warnings
enabled or perhaps invoking the compiler in a non-compliant mode) may
cause the wrong "information" to get passed to the C library's memcpy
function.

2. In the same vein, verify the compiler is set up to use the same ABI
as the libraries you're linking against.

3. Consider avoiding passing structures by value altogether
(especially in less popular or niche embedded environments). It's been
historically a source of compiler bugs and ABI incompatibilities. It's
also unnecessarily inefficient, as it requires an extra copy of THING
to be made.


Mark F. Haigh
(e-mail address removed)
 
L

Lawrence Kirby

A colleague encountered an interesting problem. Suppose we have a C
function like this:

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

to copy a THING to any byte address (which might not be aligned for a
THING, hence not doing *(THING*)addr = t).

There's a platform on which it fails, i.e. after the function the
contents of addr are not the thing written to it. (addr is an address in
a malloc'd area, hence properly aligned for THING).

Does it work if you use a copy loop such as the one below instead of
memcpy(). What if you use memmove()?
Using our own function like this:

void MemCopy(void* dest, void* src, size_t sz)
{
unsigned char* t = dest;
unsigned char* s = src;

while (sz--)
*t++ = *s++;
}

Does this version work if you use memcpy() instead of the copy loop?
DOES work. To us, the system memcpy looks broken. Any other opinions on
why the memcpy version wouldn't work?

Failure to include <string.h>, a bug somewhere else in the program
corrupting things.

Lawrence
 
B

Barry Schwarz

On Sun, 31 Jul 2005 18:08:19 -0400, Joe Wright

snip
The original was..

void WRITE_THING(void* addr, THING t)
{
memcpy(addr, &t, sizeof t);
}

..which is flawed because &t is the address of the function parameter,
not the real THING.

As long as THING is not an array, the function parameter is a copy of
the real THING. Therefore, &t is the address of this copy (which must
have the same value(s) as the original) and sizeof t is the size of
either the original or the copy (since both have the same size).
The sizeof t is also problematic if THING is other than a struct type.

You think sizeof won't work if THING is int or double?
Before you and your colleague agree among yourselves that Standard C
functions like memcpy() might be broken and you should tell c.l.c about
it, take a break, a deep breath and look at your code. memcpy() is at
least thirty years old. It works.



<<Remove the del for email>>
 

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,792
Messages
2,569,639
Members
45,353
Latest member
RogerDoger

Latest Threads

Top