473,398 Members | 2,125 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,398 software developers and data experts.

memcpy as macro legit?

I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?

Just surprised me a little is all.

Mike
Nov 14 '05 #1
14 4063
Michael B Allen <mb*****@ioplex.com> wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.
How do you know that u->size gets overwritten before evaluation?
memcpy(u, buf, u->size);
I guess 'u' and 'buf' are pointers to structures - but why would you
then use u->size instead of "sizeof *u" or "sizeof *buf"? Usually
I would assume that there's no need to store the size of a structure
within the structure. Or are you using some dirty tricks like zero-
length arrays in the structure?
Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


As far as I can see in the standard memcpy() is supposed to be a
function. Are you sure that what 'u' and 'buf' point to never
overlaps?
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #2
On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


Any standard library function can have a macro definition in the relevant
standard header. However the macro must still preserve the semantic of the
function, and as a function it cannot modify its arguments.

Lawrence
Nov 14 '05 #3
"Michael B Allen" <mb*****@ioplex.com> wrote in message
news:pa********************************@ioplex.com ...
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?

Just surprised me a little is all.


This behavior would surprise me a lot indeed.

How could a single byte be overwritten within 'u' before
having evaluated u->size to at least check that it is non-zero?

Given that the last parameter could be an ordinal constant
or an expensive function call, wouldn't even a macro need
to store the size value in a temporary before using it?

The behavior you are describing definitely isn't legit.
And as far as I understand, the C99 standard requires
memcpy to behave like a function (not like a macro) --
even though platforms obviously are allowed to treat it as an
intrinsic function, and to implement specific optimizations.
hth, Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
Nov 14 '05 #4
Lawrence Kirby wrote:

On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
I just noticed that doing something like
the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


Any standard library function can have a macro definition in
the relevant standard header. However the macro must still
preserve the semantic of the function,
and as a function it cannot modify its arguments.


The putc() and getc() macros,
are exceptions to the "cannot modify its arguments" rule.

--
pete
Nov 14 '05 #5
On Fri, 19 Nov 2004 12:03:18 +0000, pete wrote:
Lawrence Kirby wrote:

On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
> I just noticed that doing something like
> the following may fail because
> it can overwrite u->size before it's evaluated.
>
> memcpy(u, buf, u->size);
>
> Is it legit that this is a macro as opposed to a function that would
> not clobber the parameter?


Any standard library function can have a macro definition in
the relevant standard header. However the macro must still
preserve the semantic of the function,
and as a function it cannot modify its arguments.


The putc() and getc() macros,
are exceptions to the "cannot modify its arguments" rule.


Even putc() and getc() are not permitted to modify their arguments when
implemented as macros.

It is however true that they have a special license to violate function
call semantics. A true function call will evaluate each argument
expression exactly once, putc() and getc() are permitted to evaluate their
FILE * argument expression multiple times when implemented as a macro. So
if this expression contained side-effects there would be problems. E.g.
getc(*openstreams++) invokes undefined behaviour because openstreams may
be modified more than once between sequence points in the macro expansion.

Lawrence

Nov 14 '05 #6
On Fri, 19 Nov 2004 04:53:11 -0500, Jens.Toerring wrote:
Michael B Allen <mb*****@ioplex.com> wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.


How do you know that u->size gets overwritten before evaluation?
memcpy(u, buf, u->size);


I guess 'u' and 'buf' are pointers to structures - but why would you
then use u->size instead of "sizeof *u" or "sizeof *buf"? Usually I
would assume that there's no need to store the size of a structure
within the structure. Or are you using some dirty tricks like zero-
length arrays in the structure?
Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


As far as I can see in the standard memcpy() is supposed to be a
function. Are you sure that what 'u' and 'buf' point to never overlaps?


Whoops, u (struct url *) and buf (unsigned char *) do overlap. Actually
they point to the same address.

But still, u->size (which is the first member of the url structure)
was getting clobbered to 0 resulting in nothing being copied. That would
suggest to me that memcpy is not a function. This is glibc-2.2.5.

Mike
Nov 14 '05 #7
Michael B Allen <mb*****@ioplex.com> wrote:
On Fri, 19 Nov 2004 04:53:11 -0500, Jens.Toerring wrote:
As far as I can see in the standard memcpy() is supposed to be a
function. Are you sure that what 'u' and 'buf' point to never overlaps?
Whoops, u (struct url *) and buf (unsigned char *) do overlap. Actually
they point to the same address. But still, u->size (which is the first member of the url structure)
was getting clobbered to 0 resulting in nothing being copied. That would
suggest to me that memcpy is not a function. This is glibc-2.2.5.


If the memory regions overlap all bets are off and I guess it
is better not to make any assumptions about what might be the
results since your deep in undefined-behaviour-land. Perhaps
your implementation can use some aggressive optimizations in
case the buffers don't overlap but that lead to strange result
otherwise.
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #8
Lawrence Kirby <lk****@netactive.co.uk> writes:
On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


Any standard library function can have a macro definition in the relevant
standard header. However the macro must still preserve the semantic of the
function, and as a function it cannot modify its arguments.


A function can modify one of its arguments if another argument points
to it (though you have to be careful about undefined behavior).

There could also be issued with sequence points. C99 7.1.4p1 says:

Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.

with a footnote:

Such macros might not contain the sequence points that the
corresponding function calls do.

For example, the expression sin(x) + cos(x) can invoke undefined
behavior because both calls can set errno, and if sin() and cos() are
implemented as macros there may not be a sequence point where it's
needed. There was a discussion of this in comp.std.c a few years
ago; see
<http://groups.google.com/gr*********************************@king.cts.com%3 E>

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #9
Lawrence Kirby <lk****@netactive.co.uk> wrote in message news:<pa****************************@netactive.co. uk>...
On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


Any standard library function can have a macro definition in the relevant
standard header. However the macro must still preserve the semantic of the
function, and as a function it cannot modify its arguments.


Does this 'preservation of semantics' extend to the sequence point
that applies to function calls in C90?

Normative text 7.1.4p1, and certainly non-normative footnote 156,
suggests it does not apply in C99.

--
Peter
Nov 14 '05 #10
Peter Nilsson wrote:
Lawrence Kirby <lk****@netactive.co.uk> wrote in message news:<pa****************************@netactive.co. uk>...
On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:

I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?


Any standard library function can have a macro definition in the relevant
standard header. However the macro must still preserve the semantic of the
function, and as a function it cannot modify its arguments.

Does this 'preservation of semantics' extend to the sequence point
that applies to function calls in C90?

Normative text 7.1.4p1, and certainly non-normative footnote 156,
suggests it does not apply in C99.


I think it's pretty clear that Lawrence was using the term "preserve the
semantic" informally, and did not mean "with exact semantics of".

I think 7.1.4p1 is clear enough about the semantics of library functions
implemented as macros.
Mark F. Haigh
mf*****@sbcglobal.net
Nov 14 '05 #11
In <pa****************************@netactive.co.uk> Lawrence Kirby <lk****@netactive.co.uk> writes:
On Fri, 19 Nov 2004 12:03:18 +0000, pete wrote:
Lawrence Kirby wrote:

On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:

> I just noticed that doing something like
> the following may fail because
> it can overwrite u->size before it's evaluated.
>
> memcpy(u, buf, u->size);
>
> Is it legit that this is a macro as opposed to a function that would
> not clobber the parameter?

Any standard library function can have a macro definition in
the relevant standard header. However the macro must still
preserve the semantic of the function,
and as a function it cannot modify its arguments.
The putc() and getc() macros,
are exceptions to the "cannot modify its arguments" rule.


Even putc() and getc() are not permitted to modify their arguments when
implemented as macros.


If their stream argument is an expression with side effects, they are
effectively modifying their stream arguments and there is nothing in the
standard prohibiting them from doing that.
It is however true that they have a special license to violate function
call semantics. A true function call will evaluate each argument
expression exactly once, putc() and getc() are permitted to evaluate their
FILE * argument expression multiple times when implemented as a macro. So
if this expression contained side-effects there would be problems. E.g.
getc(*openstreams++) invokes undefined behaviour because openstreams may
be modified more than once between sequence points in the macro expansion.


But this is a user code issue, not a getc() implementation issue.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #12
On Tue, 23 Nov 2004 17:23:56 +0000, Dan Pop wrote:
In <pa****************************@netactive.co.uk> Lawrence Kirby <lk****@netactive.co.uk> writes:
On Fri, 19 Nov 2004 12:03:18 +0000, pete wrote:
Lawrence Kirby wrote:

On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:

> I just noticed that doing something like
> the following may fail because
> it can overwrite u->size before it's evaluated.
>
> memcpy(u, buf, u->size);
>
> Is it legit that this is a macro as opposed to a function that would
> not clobber the parameter?

Any standard library function can have a macro definition in
the relevant standard header. However the macro must still
preserve the semantic of the function,
and as a function it cannot modify its arguments.

The putc() and getc() macros,
are exceptions to the "cannot modify its arguments" rule.


Even putc() and getc() are not permitted to modify their arguments when
implemented as macros.


If their stream argument is an expression with side effects, they are
effectively modifying their stream arguments and there is nothing in the
standard prohibiting them from doing that.


The argument in question to putc() and getc() is a pointer of type FILE
*, this must not be modified. Indeed it doesn't have to be an lvalue so
getc() and putc() macros wouldn't work in general if they tried to modify
it. Of course what the argument points to can be modified (subject to
the implementation details of FILE).

Maybe the problem here is that the concept of "stream argument" is
incorrect or at least imprecise. The stream isn't the argument to the
function, the FILE * pointer is. That is the level we have to think at
when interpreting the statement "a function cannot modify its arguments".
It is however true that they have a special license to violate function
call semantics. A true function call will evaluate each argument
expression exactly once, putc() and getc() are permitted to evaluate
their FILE * argument expression multiple times when implemented as a
macro. So if this expression contained side-effects there would be
problems. E.g. getc(*openstreams++) invokes undefined behaviour because
openstreams may be modified more than once between sequence points in
the macro expansion.


But this is a user code issue, not a getc() implementation issue.


It is a discussion of what getc() and putc() are allowed to do by the
standard. As part of that discussion it is reasonable to give examples
of code that demonstrates characteristics of that behaviour, including
when it is undefined.

Lawrence
Nov 14 '05 #13
On Fri, 19 Nov 2004 20:41:54 +0000, Keith Thompson wrote:
Lawrence Kirby <lk****@netactive.co.uk> writes:
On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
I just noticed that doing something like the following may fail because
it can overwrite u->size before it's evaluated.

memcpy(u, buf, u->size);

Is it legit that this is a macro as opposed to a function that would
not clobber the parameter?
Any standard library function can have a macro definition in the relevant
standard header. However the macro must still preserve the semantic of the
function, and as a function it cannot modify its arguments.


A function can modify one of its arguments if another argument points
to it (though you have to be careful about undefined behavior).


Not really, which is obvious when you stop to consider that the argument
to a function is a value, not an lvalue. Consider

int x = 42;

then

f(x, &x);

and

f(x+0, &x);

are equivalient in C (for fun don't forget f(+x, &x)). Is x the argument
in all of these? No, but its value is. From this perspective talking about
modifying a function's argument makes no sense - there is nothing to
modify; a value has no persistence, only the contents of an object and
things hidden behind standard library functions (such as streams) do.

However "a function cannot modify its arguments" is a common enough
assertion, so what does it mean? Maybe "IF you supply an lvalue as a
function argument the function cannot use that lvalue to modify what it
designates". Naturally modifying the designated object through an lvalue
derived by some other means is possible.
There could also be issued with sequence points. C99 7.1.4p1 says:

Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.

with a footnote:

Such macros might not contain the sequence points that the
corresponding function calls do.

For example, the expression sin(x) + cos(x) can invoke undefined
behavior because both calls can set errno, and if sin() and cos() are
implemented as macros there may not be a sequence point where it's
needed. There was a discussion of this in comp.std.c a few years
ago; see
<http://groups.google.com/gr*********************************@king.cts.com%3 E>


True that is another area where macros for standard library functions can
behave differently.

Lawrence

Nov 14 '05 #14
In <pa****************************@netactive.co.uk> Lawrence Kirby <lk****@netactive.co.uk> writes:
On Tue, 23 Nov 2004 17:23:56 +0000, Dan Pop wrote:
In <pa****************************@netactive.co.uk> Lawrence Kirby <lk****@netactive.co.uk> writes:
On Fri, 19 Nov 2004 12:03:18 +0000, pete wrote:

Lawrence Kirby wrote:
>
> On Fri, 19 Nov 2004 04:27:17 -0500, Michael B Allen wrote:
>
> > I just noticed that doing something like
> > the following may fail because
> > it can overwrite u->size before it's evaluated.
> >
> > memcpy(u, buf, u->size);
> >
> > Is it legit that this is a macro as opposed to a function that would
> > not clobber the parameter?
>
> Any standard library function can have a macro definition in
> the relevant standard header. However the macro must still
> preserve the semantic of the function,
> and as a function it cannot modify its arguments.

The putc() and getc() macros,
are exceptions to the "cannot modify its arguments" rule.

Even putc() and getc() are not permitted to modify their arguments when
implemented as macros.


If their stream argument is an expression with side effects, they are
effectively modifying their stream arguments and there is nothing in the
standard prohibiting them from doing that.


The argument in question to putc() and getc() is a pointer of type FILE
*, this must not be modified. Indeed it doesn't have to be an lvalue so
getc() and putc() macros wouldn't work in general if they tried to modify
it. Of course what the argument points to can be modified (subject to
the implementation details of FILE).

Maybe the problem here is that the concept of "stream argument" is
incorrect or at least imprecise. The stream isn't the argument to the
function, the FILE * pointer is. That is the level we have to think at
when interpreting the statement "a function cannot modify its arguments".


There is no confusion if you read the standard:

7.19.7.5 The getc function

Synopsis

1 #include <stdio.h>
int getc(FILE *stream);

Description

2 The getc function is equivalent to fgetc, except that if it is
implemented as a macro, it may evaluate stream more than once,
so the argument should never be an expression with side effects.

So, "stream" is the name of the FILE pointer argument.
It is however true that they have a special license to violate function
call semantics. A true function call will evaluate each argument
expression exactly once, putc() and getc() are permitted to evaluate
their FILE * argument expression multiple times when implemented as a
macro. So if this expression contained side-effects there would be
problems. E.g. getc(*openstreams++) invokes undefined behaviour because
openstreams may be modified more than once between sequence points in
the macro expansion.


But this is a user code issue, not a getc() implementation issue.


It is a discussion of what getc() and putc() are allowed to do by the
standard.


And they *are* allowed to change their stream argument, by multiple
evaluation, if it's something like fp++. The restriction is on the user
code not call them with such an argument.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: franky.backeljauw | last post by:
Hello, following my question on "std::copy versus pointer copy versus member copy", I had some doubts on the function memcpy, as was used by tom_usenet in his reply. - Is this a c++ standard...
5
by: manya | last post by:
Ok, it's been a while since I've done the whole memcpy stuff with C++ and I'm having a hard time remembering everything. I hope, however, that you can help me with my problem. I memcpy a...
33
by: Case | last post by:
#define SIZE 100 #define USE_MEMCPY int main(void) { char a; char b; int n; /* code 'filling' a */
6
by: myhotline | last post by:
hi all im very confused about using memcpy and i have three questions....memcpy takes a pointer to src and a pointer to dest and copies src to destination...but im very confuzed about when to...
1
by: Michael B Allen | last post by:
Is the following legit? #define PRINT(err, fmt, ...) \ my_printf(__FILE__ ": %s" fmt, errstr(err), ##__VA_ARGS__) Without the ## if I call this like PRINT(EFOO, ": foo!") this reduces to...
4
by: Michael B Allen | last post by:
Let's say I have a stucture with a flexible array at the end: struct foo { short s; char bits; }; I would like to embed this in other structures like: #define TAILBITS 500
18
by: Mark | last post by:
Hi List, I want to write a function to copy some data out of a hardware buffer. The hardware can change the contents of this buffer without it being written to by my function. I want to use...
14
by: somenath | last post by:
Hi All, I am trying to understand the behavior of the memcpy and memmove. While doing so I wrote a program as mentioned bellow . #include<stdio.h> #include<stdlib.h> #include<string.h> ...
18
by: sam | last post by:
(newbie)Technically what's the difference between memset() and memcpy() functions?
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.