[memcpy] dst=NULL,size=0

M

maclab2

Hello,

I have a question about 'memcpy' function,
This is a text code:

-[begin]-------------------------------------------
#include <string.h>
#include <stdio.h>
int test(void * ptr, size_t size)
{
static char const txt [] = "abcdefghijklmn";
int result = (!ptr && size) || size > sizeof(txt);
if (!result)
{
memcpy(ptr, &txt, size);
}
return result;
}
int main(void)
{
char arr1 [3];
char arr2 [7];
printf("a=%d\n", test(arr1, sizeof(arr1)));
printf("b=%d\n", test(arr2, sizeof(arr2)));
printf("c=%d\n", test(NULL, 0));
return 0;
}
-[end]--------------------------------------------

The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Regards
 
J

James Kuyper

maclab2 wrote:
....
The code works correctly, ...

That is inherently true, because when a program has undefined behavior,
that means that there is no such thing as incorrect behavior for that
program.
... but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Yes. The behavior described for memcpy() is in terms of "the object
pointed at by s1"; that description has no meaning when the first
argument to memcpy does not point at any actual object. Thus, the
behavior is undefined because there's no applicable definition of what
the behavior should be.
 
B

Ben Bacarisse

maclab2 said:
Hello,

I have a question about 'memcpy' function,
This is a text code:

-[begin]-------------------------------------------
#include <string.h>
#include <stdio.h>
int test(void * ptr, size_t size)
{
static char const txt [] = "abcdefghijklmn";
int result = (!ptr && size) || size > sizeof(txt);
if (!result)
{
memcpy(ptr, &txt, size);
}
return result;
}
int main(void)
{
char arr1 [3];
char arr2 [7];
printf("a=%d\n", test(arr1, sizeof(arr1)));
printf("b=%d\n", test(arr2, sizeof(arr2)));
printf("c=%d\n", test(NULL, 0));
return 0;
}
-[end]--------------------------------------------

The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Yes (sadly). I'd put money on all implementations treating this as a
no-op, but I've lost such bets before! (For details, see 7.1.4 p1 and
the description of memcpy which gives no exemption from these general
provisions.)
 
G

Guest

I have a question about 'memcpy' function,

The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

this sounds like a prompt for massive hair splitting and pedantry.

NO: since nothing is copied in this case there is no dereferencing
of the null pointer. hence no problem.

YES: memcpy() expects the two pointers to be pointers to objects
and the null pointer is not an object.
 
K

Kaz Kylheku

The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Yes, read paragraph 1 of 7.1.4 (Use of library functions) together with
paragraph 2 of 7.21.1 (String function conventions).
 
B

Ben Bacarisse

I have a question about 'memcpy' function,

The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

this sounds like a prompt for massive hair splitting and pedantry.

NO: since nothing is copied in this case there is no dereferencing
of the null pointer. hence no problem.

YES: memcpy() expects the two pointers to be pointers to objects
and the null pointer is not an object.

The thing is, the OP did not ask, "am I likely to be able to get away
with it?". He or she asked "is it UB?". I don't see any room for
hair splitting -- even over the question. The OP already states that
the code "works correctly" so they must be asking for what the
standard says, surely?
 
B

Ben Bacarisse

Ben said:
maclab2 writes: [...]
The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Yes (sadly). I'd put money on all implementations treating this as a
no-op, but I've lost such bets before! (For details, see 7.1.4 p1 and
the description of memcpy which gives no exemption from these general
provisions.)

Perhaps some implementations pre-read the first byte of the source object,
before checking for a zero size (on architectures where every past-the-end
pointer points to a readable byte of memory)?

Hmm... maybe. I was thinking that there may be systems where memcpy
can be replaced by a single opcode whose behaviour is peculiar when
the target address is NULL (even with a 0 size).
That prompts me to ask, is
this valid?

char a [1];
memcpy( a+1, 0, "" );

You mean: memcpy( a+1, "", 0); yes? I am sure it is fine.

<snip examples>
 
B

Ben Bacarisse

pete said:
Ben said:
Ben Bacarisse wrote:
maclab2 writes:
[...]
The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?
Yes (sadly). I'd put money on all implementations treating this as a
no-op, but I've lost such bets before! (For details, see 7.1.4 p1 and
the description of memcpy which gives no exemption from these general
provisions.)
Perhaps some implementations pre-read the first byte of the source object,
before checking for a zero size (on architectures where every past-the-end
pointer points to a readable byte of memory)?

Hmm... maybe. I was thinking that there may be systems where memcpy
can be replaced by a single opcode whose behaviour is peculiar when
the target address is NULL (even with a 0 size).

I was thinking that it's probably because:
1 all of the string functions have their valid input
described in the same place in the standard
2 it might make sense for other string functions such as strncat,
which happens to be of the same type as memcpy,
to dereference the pointer parameters prior to using

I am not persuaded by that argument. I think the intent is that valid
but non-dereferenceable (ugh!) pointers are OK provided that no access
occurs (the one-past the end pointer being the key example here).
3 nobody needs to write memcpy(NULL, PTR, 0);

No, but it falls out of some code as a degenerate case where, for
example, malloc returns NULL when size is 0. Not a good idea,
probably, but I am still wondering what danger there is in allowing it
to be well-defined.
 
B

Ben Bacarisse

pete said:
I am philosophically opposed to optimizing the special degenerate case,
if it even costs one cpu cycle to the general case.

I would not got that far, but I can see your point. What I can't see
is an obvious reason why allowing memcpy(NULL, PTR, 0); would cost
anything at all.
 
P

Phil Carmody

Ben Bacarisse said:
Ben said:
maclab2 writes: [...]
The code works correctly, but in one case ['c'],
the memcpy gets a arguments: (NULL, PTR, 0).
Is this undefined behaviour ?

Yes (sadly). I'd put money on all implementations treating this as a
no-op, but I've lost such bets before! (For details, see 7.1.4 p1 and
the description of memcpy which gives no exemption from these general
provisions.)

Perhaps some implementations pre-read the first byte of the source object,
before checking for a zero size (on architectures where every past-the-end
pointer points to a readable byte of memory)?

Hmm... maybe. I was thinking that there may be systems where memcpy
can be replaced by a single opcode whose behaviour is peculiar when
the target address is NULL (even with a 0 size).
That prompts me to ask, is
this valid?

char a [1];
memcpy( a+1, 0, "" );

You mean: memcpy( a+1, "", 0); yes? I am sure it is fine.

Can we compromise?

memcpy(a+1, 0, 0);

;-)

I think I've seen explicit "if size==0, null pointers permitted"
in various places recently", so such behaviour isn't unexceptional.

Phil
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top