Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #151069 > unrolled thread
| Started by | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| First post | 2020-04-05 06:47 -0700 |
| Last post | 2020-04-08 01:32 +0200 |
| Articles | 9 on this page of 29 — 13 participants |
Back to article view | Back to comp.lang.c
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 2 of 2 — ← Prev page 1 [2]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2020-04-08 09:17 -0400 |
| Message-ID | <C9kjG.316344$gW1.16632@fx03.iad> |
| In reply to | #151228 |
On 4/8/20 5:06 AM, Malcolm McLean wrote:
>>
> 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.
>
The issue is that since memcpy is a very basic function, you want it as
efficient as possible. On some machines, it may be quicker to load the
pointers into registers that might object to having a null pointer
before processing the loop, and thus the machine might trap on a null
pointer.
Also, if you really want this safe version, you can make a memcpy_safe0
function defined as:
void* memcpy_safe0(void* dest, const void* src, size_t num) {
if(num) return memcpy(dest, src, num);
else return dest;
}
Note, that if the library function includes the check, there is no way
to wrap it to remove that check, thus it make sense to make the standard
version the quick one.
Note that in the above, with a decent optimizing compiler, the call to
memcpy above is tail-recursive, so becomes just a jump (or an inline
expansion of the memcpy code), and the above definition could be made
inline so perhaps the compiler could know if num was zero or not an
optimize the code.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2020-04-09 07:16 -0700 |
| Message-ID | <86d08gn3rx.fsf@linuxsc.com> |
| In reply to | #151230 |
Richard Damon <Richard@Damon-Family.org> writes:
> On 4/8/20 5:06 AM, Malcolm McLean wrote:
>
>> If Nemployees is non-zero while 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.
>
> The issue is that since memcpy is a very basic function, you want it as
> efficient as possible. On some machines, it may be quicker to load the
> pointers into registers that might object to having a null pointer
> before processing the loop, and thus the machine might trap on a null
> pointer.
>
> Also, if you really want this safe version, you can make a memcpy_safe0
> function defined as:
>
> void* memcpy_safe0(void* dest, const void* src, size_t num) {
> if(num) return memcpy(dest, src, num);
> else return dest;
> }
>
> Note, that if the library function includes the check, there is no way
> to wrap it to remove that check, thus it make sense to make the standard
> version the quick one.
>
> Note that in the above, with a decent optimizing compiler, the call to
> memcpy above is tail-recursive,
It is a tail call, but not a recursive tail call.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2020-04-08 13:33 -0700 |
| Message-ID | <87a73llnu4.fsf@nosuchdomain.example.com> |
| In reply to | #151228 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
[...]
> 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.
Your function that takes a pointer to an employee structure and
a count indicating the number of elements in the array should be
accompanied by documentation (at least a comment) that tells the
user what combinations are valid. If you write a call that violates
those requirements, that call is incorrect -- even if the function
happens not to misbehave.
If that documentation says that func(NULL, 0) is valid and
func(NULL, 1) is not, that's fine -- but then you need to guarantee
that func(NULL, 0) won't blow up in future versions unless you want
to risk breaking existing code.
See memcpy for an example of this. Ideally, your function should
be documented as clearly. If it isn't, it might be impossible to
tell whether a given call is correct or not.
--
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]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2020-04-09 09:05 -0700 |
| Message-ID | <3abbeb80-4c62-410e-a133-82d03e72b113@googlegroups.com> |
| In reply to | #151241 |
On Wednesday, 8 April 2020 21:33:36 UTC+1, Keith Thompson wrote: > Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes: > [...] > > 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. > > Your function that takes a pointer to an employee structure and > a count indicating the number of elements in the array should be > accompanied by documentation (at least a comment) that tells the > user what combinations are valid. If you write a call that violates > those requirements, that call is incorrect -- even if the function > happens not to misbehave. > > If that documentation says that func(NULL, 0) is valid and > func(NULL, 1) is not, that's fine -- but then you need to guarantee > that func(NULL, 0) won't blow up in future versions unless you want > to risk breaking existing code. > > See memcpy for an example of this. Ideally, your function should > be documented as clearly. If it isn't, it might be impossible to > tell whether a given call is correct or not. > The standard is clear, though you have to refer back to the preamble on library functions to read it. An array argument may not be null unless otherwise specified, as happens for snprintf(). However if you look in the Apple man page for memcpy, the issue is nowhere to be seen.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2020-04-09 13:28 -0700 |
| Message-ID | <87tv1sjtet.fsf@nosuchdomain.example.com> |
| In reply to | #151267 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
[...]
> The standard is clear, though you have to refer back to the
> preamble on library functions to read it. An array argument may
> not be null unless otherwise specified, as happens for snprintf().
>
> However if you look in the Apple man page for memcpy, the issue
> is nowhere to be seen.
Perhaps not directly. The Apple man page for memcpy (at least the
one I found in a quick Google search) says:
The memcpy() function copies n bytes from memory area s2 to memory
area s1. If s1 and s2 overlap, behavior is undefined. Applications
in which s1 and s2 might overlap should use memmove(3) instead.
The phrase "memory area s2" seems a bit vague. Perhaps Apple's
documentation defines it elsewhere. But surely if s2 is a null pointer
there is no "memory area s2" (and likewise for s1, of course).
But it also says:
The memcpy() function conforms to ISO/IEC 9899:1990 (``ISO C90'').
which does completely describe it.
The Linux man page for memcpy is similar.
In any case the definitive documentation for memcpy is the standard.
And when you document your own functions, I don't suggest following
the example of those man pages.
--
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]
| From | richard@cogsci.ed.ac.uk (Richard Tobin) |
|---|---|
| Date | 2020-04-09 23:41 +0000 |
| Message-ID | <r6obrl$2rpf$1@macpro.inf.ed.ac.uk> |
| In reply to | #151280 |
In article <87tv1sjtet.fsf@nosuchdomain.example.com>, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote: >Perhaps not directly. The Apple man page for memcpy (at least the >one I found in a quick Google search) says: > > The memcpy() function copies n bytes from memory area s2 to memory > area s1. If s1 and s2 overlap, behavior is undefined. Applications > in which s1 and s2 might overlap should use memmove(3) instead. > >The phrase "memory area s2" seems a bit vague. That text, and the term "memory area", appear to derive ultimately from the description of memcpy() in the System V manual page MEMORY(3C), which starts: These functions operate efficiently on memory areas (arrays of characters bounded by a count, not terminated by a null character). -- Richard
[toc] | [prev] | [next] | [standalone]
| From | Guillaume <message@bottle.org> |
|---|---|
| Date | 2020-04-08 16:17 +0200 |
| Message-ID | <r6kmeo$1bg2$1@gioia.aioe.org> |
| In reply to | #151221 |
Le 08/04/2020 à 02:30, Scott Lurndal a écrit : > 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. If you read my whole post, note that I exactly said that. You can't in the general case, but you could just for a null pointer. Whether that would be useful is also questionable, which I also said. As to zero (null pointers) being valid, even for memcpy(), it's a bit confusing. Whereas 0 can be a "valid" address on some targets at a very low level, according to the standard (at least C99): "If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function." So by that definition, a null pointer can't point to any valid object. And whatever happens with non-valid objects, is, you guessed... undefined behavior. What it all means is that the whole spirit of C (at least for a large chunk of the standard) doesn't really make any parameter invalid per se. It just states "undefined behavior" for some parameter values, and the cases in which some values are illegal are very few. A corollary here is that you can perfectly pass pointers to non-valid objects to memcpy(). But: this triggers undefined behavior. We're running in circles. ;) I'll have to admit that parameters triggering undefined behavior are not necessarily "invalid" per se by the standard. This kind of makes sense, but it is certainly confusing for many people. Anyway, as I said in previous posts, this is really a non-issue: if you need a specific behavior for undefined behavior cases, just implement functions on top (or in replacement of) the existing ones. I'm fine with this. One wrong approach though IMO would be *assuming* any specific behavior for undefined behavior cases.
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@sdf.lonestar.org> |
|---|---|
| Date | 2020-04-07 22:01 +0000 |
| Message-ID | <slrn3tukr8pu12.cn3.ike@sdf.lonestar.org> |
| In reply to | #151186 |
On 2020-04-07, Guillaume <message@bottle.org> wrote:
> void * mymemcpy(void *destination, const void *source, size_t size)
> {
> if (destination == NULL)
> return NULL;
>
> memcpy(destination, source, size);
What does the function return here?
> }
[toc] | [prev] | [next] | [standalone]
| From | Guillaume <message@bottle.org> |
|---|---|
| Date | 2020-04-08 01:32 +0200 |
| Message-ID | <r6j2hg$seb$1@gioia.aioe.org> |
| In reply to | #151213 |
Le 08/04/2020 à 00:01, Ike Naar a écrit :
> On 2020-04-07, Guillaume <message@bottle.org> wrote:
>> void * mymemcpy(void *destination, const void *source, size_t size)
>> {
>> if (destination == NULL)
>> return NULL;
>>
>> memcpy(destination, source, size);
>
> What does the function return here?
>
>> }
sorry, it should have been: return memcpy(destination, source, size);
of course.
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c
csiph-web