Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #151069 > unrolled thread

memcpy can't take null.

Started byMalcolm McLean <malcolm.arthur.mclean@gmail.com>
First post2020-04-05 06:47 -0700
Last post2020-04-08 01:32 +0200
Articles 20 on this page of 29 — 13 participants

Back to article view | Back to comp.lang.c


Contents

  memcpy can't take null. Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-04-05 06:47 -0700
    Re: memcpy can't take null. Öö Tiib <ootiib@hot.ee> - 2020-04-05 07:30 -0700
      Re: memcpy can't take null. Richard Damon <Richard@Damon-Family.org> - 2020-04-05 14:39 -0400
        Re: memcpy can't take null. Philipp Klaus Krause <pkk@spth.de> - 2020-04-06 18:46 +0200
          Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-06 12:45 -0700
            Re: memcpy can't take null. Philipp Klaus Krause <pkk@spth.de> - 2020-04-07 07:28 +0200
    Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-05 16:00 -0700
      Re: memcpy can't take null. Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2020-04-05 18:29 -0600
        Re: memcpy can't take null. scott@slp53.sl.home (Scott Lurndal) - 2020-04-06 18:08 +0000
          Re: memcpy can't take null. Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2020-04-06 15:44 -0600
      Re: memcpy can't take null. Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-04-06 13:54 -0700
        Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-06 14:30 -0700
    Re: memcpy can't take null. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2020-04-06 01:20 +0100
    Re: memcpy can't take null. Siri Cruise <chine.bleu@yahoo.com> - 2020-04-05 19:09 -0700
    Re: memcpy can't take null. Guillaume <message@bottle.org> - 2020-04-07 16:50 +0200
      Re: memcpy can't take null. Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-04-07 09:19 -0700
      Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-07 09:21 -0700
        Re: memcpy can't take null. Guillaume <message@bottle.org> - 2020-04-08 01:41 +0200
          Re: memcpy can't take null. scott@slp53.sl.home (Scott Lurndal) - 2020-04-08 00:30 +0000
            Re: memcpy can't take null. Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-04-08 02:06 -0700
              Re: memcpy can't take null. Richard Damon <Richard@Damon-Family.org> - 2020-04-08 09:17 -0400
                Re: memcpy can't take null. Tim Rentsch <tr.17687@z991.linuxsc.com> - 2020-04-09 07:16 -0700
              Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-08 13:33 -0700
                Re: memcpy can't take null. Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-04-09 09:05 -0700
                  Re: memcpy can't take null. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-04-09 13:28 -0700
                    Re: memcpy can't take null. richard@cogsci.ed.ac.uk (Richard Tobin) - 2020-04-09 23:41 +0000
            Re: memcpy can't take null. Guillaume <message@bottle.org> - 2020-04-08 16:17 +0200
      Re: memcpy can't take null. Ike Naar <ike@sdf.lonestar.org> - 2020-04-07 22:01 +0000
        Re: memcpy can't take null. Guillaume <message@bottle.org> - 2020-04-08 01:32 +0200

Page 1 of 2  [1] 2  Next page →


#151069 — memcpy can't take null.

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2020-04-05 06:47 -0700
Subjectmemcpy can't take null.
Message-ID<6c3de07e-15c8-4cc0-a805-636a5976d086@googlegroups.com>
memcpy() cannot take null as a pointer parametrer, even if the size argument
is zero.

So what are the implications for passing empty buffers about? For example,
how would people write

/* struct employee has no embedded pointers */

Employee *duplicateEmployees(Employee *employees, int Nemployees)

[toc] | [next] | [standalone]


#151072

FromÖö Tiib <ootiib@hot.ee>
Date2020-04-05 07:30 -0700
Message-ID<dbb91496-3624-477c-92b7-f1d8ff434193@googlegroups.com>
In reply to#151069
On Sunday, 5 April 2020 16:47:31 UTC+3, Malcolm McLean  wrote:
> memcpy() cannot take null as a pointer parametrer, even if the size argument
> is zero.
> 
> So what are the implications for passing empty buffers about? For example,
> how would people write
> 
> /* struct employee has no embedded pointers */
> 
> Employee *duplicateEmployees(Employee *employees, int Nemployees)

    {
       if (!employees || Nemployees < 1) return NULL;

       Employee *ret = malloc(Nemployees * sizeof(Employee));
       if (ret) memcpy(ret, employees, Nemployees * sizeof(Employee));

       return ret;
    }

[toc] | [prev] | [next] | [standalone]


#151092

FromRichard Damon <Richard@Damon-Family.org>
Date2020-04-05 14:39 -0400
Message-ID<1CpiG.149251$Pj7.50779@fx14.iad>
In reply to#151072
On 4/5/20 10:30 AM, Öö Tiib wrote:
> On Sunday, 5 April 2020 16:47:31 UTC+3, Malcolm McLean  wrote:
>> memcpy() cannot take null as a pointer parametrer, even if the size argument
>> is zero.
>>
>> So what are the implications for passing empty buffers about? For example,
>> how would people write
>>
>> /* struct employee has no embedded pointers */
>>
>> Employee *duplicateEmployees(Employee *employees, int Nemployees)
> 
>     {
>        if (!employees || Nemployees < 1) return NULL;
> 
>        Employee *ret = malloc(Nemployees * sizeof(Employee));
>        if (ret) memcpy(ret, employees, Nemployees * sizeof(Employee));
> 
>        return ret;
>     }
> 

Since malloc can return either a null pointer or a unique pointer for an
allocation of size 0, if I wanted to be able to use a null pointer for
an error return in functions like this, I would be tempted to create a
wrapper for malloc() if the size requested was 0, would allocate a
buffer of 1 byte, so null returns are always errors. This wrapper could
perhaps use knowledge of the implementation, if it KNOWS that malloc(0)
will return unique pointers and not nulls (except for out of memory),
then it could still call malloc(0).

This lack of standardization of behavior is a historical artifact that
K&R didn't define what to do here, and when the first Standard was being
written, both options were is common usage, so rather than break
existing implementations, it was left undefined. It is of course fairly
trivial to make a wrapper to provide the alternate behavior if you
really need it as described above.

[toc] | [prev] | [next] | [standalone]


#151145

FromPhilipp Klaus Krause <pkk@spth.de>
Date2020-04-06 18:46 +0200
Message-ID<r6fmcn$f4r$1@solani.org>
In reply to#151092
Am 05.04.20 um 20:39 schrieb Richard Damon:
> This lack of standardization of behavior is a historical artifact that
> K&R didn't define what to do here, and when the first Standard was being
> written, both options were is common usage, so rather than break
> existing implementations, it was left undefined. It is of course fairly
> trivial to make a wrapper to provide the alternate behavior if you
> really need it as described above.

The next C standard will even make realloc for zero size undefined
behaviour.
Too many implementations didn't conform with the old C11 standard for
zero size realloc. C17 thus allowed more implementation-defined
behaviour, but at that point it wasn't very useable for portable
programs anymore. So it will just be undefined behaviour in C2X.

[toc] | [prev] | [next] | [standalone]


#151154

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-04-06 12:45 -0700
Message-ID<87eet0o0tb.fsf@nosuchdomain.example.com>
In reply to#151145
Philipp Klaus Krause <pkk@spth.de> writes:
[...]
> The next C standard will even make realloc for zero size undefined
> behaviour.
> Too many implementations didn't conform with the old C11 standard for
> zero size realloc. C17 thus allowed more implementation-defined
> behaviour, but at that point it wasn't very useable for portable
> programs anymore. So it will just be undefined behaviour in C2X.

Do you have a citation for that?

The latest draft I have (n2455.pdf, November 18, 2019) does have this
new wording relative to n1570.pdf, but is identical to the wording in
C17.  There is no new undefined behavior as far as I can tell.

    If size is nonzero and memory for the new object is not
    allocated, the old object is not deallocated.  If size is
    zero and memory for the new object is not allocated, it is
    implementation-defined whether the old object is deallocated.
    If the old object is not deallocated, its value shall be
    unchanged.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#151170

FromPhilipp Klaus Krause <pkk@spth.de>
Date2020-04-07 07:28 +0200
Message-ID<r6h32q$h81$1@solani.org>
In reply to#151154
Am 06.04.20 um 21:45 schrieb Keith Thompson:
> Philipp Klaus Krause <pkk@spth.de> writes:
> [...]
>> The next C standard will even make realloc for zero size undefined
>> behaviour.
>> Too many implementations didn't conform with the old C11 standard for
>> zero size realloc. C17 thus allowed more implementation-defined
>> behaviour, but at that point it wasn't very useable for portable
>> programs anymore. So it will just be undefined behaviour in C2X.
> 
> Do you have a citation for that?
> 

Not really. There is N2464, but you'll have to wait a a bit for the
draft meeting minutes for the meeting last week to see the votes on it
(or until August for the decision on the final meeting minutes).

There is item 6.35 in the 2019 Ithaka meeting minutes regarding an
earlier version of the realloc paper.

> The latest draft I have (n2455.pdf, November 18, 2019)

N2478 / N2479, February 2020 is the latest draft (but naturally doesn't
have changes voted on last week).

Philipp

[toc] | [prev] | [next] | [standalone]


#151104

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-04-05 16:00 -0700
Message-ID<87a73ppmgj.fsf@nosuchdomain.example.com>
In reply to#151069
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> memcpy() cannot take null as a pointer parametrer, even if the size argument
> is zero.
>
> So what are the implications for passing empty buffers about? For example,
> how would people write
>
> /* struct employee has no embedded pointers */
>
> Employee *duplicateEmployees(Employee *employees, int Nemployees)

C doesn't directly support empty arrays, but since arrays are usually
manipulated via pointers to the initial element, it's easy enough
to treat a pointer as pointing to an empty array.

A null pointer doesn't point to an empty array.  It doesn't point
to *anything*.  Similarly, a null pointer doesn't point to an empty
string (there have been problems in the past with code that assumed
it did, and that happened to "work" on some systems).

Just keep that consistently in mind, and write your code in
whatever way is necessary to maintain that.  This might require
a little special case code for handling the result of malloc(0).
So write that code.

Employee *duplicateEmployees(Employee *employees, size_t Nemployees) {
    const size_t requestedCount = Nemployees + (Nemployees == 0);
    Employee *const new = malloc(requestedCount * sizeof *new);
    if (new != NULL) {
        memcpy(new, employees, Nemployees * sizeof *new);
    }
    return new;
}

An alternative would be to treat a null pointer as a pointer to an
empty array, but then you'd probably need more special case code on
top of that to keep things consistent (to avoid passing null pointers
to memcpy, for example).  By *not* treating a null pointer as a
pointer to an empty array, you can (probably) isolate the special
case code to allocation functions.  You'd also lose the ability to
use a null pointer as a special value that doesn't point to anything.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#151108

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2020-04-05 18:29 -0600
Message-ID<1bzhbpmp7j.fsf@pfeifferfamily.net>
In reply to#151104
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>
> A null pointer doesn't point to an empty array.  It doesn't point
> to *anything*.  Similarly, a null pointer doesn't point to an empty
> string (there have been problems in the past with code that assumed
> it did, and that happened to "work" on some systems).

In particular, VAXen had page 0 user readable, and byte 0 contained a 0
by pure luck.  I thought for years a null pointer could be used to
represent an empty string -- I learned my mistake when I moved my code
over to a Sun workstation.

[toc] | [prev] | [next] | [standalone]


#151149

Fromscott@slp53.sl.home (Scott Lurndal)
Date2020-04-06 18:08 +0000
Message-ID<ceKiG.895917$5o5.652843@fx41.iad>
In reply to#151108
Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:
>Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>
>> A null pointer doesn't point to an empty array.  It doesn't point
>> to *anything*.  Similarly, a null pointer doesn't point to an empty
>> string (there have been problems in the past with code that assumed
>> it did, and that happened to "work" on some systems).
>
>In particular, VAXen had page 0 user readable, and byte 0 contained a 0
>by pure luck.  I thought for years a null pointer could be used to
>represent an empty string -- I learned my mistake when I moved my code
>over to a Sun workstation.

BSD unix supported a readonly page of zeros at virtual address zero (on the VAX),
which caused difficulties in porting BSD utilities to SVR4 when they
were merged in.

I don't remember that VMS did the same, but it's been forty years since.

[toc] | [prev] | [next] | [standalone]


#151162

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2020-04-06 15:44 -0600
Message-ID<1bpnckmgr7.fsf@pfeifferfamily.net>
In reply to#151149
scott@slp53.sl.home (Scott Lurndal) writes:

> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:
>>Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>
>>> A null pointer doesn't point to an empty array.  It doesn't point
>>> to *anything*.  Similarly, a null pointer doesn't point to an empty
>>> string (there have been problems in the past with code that assumed
>>> it did, and that happened to "work" on some systems).
>>
>>In particular, VAXen had page 0 user readable, and byte 0 contained a 0
>>by pure luck.  I thought for years a null pointer could be used to
>>represent an empty string -- I learned my mistake when I moved my code
>>over to a Sun workstation.
>
> BSD unix supported a readonly page of zeros at virtual address zero (on the VAX),
> which caused difficulties in porting BSD utilities to SVR4 when they
> were merged in.
>
> I don't remember that VMS did the same, but it's been forty years since.

Yes, I was referring to BSD.  I didn't remember (if I ever knew) that
the whole first page was 0; the first byte was sufficient to create the
misunderstanding.

[toc] | [prev] | [next] | [standalone]


#151158

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2020-04-06 13:54 -0700
Message-ID<07c3ec1e-d2d5-41a3-bbc7-6e37b6464c01@googlegroups.com>
In reply to#151104
On Monday, 6 April 2020 00:00:41 UTC+1, Keith Thompson  wrote:
> Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> > memcpy() cannot take null as a pointer parametrer, even if the size argument
> > is zero.
> >
> > So what are the implications for passing empty buffers about? For example,
> > how would people write
> >
> > /* struct employee has no embedded pointers */
> >
> > Employee *duplicateEmployees(Employee *employees, int Nemployees)
> 
> C doesn't directly support empty arrays, but since arrays are usually
> manipulated via pointers to the initial element, it's easy enough
> to treat a pointer as pointing to an empty array.
> 
> A null pointer doesn't point to an empty array.  It doesn't point
> to *anything*.  Similarly, a null pointer doesn't point to an empty
> string (there have been problems in the past with code that assumed
> it did, and that happened to "work" on some systems).
> 
> Just keep that consistently in mind, and write your code in
> whatever way is necessary to maintain that.  This might require
> a little special case code for handling the result of malloc(0).
> So write that code.
> 
> Employee *duplicateEmployees(Employee *employees, size_t Nemployees) {
>     const size_t requestedCount = Nemployees + (Nemployees == 0);
>     Employee *const new = malloc(requestedCount * sizeof *new);
>     if (new != NULL) {
>         memcpy(new, employees, Nemployees * sizeof *new);
>     }
>     return new;
> }
> 
> An alternative would be to treat a null pointer as a pointer to an
> empty array, but then you'd probably need more special case code on
> top of that to keep things consistent (to avoid passing null pointers
> to memcpy, for example).  By *not* treating a null pointer as a
> pointer to an empty array, you can (probably) isolate the special
> case code to allocation functions.  You'd also lose the ability to
> use a null pointer as a special value that doesn't point to anything.
> 
> 
I think this is the best answer.

The standard library doesn't accept NULL as a valid pointer to the
empty array, so it's reasonable to say that user-defined functions
don't accept it either. That means that if you are passed a non-
null pointer (presumably valid) with a size of zero, you should pass
back a valid pointer. Otherwise caller suddenly finds NULLs infesting
what he thought were valid empty arrays.

if you are passed NULL and non-zero for the size, it is clearly
an error, and it's best to pass it onto memcpy in the hope that
memcpy will crash out. Since we don't know what we are running on,
the implementation has a better idea how to crash the program
than we do. You shouldn't suppress the error and pass back NULL -
that's making it harder for caller to find where the bug lies.

But if you are passed NULL and zero for the size, should you still
pass it on to memcpy() ?

[toc] | [prev] | [next] | [standalone]


#151159

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-04-06 14:30 -0700
Message-ID<87y2r8mhei.fsf@nosuchdomain.example.com>
In reply to#151158
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> On Monday, 6 April 2020 00:00:41 UTC+1, Keith Thompson  wrote:
>> Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
>> > memcpy() cannot take null as a pointer parametrer, even if the size argument
>> > is zero.
>> >
>> > So what are the implications for passing empty buffers about? For example,
>> > how would people write
>> >
>> > /* struct employee has no embedded pointers */
>> >
>> > Employee *duplicateEmployees(Employee *employees, int Nemployees)
>> 
>> C doesn't directly support empty arrays, but since arrays are usually
>> manipulated via pointers to the initial element, it's easy enough
>> to treat a pointer as pointing to an empty array.
>> 
>> A null pointer doesn't point to an empty array.  It doesn't point
>> to *anything*.  Similarly, a null pointer doesn't point to an empty
>> string (there have been problems in the past with code that assumed
>> it did, and that happened to "work" on some systems).
>> 
>> Just keep that consistently in mind, and write your code in
>> whatever way is necessary to maintain that.  This might require
>> a little special case code for handling the result of malloc(0).
>> So write that code.
>> 
>> Employee *duplicateEmployees(Employee *employees, size_t Nemployees) {
>>     const size_t requestedCount = Nemployees + (Nemployees == 0);
>>     Employee *const new = malloc(requestedCount * sizeof *new);
>>     if (new != NULL) {
>>         memcpy(new, employees, Nemployees * sizeof *new);
>>     }
>>     return new;
>> }
>> 
>> An alternative would be to treat a null pointer as a pointer to an
>> empty array, but then you'd probably need more special case code on
>> top of that to keep things consistent (to avoid passing null pointers
>> to memcpy, for example).  By *not* treating a null pointer as a
>> pointer to an empty array, you can (probably) isolate the special
>> case code to allocation functions.  You'd also lose the ability to
>> use a null pointer as a special value that doesn't point to anything.
>> 
>> 
> I think this is the best answer.
>
> The standard library doesn't accept NULL as a valid pointer to the
> empty array, so it's reasonable to say that user-defined functions
> don't accept it either. That means that if you are passed a non-
> null pointer (presumably valid) with a size of zero, you should pass
> back a valid pointer. Otherwise caller suddenly finds NULLs infesting
> what he thought were valid empty arrays.
>
> if you are passed NULL and non-zero for the size, it is clearly
> an error, and it's best to pass it onto memcpy in the hope that
> memcpy will crash out. Since we don't know what we are running on,
> the implementation has a better idea how to crash the program
> than we do. You shouldn't suppress the error and pass back NULL -
> that's making it harder for caller to find where the bug lies.
>
> But if you are passed NULL and zero for the size, should you still
> pass it on to memcpy() ?

You should decide *and document* what argument values are valid, and
what values are invalid.  If a function receives invalid values, either
it should behave in some documented manner, or the documentation should
say that it's the caller's responsibility to pass only valid arguments
(otherwise the behavior is undefined).

For some functions, a null pointer might be valid, indicating that there
is no array (distinct from an empty array).  For others, a null pointer
might be invalid.  Decide and document.

You might consider wrapping the address and count in a structure.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#151107

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2020-04-06 01:20 +0100
Message-ID<871rp1cvmd.fsf@bsb.me.uk>
In reply to#151069
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:

> memcpy() cannot take null as a pointer parametrer, even if the size argument
> is zero.
>
> So what are the implications for passing empty buffers about? For example,
> how would people write
>
> /* struct employee has no embedded pointers */
>
> Employee *duplicateEmployees(Employee *employees, int Nemployees)

Employee *duplicateEmployees(Employee *employees, int Nemployees)
{
     Employee *copy = 0;
     if (Nemployees > 0 && (copy = malloc(Nemployees * sizeof *copy)))
          memcpy(copy, employees, Nemployees * sizeof *copy);
     return copy;
}

though I'd rather it were

Employee *duplicateEmployees(const Employee *employees, size_t Nemployees);

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#151109

FromSiri Cruise <chine.bleu@yahoo.com>
Date2020-04-05 19:09 -0700
Message-ID<chine.bleu-82C6F2.19090105042020@reader.eternal-september.org>
In reply to#151069
In article 
<6c3de07e-15c8-4cc0-a805-636a5976d086@googlegroups.com>,
 Malcolm McLean <malcolm.arthur.mclean@gmail.com> wrote:

> memcpy() cannot take null as a pointer parametrer, even if the size argument
> is zero.

rmemcpy does.

    #define rmemcpy(dd, ss, len) ({ \
        void *_dd = (dd), *_ss = (ss); size_t _len = (len); \
        if (_dd==0 || _len<=0) ; \
        else if (_ss==0) memset(_dd, 0, _len); \
        else memcpy(_dd, _ss, _len); \
        _dd; \
    })

Ma deese! Do you mean I am allowed to wrap other code to even out 
interfaces to what I want? Epouvantable!

    #define tmemcpy(Type, dd, ss, len) \
        ((Type*)rmemcpy(dd, ss, (len)*sizeof(Type)))

How is this allowed?

    #define rstrcmp(a, b) ({char *_a=(a), *_b=(b); \
        _a==_b ? 0 : !_a ? -1 : !_b ? 1 : strcmp(_a, _b) ; \
    })
    #define rstreq(a, b) (rstrcmp(a, b)==0)
    #define rstrne(a, b) (rstrcmp(a, b)!=0)
    #define rstrlt(a, b) (rstrcmp(a, b)<0)
    #define rstrle(a, b) (rstrcmp(a, b)<=0)
    #define rstrgt(a, b) (rstrcmp(a, b)>0)
    #define rstrge(a, b) (rstrcmp(a, b)>=0)

-- 
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.    @
'I desire mercy, not sacrifice.'                                    /|\
The first law of discordiamism: The more energy   This post         / \
to make order is nore energy made into entropy.   insults Islam.  Mohammed

[toc] | [prev] | [next] | [standalone]


#151186

FromGuillaume <message@bottle.org>
Date2020-04-07 16:50 +0200
Message-ID<r6i3vk$14n3$1@gioia.aioe.org>
In reply to#151069
Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
> memcpy() cannot take null as a pointer parametrer, even if the size argument
> is zero.

Most of the string/memory functions of the C std lib don't do any kind 
of error checking. You may consider that passing memcpy a null pointer 
AND a size of 0 is not an error per se, but I wouldn't necessarily agree 
(along with probably many others.)

The reason for no error checking is likely historical. Possibly for 
performance reasons. Not quite sure, but the idea is pervasive in most 
of the std lib.

BTW, what would you expect memcpy to do in such a case? I guess just do 
nothing and return NULL?

In which case you'd just write:

void * mymemcpy(void *destination, const void *source, size_t size)
{
     if (destination == NULL)
         return NULL;

     memcpy(destination, source, size);
}

Note that I can't see how you could usefully distinguish the case where 
destination is NULL and size isn't zero, from the case where destination 
is NULL and size is zero. In both cases, there's nothing to do, and the 
function could return nothing else than NULL IMO, so the above 
definition should be OK.

> So what are the implications for passing empty buffers about?
You implement error checking yourself, which many find tedious in C.

But maybe you should tell us a bit more about what you call an "empty 
buffer".

Typically, to be consistent IMO a NULL pointer would mean an unallocated 
buffer, whereas an "empty" buffer may be more like an allocated buffer 
with no data. Really depends on your requirements/implementation. In the 
later case, you'd need to define your buffers as structs with a bit more 
info than just a pointer to the buffer memory.

[toc] | [prev] | [next] | [standalone]


#151192

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2020-04-07 09:19 -0700
Message-ID<3ff768db-1f76-4bc5-b1ad-b7c80d8e27e0@googlegroups.com>
In reply to#151186
On Tuesday, 7 April 2020 15:50:43 UTC+1, Guillaume  wrote:
> Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
> > memcpy() cannot take null as a pointer parametrer, even if the size argument
> > is zero.
> 
> Most of the string/memory functions of the C std lib don't do any kind 
> of error checking. You may consider that passing memcpy a null pointer 
> AND a size of 0 is not an error per se, but I wouldn't necessarily agree 
> (along with probably many others.)
> 
It's not inherently a logical error to regard NULL as a pointer to no
bytes, and it's not enforced by the C language as such. However the 
convention that the standard library uses is that NULL with a 
size of zero is an error, rather than a valid call for the null case.
>
> > So what are the implications for passing empty buffers about?
> You implement error checking yourself, which many find tedious in C.
> 
> But maybe you should tell us a bit more about what you call an "empty 
> buffer".
>
"Empty buffer" is maybe the wrong term. I mean a buffer with no data
in it, and of zero capacity. C doesn't allow zero-sized arrays, but
it does allow malloc() to return a non-null, freeable pointer for
a request of zero bytes. 

[toc] | [prev] | [next] | [standalone]


#151193

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2020-04-07 09:21 -0700
Message-ID<87zhbnl10s.fsf@nosuchdomain.example.com>
In reply to#151186
Guillaume <message@bottle.org> writes:
> Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
>> memcpy() cannot take null as a pointer parametrer, even if the size argument
>> is zero.
>
> Most of the string/memory functions of the C std lib don't do any kind
> of error checking. You may consider that passing memcpy a null pointer
> AND a size of 0 is not an error per se, but I wouldn't necessarily
> agree (along with probably many others.)

It's not as ambiguous as you make it sound.  Passing a null pointer to
memcpy has undefined behavior.

    The memcpy function copies n characters from the object pointed to
    by s2 into the object pointed to by s1.

If s1 or s2 doesn't point to an object, then that argument is invalid as
described in 7.1.4.


[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#151216

FromGuillaume <message@bottle.org>
Date2020-04-08 01:41 +0200
Message-ID<r6j33u$15ev$1@gioia.aioe.org>
In reply to#151193
Le 07/04/2020 à 18:21, Keith Thompson a écrit :
> Guillaume <message@bottle.org> writes:
>> Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
>>> memcpy() cannot take null as a pointer parametrer, even if the size argument
>>> is zero.
>>
>> Most of the string/memory functions of the C std lib don't do any kind
>> of error checking. You may consider that passing memcpy a null pointer
>> AND a size of 0 is not an error per se, but I wouldn't necessarily
>> agree (along with probably many others.)
> 
> It's not as ambiguous as you make it sound.  Passing a null pointer to
> memcpy has undefined behavior.

None of what I said makes it ambiguous. I just said most of those 
functions don't do any error checking for invalid parameters. Nothing 
ambiguous about it.

> 
>      The memcpy function copies n characters from the object pointed to
>      by s2 into the object pointed to by s1.
> 
> If s1 or s2 doesn't point to an object, then that argument is invalid as
> described in 7.1.4.

Exactly. To me an invalid argument is an error. Then the underlying 
function is implemented with error checking (so the behavior is defined) 
or with no error checking (so the behavior is obviously undefined.)

Error checking here meant "parameter validity checking".

Of course, note that the case exposed by Malcolm is just a particular 
case that *could* have been handled by memcpy(). But the standard is 
more general, as it generally talks about "pointers not pointing to an 
object". Which of course means NULL, but also any other value that would 
happen to point to a random location that would not have been allocated 
properly, or that would have been free'd.

In that regard, the usefulness of checking for just NULL when any other 
value could also be not pointing to an object is admittedly 
questionable, and is probably the main reason null pointers are not 
checked explicitely in those functions.

[toc] | [prev] | [next] | [standalone]


#151221

Fromscott@slp53.sl.home (Scott Lurndal)
Date2020-04-08 00:30 +0000
Message-ID<dW8jG.1373649$hD4.309580@fx47.iad>
In reply to#151216
Guillaume <message@bottle.org> writes:
>Le 07/04/2020 à 18:21, Keith Thompson a écrit :
>> Guillaume <message@bottle.org> writes:
>>> Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
>>>> memcpy() cannot take null as a pointer parametrer, even if the size argument
>>>> is zero.
>>>
>>> Most of the string/memory functions of the C std lib don't do any kind
>>> of error checking. You may consider that passing memcpy a null pointer
>>> AND a size of 0 is not an error per se, but I wouldn't necessarily
>>> agree (along with probably many others.)
>> 
>> It's not as ambiguous as you make it sound.  Passing a null pointer to
>> memcpy has undefined behavior.
>
>None of what I said makes it ambiguous. I just said most of those 
>functions don't do any error checking for invalid parameters. Nothing 
>ambiguous about it.
>
>> 
>>      The memcpy function copies n characters from the object pointed to
>>      by s2 into the object pointed to by s1.
>> 
>> If s1 or s2 doesn't point to an object, then that argument is invalid as
>> described in 7.1.4.
>
>Exactly. To me an invalid argument is an error. Then the underlying 
>function is implemented with error checking (so the behavior is defined) 
>or with no error checking (so the behavior is obviously undefined.)
>
>Error checking here meant "parameter validity checking".

How would you validate any of the parameters to memcpy?  Particularly
considering that from a hardware point of view, zero is a legal virtual
address.

Back a quarter century ago, one of the standards committees I sat on
discussed this very topic (with options like an OS system call to validate
that the virtual addresses were valid for the process - huge overhead).

C is, after all, used in many contexts, often as bare metal code.

The final consensus was that there was no effective way to check
the parameters to mem* or str* functions without a serious performance
drop.

[toc] | [prev] | [next] | [standalone]


#151228

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2020-04-08 02:06 -0700
Message-ID<8338dd09-dfed-447b-adf0-356695b1b1d8@googlegroups.com>
In reply to#151221
On Wednesday, 8 April 2020 01:30:08 UTC+1, Scott Lurndal  wrote:
> Guillaume <message@bottle.org> writes:
> >Le 07/04/2020 à 18:21, Keith Thompson a écrit :
> >> Guillaume <message@bottle.org> writes:
> >>> Le 05/04/2020 à 15:47, Malcolm McLean a écrit :
> >>>> memcpy() cannot take null as a pointer parametrer, even if the size argument
> >>>> is zero.
> >>>
> >>> Most of the string/memory functions of the C std lib don't do any kind
> >>> of error checking. You may consider that passing memcpy a null pointer
> >>> AND a size of 0 is not an error per se, but I wouldn't necessarily
> >>> agree (along with probably many others.)
> >> 
> >> It's not as ambiguous as you make it sound.  Passing a null pointer to
> >> memcpy has undefined behavior.
> >
> >None of what I said makes it ambiguous. I just said most of those 
> >functions don't do any error checking for invalid parameters. Nothing 
> >ambiguous about it.
> >
> >> 
> >>      The memcpy function copies n characters from the object pointed to
> >>      by s2 into the object pointed to by s1.
> >> 
> >> If s1 or s2 doesn't point to an object, then that argument is invalid as
> >> described in 7.1.4.
> >
> >Exactly. To me an invalid argument is an error. Then the underlying 
> >function is implemented with error checking (so the behavior is defined) 
> >or with no error checking (so the behavior is obviously undefined.)
> >
> >Error checking here meant "parameter validity checking".
> 
> How would you validate any of the parameters to memcpy?  Particularly
> considering that from a hardware point of view, zero is a legal virtual
> address.
> 
> Back a quarter century ago, one of the standards committees I sat on
> discussed this very topic (with options like an OS system call to validate
> that the virtual addresses were valid for the process - huge overhead).
> 
> C is, after all, used in many contexts, often as bare metal code.
> 
> The final consensus was that there was no effective way to check
> the parameters to mem* or str* functions without a serious performance
> drop.
>
If Nemployees is non-zero whilst the pointer employees points to invalid
memory, it's likely that the bug will be discovered soon enough.
But if Nemployees is zero and employees is NULL, then the loops through
the employees array will all be no-ops and have defined, correct
behaviour. It's only if you call a library function like memcpy that
the code becomes incorrect.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web