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


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

UB of memcpy(NULL, NULL, 0)

Started byNoob <root@127.0.0.1>
First post2016-10-13 12:42 +0200
Last post2016-10-22 16:33 -0700
Articles 20 on this page of 100 — 20 participants

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


Contents

  UB of memcpy(NULL, NULL, 0) Noob <root@127.0.0.1> - 2016-10-13 12:42 +0200
    Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-13 11:55 +0100
      Re: UB of memcpy(NULL, NULL, 0) Noob <root@127.0.0.1> - 2016-10-13 13:09 +0200
        Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-13 12:22 +0100
          Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-13 12:22 -0700
            Re: UB of memcpy(NULL, NULL, 0) "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2016-10-13 12:32 -0700
              Re: UB of memcpy(NULL, NULL, 0) "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2016-10-13 12:34 -0700
      Re: UB of memcpy(NULL, NULL, 0) Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-10-13 08:24 -0600
        Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-13 16:22 +0100
        Re: UB of memcpy(NULL, NULL, 0) Noob <root@127.0.0.1> - 2016-10-13 17:49 +0200
          Re: UB of memcpy(NULL, NULL, 0) Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-10-13 12:02 -0600
    Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-15 20:56 +0200
      Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-15 12:52 -0700
      Re: UB of memcpy(NULL, NULL, 0) "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-15 15:55 -0400
      Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-15 13:41 -0700
        Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-16 11:17 +0200
          Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-16 10:26 +0100
          Re: UB of memcpy(NULL, NULL, 0) raltbos@xs4all.nl (Richard Bos) - 2016-10-16 09:55 +0000
            Re: UB of memcpy(NULL, NULL, 0) Jerry Stuckle <jstucklex@attglobal.net> - 2016-10-16 08:44 -0400
              Re: UB of memcpy(NULL, NULL, 0) David Brown <david.brown@hesbynett.no> - 2016-10-17 10:06 +0200
                Re: UB of memcpy(NULL, NULL, 0) Jerry Stuckle <jstucklex@attglobal.net> - 2016-10-17 09:06 -0400
                  Re: UB of memcpy(NULL, NULL, 0) David Brown <david.brown@hesbynett.no> - 2016-10-17 16:29 +0200
                    Re: UB of memcpy(NULL, NULL, 0) Jerry Stuckle <jstucklex@attglobal.net> - 2016-10-17 17:05 -0400
                      Re: UB of memcpy(NULL, NULL, 0) David Brown <david.brown@hesbynett.no> - 2016-10-18 11:19 +0200
                        Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-18 08:04 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Jerry Stuckle <jstucklex@attglobal.net> - 2016-10-18 16:27 -0400
              Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-17 08:59 -0700
                Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-17 11:21 -0700
                  Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-17 13:42 -0700
                    Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-17 14:46 -0700
                      Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-17 15:52 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-17 16:43 -0700
                          Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-18 08:00 -0700
                            Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-18 09:14 -0700
                              Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-18 09:43 -0700
                                Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-18 11:31 -0700
                                  Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-18 12:49 -0700
                                Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-18 12:03 -0700
                Re: UB of memcpy(NULL, NULL, 0) Jerry Stuckle <jstucklex@attglobal.net> - 2016-10-17 17:06 -0400
                  Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-17 14:55 -0700
          Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-16 11:23 -0700
        Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-17 08:49 -0700
          Re: UB of memcpy(NULL, NULL, 0) raltbos@xs4all.nl (Richard Bos) - 2016-10-18 16:54 +0000
            Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-18 11:09 -0700
              Re: UB of memcpy(NULL, NULL, 0) raltbos@xs4all.nl (Richard Bos) - 2016-10-23 13:24 +0000
                Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 09:28 -0700
                Re: UB of memcpy(NULL, NULL, 0) <william@wilbur.25thandClement.com> - 2016-10-29 11:32 -0700
                  Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-29 14:12 -0700
      Re: UB of memcpy(NULL, NULL, 0) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-15 22:00 +0100
        Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-16 02:51 -0700
          Re: UB of memcpy(NULL, NULL, 0) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-16 11:20 +0100
            Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-16 04:14 -0700
              Re: UB of memcpy(NULL, NULL, 0) BartC <bc@freeuk.com> - 2016-10-16 12:22 +0100
              Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-16 13:01 +0100
                Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-16 05:29 -0700
                  Re: UB of memcpy(NULL, NULL, 0) Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-16 20:47 +0100
                    Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-17 02:08 -0700
                  Re: UB of memcpy(NULL, NULL, 0) David Brown <david.brown@hesbynett.no> - 2016-10-17 10:24 +0200
                    Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-17 08:05 -0700
                      Re: UB of memcpy(NULL, NULL, 0) David Brown <david.brown@hesbynett.no> - 2016-10-17 17:25 +0200
    Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-17 17:08 +0200
      Re: UB of memcpy(NULL, NULL, 0) Lorinczy Zsigmond <zsiga@nospam.for.me> - 2016-10-21 12:46 +0200
        Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-21 08:06 -0700
          Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-21 18:30 +0200
            Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-21 09:34 -0700
              Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-22 07:42 +0200
                Re: UB of memcpy(NULL, NULL, 0) James Kuyper <jameskuyper@verizon.net> - 2016-10-22 10:31 -0400
                  Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-22 17:49 +0200
                    Re: UB of memcpy(NULL, NULL, 0) Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-22 13:43 -0700
                      Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-23 07:47 +0200
                        Re: UB of memcpy(NULL, NULL, 0) "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-23 11:07 -0400
                          Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-23 17:45 +0200
                            Re: UB of memcpy(NULL, NULL, 0) "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-23 12:16 -0400
                            Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 07:38 -0700
                              Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-24 08:38 -0700
                                Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 09:44 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-23 12:22 -0700
                          Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-23 13:37 -0700
                            Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-23 14:15 -0700
                            Re: UB of memcpy(NULL, NULL, 0) Ike Naar <ike@iceland.freeshell.org> - 2016-10-24 06:11 +0000
                              Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-24 00:58 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-23 14:07 -0700
                      Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 07:48 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-24 08:40 -0700
                          Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 10:03 -0700
                            Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-24 12:06 -0700
                              Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 13:36 -0700
                                Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-24 13:57 -0700
                        Re: UB of memcpy(NULL, NULL, 0) Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-24 14:16 -0700
                          Re: UB of memcpy(NULL, NULL, 0) supercat@casperkitty.com - 2016-10-24 17:23 -0700
                            Re: UB of memcpy(NULL, NULL, 0) Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-25 07:57 -0700
                    Re: UB of memcpy(NULL, NULL, 0) James Kuyper <jameskuyper@verizon.net> - 2016-10-22 18:23 -0400
                  Re: UB of memcpy(NULL, NULL, 0) "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-23 10:44 -0400
                    Re: UB of memcpy(NULL, NULL, 0) Richard Heathfield <rjh@cpax.org.uk> - 2016-10-23 16:24 +0100
                      Re: Verbing Noob <root@127.0.0.1> - 2016-10-23 18:02 +0200
          Re: UB of memcpy(NULL, NULL, 0) raltbos@xs4all.nl (Richard Bos) - 2016-10-23 13:26 +0000
            Re: UB of memcpy(NULL, NULL, 0) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-10-23 07:40 -0700
        Re: UB of memcpy(NULL, NULL, 0) asetofsymbols@gmail.com - 2016-10-21 23:56 -0700
          Re: UB of memcpy(NULL, NULL, 0) Lőrinczy Zsigmond <nospam@for.me> - 2016-10-22 12:21 +0200
            Re: UB of memcpy(NULL, NULL, 0) Keith Thompson <kst-u@mib.org> - 2016-10-22 16:33 -0700

Page 2 of 5 — ← Prev page 1 [2] 3 4 5  Next page →


#94970

FromJerry Stuckle <jstucklex@attglobal.net>
Date2016-10-17 09:06 -0400
Message-ID<nu2ibp$5c5$1@jstuckle.eternal-september.org>
In reply to#94959
On 10/17/2016 4:06 AM, David Brown wrote:
> On 16/10/16 14:44, Jerry Stuckle wrote:
>> On 10/16/2016 5:55 AM, Richard Bos wrote:
>>> =?UTF-8?Q?L=c5=91rinczy_Zsigmond?= <nospam@for.me> wrote:
>>>
>>>>
>>>>> As a programmer, how much of a burden is it to avoid calling memcpy()
>>>>> with a null pointer?
>>>>
>>>> It would add a redundant 'if' to the code, increasing complexity
>>>>
>>>> - memcpy (to, from, len)
>>>> + if (len) memcpy (to, from, len)
>>>
>>> Nope. Testing for null pointers should be done as early and as high up
>>> as possible, _not_ in system code nor every single time you call a
>>> system function. That way, you avoid a whole slew of if's with a single
>>> one, rather than risk missing one.
>>> Demanding that the check be done in system code also means that _all_
>>> calls to that system function suffer the penalty, even those in code
>>> that's written properly, with the big picture in mind.
>>> In other words, don't write this:
>>>
>>
>> Which can cause a problem with embedded and kernel programming, where
>> location 0 is a valid address.  In many systems (including Intel
>> processors), for instance, this is the beginning of the interrupt
>> vectors, which must be set during initialization.  It is very possible
>> to set multiple vectors with one call to memcpy.
>>
> 
> In practice, while location 0 is usually a valid address in embedded
> systems, it is typically a rather special address.  A common case is for
> the reset vector or initial stack pointer.  Sometimes (especially on
> small microcontrollers) it can be part of the hardware register map.
> 
> You would rarely want to access such locations through a pointer, and
> you certainly don't want to do so via memcpy or similar functions.
> Quite simply, it is not a problem.
>

As I said - it is often the start of the interrupt vectors - such as the
reset vector.

When dealing with small embedded systems without an OS (or writing the
OS), you ALWAYS want to set the interrupt vectors the proper values. The
way to do this is through a pointer.

>> Forcing library functions to test for a null pointer would preclude
>> using them for these functions.
> 
> I interpreted Richard's post to mean that any tests for null pointers
> (or other special cases) should be handled in application code /before/
> calling library functions - thus the library functions don't need to
> check for null pointers, and could perhaps even allow their usage.
> 

Which is exactly what I agreed with.

> The only sensible attitude is to avoid calling memcpy and similar
> functions with null pointers.  The standard says memcpy has undefined
> behaviour for null pointers, to give the compiler and library
> implementers full freedom to choose the optimal code.  So you do any
> required checks before calling them.
> 

You didn't even read my post before responding, did you?  You just saw
that I posted and had to try to prove me wrong again.  But once again
you have just made a fool of yourself.




-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

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


#94980

FromDavid Brown <david.brown@hesbynett.no>
Date2016-10-17 16:29 +0200
Message-ID<nu2n8j$nco$1@dont-email.me>
In reply to#94970
On 17/10/16 15:06, Jerry Stuckle wrote:
> On 10/17/2016 4:06 AM, David Brown wrote:
>> On 16/10/16 14:44, Jerry Stuckle wrote:
>>> On 10/16/2016 5:55 AM, Richard Bos wrote:
>>>> =?UTF-8?Q?L=c5=91rinczy_Zsigmond?= <nospam@for.me> wrote:
>>>>
>>>>>
>>>>>> As a programmer, how much of a burden is it to avoid calling memcpy()
>>>>>> with a null pointer?
>>>>>
>>>>> It would add a redundant 'if' to the code, increasing complexity
>>>>>
>>>>> - memcpy (to, from, len)
>>>>> + if (len) memcpy (to, from, len)
>>>>
>>>> Nope. Testing for null pointers should be done as early and as high up
>>>> as possible, _not_ in system code nor every single time you call a
>>>> system function. That way, you avoid a whole slew of if's with a single
>>>> one, rather than risk missing one.
>>>> Demanding that the check be done in system code also means that _all_
>>>> calls to that system function suffer the penalty, even those in code
>>>> that's written properly, with the big picture in mind.
>>>> In other words, don't write this:
>>>>
>>>
>>> Which can cause a problem with embedded and kernel programming, where
>>> location 0 is a valid address.  In many systems (including Intel
>>> processors), for instance, this is the beginning of the interrupt
>>> vectors, which must be set during initialization.  It is very possible
>>> to set multiple vectors with one call to memcpy.
>>>
>>
>> In practice, while location 0 is usually a valid address in embedded
>> systems, it is typically a rather special address.  A common case is for
>> the reset vector or initial stack pointer.  Sometimes (especially on
>> small microcontrollers) it can be part of the hardware register map.
>>
>> You would rarely want to access such locations through a pointer, and
>> you certainly don't want to do so via memcpy or similar functions.
>> Quite simply, it is not a problem.
>>
> 
> As I said - it is often the start of the interrupt vectors - such as the
> reset vector.
> 
> When dealing with small embedded systems without an OS (or writing the
> OS), you ALWAYS want to set the interrupt vectors the proper values. The
> way to do this is through a pointer.
> 

The most common way to get the correct interrupt vectors is to have them
as statically linked when you build your binary image for the
microcontroller - you don't change them at run-time, because they are
part of the flash or rom image.

For bigger embedded systems, you might want to install interrupt
handlers during initialisation at run-time.  This is usually done by
building a second interrupt table in ram, and moving the cpu's
"interrupt table vector" to point to the new table.  This means that the
interrupt vectors you are writing are not at location 0, but in ordinary
ram.

And even in cases where you want to change the interrupt vectors, there
is one vector you /never/ want to change at run-time (except when doing
a whole system update) - the reset vector!


>>> Forcing library functions to test for a null pointer would preclude
>>> using them for these functions.
>>
>> I interpreted Richard's post to mean that any tests for null pointers
>> (or other special cases) should be handled in application code /before/
>> calling library functions - thus the library functions don't need to
>> check for null pointers, and could perhaps even allow their usage.
>>
> 
> Which is exactly what I agreed with.
> 
>> The only sensible attitude is to avoid calling memcpy and similar
>> functions with null pointers.  The standard says memcpy has undefined
>> behaviour for null pointers, to give the compiler and library
>> implementers full freedom to choose the optimal code.  So you do any
>> required checks before calling them.
>>
> 
> You didn't even read my post before responding, did you?  You just saw
> that I posted and had to try to prove me wrong again.  But once again
> you have just made a fool of yourself.
> 

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


#95023

FromJerry Stuckle <jstucklex@attglobal.net>
Date2016-10-17 17:05 -0400
Message-ID<nu3eeq$h8g$1@jstuckle.eternal-september.org>
In reply to#94980
On 10/17/2016 10:29 AM, David Brown wrote:
> On 17/10/16 15:06, Jerry Stuckle wrote:
>> On 10/17/2016 4:06 AM, David Brown wrote:
>>> On 16/10/16 14:44, Jerry Stuckle wrote:
>>>> On 10/16/2016 5:55 AM, Richard Bos wrote:
>>>>> =?UTF-8?Q?L=c5=91rinczy_Zsigmond?= <nospam@for.me> wrote:
>>>>>
>>>>>>
>>>>>>> As a programmer, how much of a burden is it to avoid calling memcpy()
>>>>>>> with a null pointer?
>>>>>>
>>>>>> It would add a redundant 'if' to the code, increasing complexity
>>>>>>
>>>>>> - memcpy (to, from, len)
>>>>>> + if (len) memcpy (to, from, len)
>>>>>
>>>>> Nope. Testing for null pointers should be done as early and as high up
>>>>> as possible, _not_ in system code nor every single time you call a
>>>>> system function. That way, you avoid a whole slew of if's with a single
>>>>> one, rather than risk missing one.
>>>>> Demanding that the check be done in system code also means that _all_
>>>>> calls to that system function suffer the penalty, even those in code
>>>>> that's written properly, with the big picture in mind.
>>>>> In other words, don't write this:
>>>>>
>>>>
>>>> Which can cause a problem with embedded and kernel programming, where
>>>> location 0 is a valid address.  In many systems (including Intel
>>>> processors), for instance, this is the beginning of the interrupt
>>>> vectors, which must be set during initialization.  It is very possible
>>>> to set multiple vectors with one call to memcpy.
>>>>
>>>
>>> In practice, while location 0 is usually a valid address in embedded
>>> systems, it is typically a rather special address.  A common case is for
>>> the reset vector or initial stack pointer.  Sometimes (especially on
>>> small microcontrollers) it can be part of the hardware register map.
>>>
>>> You would rarely want to access such locations through a pointer, and
>>> you certainly don't want to do so via memcpy or similar functions.
>>> Quite simply, it is not a problem.
>>>
>>
>> As I said - it is often the start of the interrupt vectors - such as the
>> reset vector.
>>
>> When dealing with small embedded systems without an OS (or writing the
>> OS), you ALWAYS want to set the interrupt vectors the proper values. The
>> way to do this is through a pointer.
>>
> 
> The most common way to get the correct interrupt vectors is to have them
> as statically linked when you build your binary image for the
> microcontroller - you don't change them at run-time, because they are
> part of the flash or rom image.
>

Maybe the most common way for YOU to do it.  However, not the most
common way for OTHERS to do it.  It all depends on the microcontroller
and the load routine.

And it's not at all unusual for the loader to have one set of interrupt
vectors, but once everything is loaded, to initialize the runtime to a
different set of interrupt vectors.

> For bigger embedded systems, you might want to install interrupt
> handlers during initialisation at run-time.  This is usually done by
> building a second interrupt table in ram, and moving the cpu's
> "interrupt table vector" to point to the new table.  This means that the
> interrupt vectors you are writing are not at location 0, but in ordinary
> ram.
> 

That depends on the capability of the controller.  Many are fixed at
location zero - even Intel chips.

> And even in cases where you want to change the interrupt vectors, there
> is one vector you /never/ want to change at run-time (except when doing
> a whole system update) - the reset vector!
> 

Once again, incorrect.  It may be quite necessary to change the reset
interrupt vector once code is loaded - for instance, when loading a new
version of firmware into flash memory.  Even during normal operation it
may be necessary to change the reset interrupt vector.

> 
>>>> Forcing library functions to test for a null pointer would preclude
>>>> using them for these functions.
>>>
>>> I interpreted Richard's post to mean that any tests for null pointers
>>> (or other special cases) should be handled in application code /before/
>>> calling library functions - thus the library functions don't need to
>>> check for null pointers, and could perhaps even allow their usage.
>>>
>>
>> Which is exactly what I agreed with.
>>
>>> The only sensible attitude is to avoid calling memcpy and similar
>>> functions with null pointers.  The standard says memcpy has undefined
>>> behaviour for null pointers, to give the compiler and library
>>> implementers full freedom to choose the optimal code.  So you do any
>>> required checks before calling them.
>>>
>>
>> You didn't even read my post before responding, did you?  You just saw
>> that I posted and had to try to prove me wrong again.  But once again
>> you have just made a fool of yourself.
>>
> 

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

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


#95046

FromDavid Brown <david.brown@hesbynett.no>
Date2016-10-18 11:19 +0200
Message-ID<nu4peg$qrd$1@dont-email.me>
In reply to#95023
On 17/10/16 23:05, Jerry Stuckle wrote:
> On 10/17/2016 10:29 AM, David Brown wrote:
>> On 17/10/16 15:06, Jerry Stuckle wrote:
>>> On 10/17/2016 4:06 AM, David Brown wrote:
>>>> On 16/10/16 14:44, Jerry Stuckle wrote:
>>>>> On 10/16/2016 5:55 AM, Richard Bos wrote:
>>>>>> =?UTF-8?Q?L=c5=91rinczy_Zsigmond?= <nospam@for.me> wrote:
>>>>>>
>>>>>>>
>>>>>>>> As a programmer, how much of a burden is it to avoid calling memcpy()
>>>>>>>> with a null pointer?
>>>>>>>
>>>>>>> It would add a redundant 'if' to the code, increasing complexity
>>>>>>>
>>>>>>> - memcpy (to, from, len)
>>>>>>> + if (len) memcpy (to, from, len)
>>>>>>
>>>>>> Nope. Testing for null pointers should be done as early and as high up
>>>>>> as possible, _not_ in system code nor every single time you call a
>>>>>> system function. That way, you avoid a whole slew of if's with a single
>>>>>> one, rather than risk missing one.
>>>>>> Demanding that the check be done in system code also means that _all_
>>>>>> calls to that system function suffer the penalty, even those in code
>>>>>> that's written properly, with the big picture in mind.
>>>>>> In other words, don't write this:
>>>>>>
>>>>>
>>>>> Which can cause a problem with embedded and kernel programming, where
>>>>> location 0 is a valid address.  In many systems (including Intel
>>>>> processors), for instance, this is the beginning of the interrupt
>>>>> vectors, which must be set during initialization.  It is very possible
>>>>> to set multiple vectors with one call to memcpy.
>>>>>
>>>>
>>>> In practice, while location 0 is usually a valid address in embedded
>>>> systems, it is typically a rather special address.  A common case is for
>>>> the reset vector or initial stack pointer.  Sometimes (especially on
>>>> small microcontrollers) it can be part of the hardware register map.
>>>>
>>>> You would rarely want to access such locations through a pointer, and
>>>> you certainly don't want to do so via memcpy or similar functions.
>>>> Quite simply, it is not a problem.
>>>>
>>>
>>> As I said - it is often the start of the interrupt vectors - such as the
>>> reset vector.
>>>
>>> When dealing with small embedded systems without an OS (or writing the
>>> OS), you ALWAYS want to set the interrupt vectors the proper values. The
>>> way to do this is through a pointer.
>>>
>>
>> The most common way to get the correct interrupt vectors is to have them
>> as statically linked when you build your binary image for the
>> microcontroller - you don't change them at run-time, because they are
>> part of the flash or rom image.
>>
> 
> Maybe the most common way for YOU to do it.  However, not the most
> common way for OTHERS to do it.  It all depends on the microcontroller
> and the load routine.

Yes, it is the most common way to do it - because most microcontrollers
are small, and most of their programs are small, and the interrupt
vectors can be fixed at compile and link time.

But of course it depends on the microcontroller in question, and the
arrangement of the program.  In particular, if the system has a separate
bootloader of some sort then it is not unlikely that you want to change
the interrupt vectors in some way.

> 
> And it's not at all unusual for the loader to have one set of interrupt
> vectors, but once everything is loaded, to initialize the runtime to a
> different set of interrupt vectors.

Agreed, for systems with separate bootloaders.

But most small microcontroller programs don't have separate bootloaders.
 (And for many that do, the bootloaders are so small and simple that
they don't use interrupts at all.)

> 
>> For bigger embedded systems, you might want to install interrupt
>> handlers during initialisation at run-time.  This is usually done by
>> building a second interrupt table in ram, and moving the cpu's
>> "interrupt table vector" to point to the new table.  This means that the
>> interrupt vectors you are writing are not at location 0, but in ordinary
>> ram.
>>
> 
> That depends on the capability of the controller.  Many are fixed at
> location zero - even Intel chips.

These things /always/ depend on the capability of the controller.  On
most bigger embedded systems, you can change the location of the
interrupt vectors.  I don't know the details of Intel's chips, but those
are hardly common in embedded systems, and they certainly don't count as
microcontrollers.  (Unless you are talking about 8051 devices, and on
those the interrupt vectors are fixed at compile and link time.)

> 
>> And even in cases where you want to change the interrupt vectors, there
>> is one vector you /never/ want to change at run-time (except when doing
>> a whole system update) - the reset vector!
>>
> 
> Once again, incorrect.  It may be quite necessary to change the reset
> interrupt vector once code is loaded - for instance, when loading a new
> version of firmware into flash memory.  Even during normal operation it
> may be necessary to change the reset interrupt vector.

I already mentioned doing a whole system update - look a few lines up in
my post.

In normal operation, you don't change the reset vector.  Why would you?
 It is only used when there is a reset, and unless you have changed it
in non-volatile memory as part of a system update, it will be re-loaded
from ROM, Flash, or whatever is the bootup procedure for the device.
Any temporary run-time changes will be lost before they would ever be used.

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


#95057

Fromsupercat@casperkitty.com
Date2016-10-18 08:04 -0700
Message-ID<be45079c-a400-4a32-82a3-42704c783b60@googlegroups.com>
In reply to#95046
On Tuesday, October 18, 2016 at 4:19:39 AM UTC-5, David Brown wrote:
> In normal operation, you don't change the reset vector.  Why would you?
>  It is only used when there is a reset, and unless you have changed it
> in non-volatile memory as part of a system update, it will be re-loaded
> from ROM, Flash, or whatever is the bootup procedure for the device.
> Any temporary run-time changes will be lost before they would ever be used.

Changing the reset vector isn't terribly uncommon on systems which have
several kinds of reset and use a latch to select whether address 0 maps to
RAM or ROM (common on Z80 and COSMAC 1802 among others).  A "soft reset"
function may be wired to reset almost everything in the system but leave
the latch set to map RAM at address zero.

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


#95077

FromJerry Stuckle <jstucklex@attglobal.net>
Date2016-10-18 16:27 -0400
Message-ID<nu60iu$e6c$1@jstuckle.eternal-september.org>
In reply to#95046
On 10/18/2016 5:19 AM, David Brown wrote:
> On 17/10/16 23:05, Jerry Stuckle wrote:
>> On 10/17/2016 10:29 AM, David Brown wrote:
>>> On 17/10/16 15:06, Jerry Stuckle wrote:
>>>> On 10/17/2016 4:06 AM, David Brown wrote:
>>>>> On 16/10/16 14:44, Jerry Stuckle wrote:
>>>>>> On 10/16/2016 5:55 AM, Richard Bos wrote:
>>>>>>> =?UTF-8?Q?L=c5=91rinczy_Zsigmond?= <nospam@for.me> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>> As a programmer, how much of a burden is it to avoid calling memcpy()
>>>>>>>>> with a null pointer?
>>>>>>>>
>>>>>>>> It would add a redundant 'if' to the code, increasing complexity
>>>>>>>>
>>>>>>>> - memcpy (to, from, len)
>>>>>>>> + if (len) memcpy (to, from, len)
>>>>>>>
>>>>>>> Nope. Testing for null pointers should be done as early and as high up
>>>>>>> as possible, _not_ in system code nor every single time you call a
>>>>>>> system function. That way, you avoid a whole slew of if's with a single
>>>>>>> one, rather than risk missing one.
>>>>>>> Demanding that the check be done in system code also means that _all_
>>>>>>> calls to that system function suffer the penalty, even those in code
>>>>>>> that's written properly, with the big picture in mind.
>>>>>>> In other words, don't write this:
>>>>>>>
>>>>>>
>>>>>> Which can cause a problem with embedded and kernel programming, where
>>>>>> location 0 is a valid address.  In many systems (including Intel
>>>>>> processors), for instance, this is the beginning of the interrupt
>>>>>> vectors, which must be set during initialization.  It is very possible
>>>>>> to set multiple vectors with one call to memcpy.
>>>>>>
>>>>>
>>>>> In practice, while location 0 is usually a valid address in embedded
>>>>> systems, it is typically a rather special address.  A common case is for
>>>>> the reset vector or initial stack pointer.  Sometimes (especially on
>>>>> small microcontrollers) it can be part of the hardware register map.
>>>>>
>>>>> You would rarely want to access such locations through a pointer, and
>>>>> you certainly don't want to do so via memcpy or similar functions.
>>>>> Quite simply, it is not a problem.
>>>>>
>>>>
>>>> As I said - it is often the start of the interrupt vectors - such as the
>>>> reset vector.
>>>>
>>>> When dealing with small embedded systems without an OS (or writing the
>>>> OS), you ALWAYS want to set the interrupt vectors the proper values. The
>>>> way to do this is through a pointer.
>>>>
>>>
>>> The most common way to get the correct interrupt vectors is to have them
>>> as statically linked when you build your binary image for the
>>> microcontroller - you don't change them at run-time, because they are
>>> part of the flash or rom image.
>>>
>>
>> Maybe the most common way for YOU to do it.  However, not the most
>> common way for OTHERS to do it.  It all depends on the microcontroller
>> and the load routine.
> 
> Yes, it is the most common way to do it - because most microcontrollers
> are small, and most of their programs are small, and the interrupt
> vectors can be fixed at compile and link time.
> 
> But of course it depends on the microcontroller in question, and the
> arrangement of the program.  In particular, if the system has a separate
> bootloader of some sort then it is not unlikely that you want to change
> the interrupt vectors in some way.
> 
>>
>> And it's not at all unusual for the loader to have one set of interrupt
>> vectors, but once everything is loaded, to initialize the runtime to a
>> different set of interrupt vectors.
> 
> Agreed, for systems with separate bootloaders.
> 
> But most small microcontroller programs don't have separate bootloaders.
>  (And for many that do, the bootloaders are so small and simple that
> they don't use interrupts at all.)
>

I admit the smallest I work with run about 32K.  But even these often
use boot loaders.  It makes it much easier to update the code when
necessary.  It is much more difficult to do without a boot loader,
generally requiring external hardware to reload chip.

>>
>>> For bigger embedded systems, you might want to install interrupt
>>> handlers during initialisation at run-time.  This is usually done by
>>> building a second interrupt table in ram, and moving the cpu's
>>> "interrupt table vector" to point to the new table.  This means that the
>>> interrupt vectors you are writing are not at location 0, but in ordinary
>>> ram.
>>>
>>
>> That depends on the capability of the controller.  Many are fixed at
>> location zero - even Intel chips.
> 
> These things /always/ depend on the capability of the controller.  On
> most bigger embedded systems, you can change the location of the
> interrupt vectors.  I don't know the details of Intel's chips, but those
> are hardly common in embedded systems, and they certainly don't count as
> microcontrollers.  (Unless you are talking about 8051 devices, and on
> those the interrupt vectors are fixed at compile and link time.)
> 

Yes, it depends on the controller.  But most of ones I've worked with
are at fixed addresses.

And actually, I have used Intel chips in embedded systems.  They have a
whole line of embedded processors.

>>
>>> And even in cases where you want to change the interrupt vectors, there
>>> is one vector you /never/ want to change at run-time (except when doing
>>> a whole system update) - the reset vector!
>>>
>>
>> Once again, incorrect.  It may be quite necessary to change the reset
>> interrupt vector once code is loaded - for instance, when loading a new
>> version of firmware into flash memory.  Even during normal operation it
>> may be necessary to change the reset interrupt vector.
> 
> I already mentioned doing a whole system update - look a few lines up in
> my post.
> 
> In normal operation, you don't change the reset vector.  Why would you?
>  It is only used when there is a reset, and unless you have changed it
> in non-volatile memory as part of a system update, it will be re-loaded
> from ROM, Flash, or whatever is the bootup procedure for the device.
> Any temporary run-time changes will be lost before they would ever be used.
> 
> 

Yes, they are reloaded in the bootup procedure, but can be changed when
going from bootup to the running code.  I've done this many times to
initiate things like a core dump when reset is pressed.  It's a very
good debugging mechanism you can invoke when all else fails.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

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


#94996

Fromsupercat@casperkitty.com
Date2016-10-17 08:59 -0700
Message-ID<e01043bf-9ac9-4efb-a097-01ee97080195@googlegroups.com>
In reply to#94925
On Sunday, October 16, 2016 at 7:44:47 AM UTC-5, Jerry Stuckle wrote:
> Forcing library functions to test for a null pointer would preclude
> using them for these functions.

I don't think anyone is arguing that if memcpy is given a *non-zero length*
it should not require both pointers to be valid.  If the length is zero,
however, the Standard specifies no reason why memcpy should do *anything*
with its other arguments.  While it might be possible for an implementation
to achieve the indicated behavior by checking for a null argument, I would
not expect any implementation would use null-argument checking for that
purpose rather than simply exiting early in the case where length is zero.

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


#95007

FromKeith Thompson <kst-u@mib.org>
Date2016-10-17 11:21 -0700
Message-ID<lnfunug7kt.fsf@kst-u.example.com>
In reply to#94996
supercat@casperkitty.com writes:
[...]
> I don't think anyone is arguing that if memcpy is given a *non-zero length*
> it should not require both pointers to be valid.  If the length is zero,
> however, the Standard specifies no reason why memcpy should do *anything*
> with its other arguments.  While it might be possible for an implementation
> to achieve the indicated behavior by checking for a null argument, I would
> not expect any implementation would use null-argument checking for that
> purpose rather than simply exiting early in the case where length is zero.

Your argument is based on what the standard says.  What it says,
unambiguously, is that the behavior of memcpy() is undefined if
either s1 or s1 is null.

It doesn't give a *reason* for memcpy(NULL, 0, 0) to do anything
because it doesn't need to.  It doesn't give reasons for most of
its rules.

*Should* memcpy(NULL, NULL, 0) have been well defined (similar to
the way free(NULL) is well defined)?  Maybe.  Given a choice, I
might have had a slight preference for defining it to do nothing.
But I wasn't given that choice, and I'm fine with that.  I would
oppose changing it to be well defined in a future standard, because
the transition could cause more problems than the current rule and
it would be more difficult to explain.

And consider compiler warnings.  Suppose a compiler is able to prove
that the s1 and/or s2 argument is a null pointer, but doesn't know
whether n is zero.  A contrived example:

    $ gcc-6.2.0 -c -Wnonnull c.c
    c.c: In function ‘main’:
    c.c:4:5: warning: null argument where non-null required (argument 1) [-Wnonnull]
         memcpy(NULL, NULL, rand() % 2);
         ^~~~~~
    c.c:4:5: warning: null argument where non-null required (argument 2) [-Wnonnull]
    $

If memcpy(NULL, NULL, 0) were well defined, the warning would have to be
considerably more verbose.

As far as I'm concerned, it's just not that big a deal.  The current
rule seems to be optimized for simplicity.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95020

Fromsupercat@casperkitty.com
Date2016-10-17 13:42 -0700
Message-ID<b0938930-5d55-4375-a46c-c8697b44cf5b@googlegroups.com>
In reply to#95007
On Monday, October 17, 2016 at 1:20:33 PM UTC-5, Keith Thompson wrote:
> Your argument is based on what the standard says.  What it says,
> unambiguously, is that the behavior of memcpy() is undefined if
> either s1 or s1 is null.

The Standard clearly intends that except when specified otherwise,
functions that are invoked in ways *that would make use of pointers
given to them* will invoke UB if those pointers are not valid.  It
is not clear whether it was *intended* that it was required that
pointers must be valid whether or not they are used, or that the mem*
functions "use" their pointers even when size is zero.

In cases where the intention of the Standard is unclear, but where
an implementation could at essentially zero cost behave in a manner
that would be consistent not only with the Standard as not any
plausible interpretation of the intent, I would suggest that people
seeking to produce quality implementations should interpret the
Standard in that fashion.

If a platform could support a useful behavioral guarantee at essentially
zero cost and a compiler writer faces a choice between either supporting
the behavior 100% of the time, or only supporting it in the 99%+ of cases
where it can't see any advantage to doing anything else, should there be
no consideration beyond the fact that picking the latter option would not
make the compiler non-conforming?

> *Should* memcpy(NULL, NULL, 0) have been well defined (similar to
> the way free(NULL) is well defined)?  Maybe.  Given a choice, I
> might have had a slight preference for defining it to do nothing.
> But I wasn't given that choice, and I'm fine with that.  I would
> oppose changing it to be well defined in a future standard, because
> the transition could cause more problems than the current rule and
> it would be more difficult to explain.

The memcpy and memmove functions actually have a much bigger problem,
which is that they sometimes transfer the Effective Type of the source
operand; if the Standard added language to fix that, clarifying that
memcpy(anything, anything, 0) would be simple.

> And consider compiler warnings.  Suppose a compiler is able to prove
> that the s1 and/or s2 argument is a null pointer, but doesn't know
> whether n is zero.  A contrived example:

Given that compilers are allowed to issue non-fatal warnings for any reason
whatsoever, even for strictly-conforming programs, I don't see why defining
memcpy(any, any, 0) as a no-op should prevent a compiler from issuing a
warnings about memcpy(anything, NULL, anything), since such a statement would
be at best useless.

>     c.c:4:5: warning: null argument where non-null required (argument 2) [-Wnonnull]

> If memcpy(NULL, NULL, 0) were well defined, the warning would have to be
> considerably more verbose.

Not really, "memcpy() argument 2 always null".  That's actually shorter
and more useful than the given message [in a macro, it may not be clear
what function it's squawking about].  If one wants to say more about why
a null argument is bad:

   memcpy() with src==null performs no useful action.

That doesn't seem horribly verbose to me.

> As far as I'm concerned, it's just not that big a deal.  The current
> rule seems to be optimized for simplicity.

It is; the question is whether that's because the authors:

  1. didn't think implementations should need to treat that case
     as a no-op, or

  2. couldn't imagine any implementations doing otherwise and didn't
     want to waste ink ordering implementations to do something they'd
     do anyway.

If the intention was the second, and the authors were optimizing for
simplicity, what would you expect the authors of the Standard to say?

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


#95027

FromKeith Thompson <kst-u@mib.org>
Date2016-10-17 14:46 -0700
Message-ID<ln37jufy2r.fsf@kst-u.example.com>
In reply to#95020
supercat@casperkitty.com writes:
> On Monday, October 17, 2016 at 1:20:33 PM UTC-5, Keith Thompson wrote:
>> Your argument is based on what the standard says.  What it says,
>> unambiguously, is that the behavior of memcpy() is undefined if
>> either s1 or s1 is null.
>
> The Standard clearly intends that except when specified otherwise,
> functions that are invoked in ways *that would make use of pointers
> given to them* will invoke UB if those pointers are not valid.  It
> is not clear whether it was *intended* that it was required that
> pointers must be valid whether or not they are used, or that the mem*
> functions "use" their pointers even when size is zero.

Please cite any wording in the standard that supports your "that would
make use of pointers given to them" wording.

N1570 7.1.4p1:

    Each of the following statements applies unless explicitly
    stated otherwise in the detailed descriptions that follow: If
    an argument to a function has an invalid value (such as [...],
    or a null pointer, or [...]) or [...], the behavior is undefined.

Feel free to confirm that the words I've omitted are not relevant
to the current discussion.

> In cases where the intention of the Standard is unclear, but where
> an implementation could at essentially zero cost behave in a manner
> that would be consistent not only with the Standard as not any
> plausible interpretation of the intent, I would suggest that people
> seeking to produce quality implementations should interpret the
> Standard in that fashion.

They are most certainly free to do so.  (In fact, memcpy(NULL, NULL, 0)
appears to quietly do nothing on the implementation I'm using, though
its documentation doesn't mention that case so I certainly wouldn't want
to depend on it.)

[big snip]

I don't even necessarly disagree with you that the memcpy(NULL, NULL, 0)
*should* have had defined behavior.  If it had been defined that
way by ANSI, or by the "1984 /usr/group Standard" referenced in the
standard's introduction, I'd be perfectly happy with that, and I'd
feel free to depend on that behavior.  But I'm not bothered by the
fact that the behavior is undefined, and I've seen no evidence that
it was ever intended to be defined.  If the committee had intended
to define the behavior of memcpy(NULL, NULL, 0), they could easily
have done so, as they did for free(NULL).  The fact that they didn't
do so is the only evidence I can see (or that I personally need)
of their intent.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95031

Fromsupercat@casperkitty.com
Date2016-10-17 15:52 -0700
Message-ID<003e026c-0fca-40b2-ab84-2197571d165f@googlegroups.com>
In reply to#95027
On Monday, October 17, 2016 at 4:45:57 PM UTC-5, Keith Thompson wrote:
> > The Standard clearly intends that except when specified otherwise,
> > functions that are invoked in ways *that would make use of pointers
> > given to them* will invoke UB if those pointers are not valid.  It
> > is not clear whether it was *intended* that it was required that
> > pointers must be valid whether or not they are used, or that the mem*
> > functions "use" their pointers even when size is zero.
> 
> Please cite any wording in the standard that supports your "that would
> make use of pointers given to them" wording.

The opposite of my first sentence above would be that passing invalid
pointers to functions will not invoke UB, *even if the functions would be
expected to use those pointers*.  The point of my highlighting was to
indicate that I am conceding only those cases.

> N1570 7.1.4p1:
> 
>     Each of the following statements applies unless explicitly
>     stated otherwise in the detailed descriptions that follow: If
>     an argument to a function has an invalid value (such as [...],
>     or a null pointer, or [...]) or [...], the behavior is undefined.
> 
> Feel free to confirm that the words I've omitted are not relevant
> to the current discussion.

What is ambiguous is what is meant by the phrase "invalid value" in 7.1.4.
While the Standard gives some examples of invalid values, the phrase "such
as" does not imply that everything to its right is always something of the
type to its left.  If a recycling center says it accepts products made of
thin sheet aluminum such as soda cans, for example, that would not imply
that it accepts steel soda cans.

The validity of a pointer argument depends upon whether it can support the
uses to which it will be put, and if the length is zero, neither argument
to memcpy() will be used in *any observable fashion whatsoever*.  Note that
the situation is very different with something like free(0) [which is
defined], or fclose(0) [which isn't] since the only way either function
could avoid UB when given a null pointer would be to explicitly check for
it, while the only thing memcpy would need to do is simply ignore a
parameter whose value could have no defined effect on program execution.

> I don't even necessarly disagree with you that the memcpy(NULL, NULL, 0)
> *should* have had defined behavior.  If it had been defined that
> way by ANSI, or by the "1984 /usr/group Standard" referenced in the
> standard's introduction, I'd be perfectly happy with that, and I'd
> feel free to depend on that behavior.  But I'm not bothered by the
> fact that the behavior is undefined, and I've seen no evidence that
> it was ever intended to be defined.  If the committee had intended
> to define the behavior of memcpy(NULL, NULL, 0), they could easily
> have done so, as they did for free(NULL).  The fact that they didn't
> do so is the only evidence I can see (or that I personally need)
> of their intent.

The function "free()" would be expected to result in accesses to storage
at the passed-in address except for the explicit case where that address
is null.  By contrast, memcpy(dest, src, 0) is guaranteed not to read any
bytes from src, nor write any bytes to dest, except in cases where those
reads or writes would have no observable effect on program behavior.

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


#95036

FromKeith Thompson <kst-u@mib.org>
Date2016-10-17 16:43 -0700
Message-ID<lny41mee3s.fsf@kst-u.example.com>
In reply to#95031
supercat@casperkitty.com writes:
> On Monday, October 17, 2016 at 4:45:57 PM UTC-5, Keith Thompson wrote:
>> > The Standard clearly intends that except when specified otherwise,
>> > functions that are invoked in ways *that would make use of pointers
>> > given to them* will invoke UB if those pointers are not valid.  It
>> > is not clear whether it was *intended* that it was required that
>> > pointers must be valid whether or not they are used, or that the mem*
>> > functions "use" their pointers even when size is zero.
>> 
>> Please cite any wording in the standard that supports your "that would
>> make use of pointers given to them" wording.
>
> The opposite of my first sentence above would be that passing invalid
> pointers to functions will not invoke UB, *even if the functions would be
> expected to use those pointers*.  The point of my highlighting was to
> indicate that I am conceding only those cases.

So that's consistent with what the standard actually says, which is
that a null pointer argument results in undefined behavior unless
the documentation for the function says otherwise.

Hmm, I just noticed that there is no such explicit exception for
`printf("%p", (void*)0)`.  I presume that it's intended to print an
implementation-defined representation of a null pointer, and that the
lack of an explicit exception is an unintentional oversight (the
committee's or perhaps mine if there's something I've missed).

>> N1570 7.1.4p1:
>> 
>>     Each of the following statements applies unless explicitly
>>     stated otherwise in the detailed descriptions that follow: If
>>     an argument to a function has an invalid value (such as [...],
>>     or a null pointer, or [...]) or [...], the behavior is undefined.
>> 
>> Feel free to confirm that the words I've omitted are not relevant
>> to the current discussion.
>
> What is ambiguous is what is meant by the phrase "invalid value" in 7.1.4.
> While the Standard gives some examples of invalid values, the phrase "such
> as" does not imply that everything to its right is always something of the
> type to its left.  If a recycling center says it accepts products made of
> thin sheet aluminum such as soda cans, for example, that would not imply
> that it accepts steel soda cans.

I believe the intent is that all the cases following "such as" are meant
to be invalid unless explicitly stated otherwise in the detailed
descriptions.  All the cases other than "a null pointer" are clearly
invalid.  I find it implausible that that's the only exception,
especially given that there are cases where null pointers are stated
explicitly to be valid.  (Usually such a statement is needed because the
behavior would be unclear otherwise.)

> The validity of a pointer argument depends upon whether it can support the
> uses to which it will be put, and if the length is zero, neither argument
> to memcpy() will be used in *any observable fashion whatsoever*.  Note that
> the situation is very different with something like free(0) [which is
> defined], or fclose(0) [which isn't] since the only way either function
> could avoid UB when given a null pointer would be to explicitly check for
> it, while the only thing memcpy would need to do is simply ignore a
> parameter whose value could have no defined effect on program execution.

Consider a hypothetical implementation of memcpy() that checks its
arguments, causing a segfault if either s1 or s2 is a null pointer.
You would assert, I presume, that such an implementation would
be non-conforming?

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95056

Fromsupercat@casperkitty.com
Date2016-10-18 08:00 -0700
Message-ID<3dc49e97-bb93-411f-8fe3-7cdbb6fdb70d@googlegroups.com>
In reply to#95036
On Monday, October 17, 2016 at 6:43:23 PM UTC-5, Keith Thompson wrote:
> I believe the intent is that all the cases following "such as" are meant
> to be invalid unless explicitly stated otherwise in the detailed
> descriptions.  All the cases other than "a null pointer" are clearly
> invalid.  I find it implausible that that's the only exception,
> especially given that there are cases where null pointers are stated
> explicitly to be valid.  (Usually such a statement is needed because the
> behavior would be unclear otherwise.)

The term "such as" in English prose does not imply that the author has
endeavored to call out every possible exception, much less gone through
any effort to ensure that all possible exceptions were listed.

> Consider a hypothetical implementation of memcpy() that checks its
> arguments, causing a segfault if either s1 or s2 is a null pointer.
> You would assert, I presume, that such an implementation would
> be non-conforming?

Consider a not-so-hypothetical C compiler which requires functions to be
written out as:

    int foo(bar)
      int bar;
    {
       printf("%d", bar);
    }

rather than what is now the more fashionable

    int foo(int bar)
    {
       printf("%d", bar);
    }

There were a lot of implementations like that in 1988.  Would you brand
them all as non-conforming?  There is nothing wrong with a standard
requiring implementations to do something they wouldn't otherwise do--
that's part of the *point* of standards.  Even on your hypothetical
implementation, do you think that the usefulness would be in any way
impaired by requiring that it check for a size of zero before validating
the pointers?

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


#95068

FromKeith Thompson <kst-u@mib.org>
Date2016-10-18 09:14 -0700
Message-ID<lnh989eit0.fsf@kst-u.example.com>
In reply to#95056
supercat@casperkitty.com writes:
> On Monday, October 17, 2016 at 6:43:23 PM UTC-5, Keith Thompson wrote:
>> I believe the intent is that all the cases following "such as" are meant
>> to be invalid unless explicitly stated otherwise in the detailed
>> descriptions.  All the cases other than "a null pointer" are clearly
>> invalid.  I find it implausible that that's the only exception,
>> especially given that there are cases where null pointers are stated
>> explicitly to be valid.  (Usually such a statement is needed because the
>> behavior would be unclear otherwise.)
>
> The term "such as" in English prose does not imply that the author has
> endeavored to call out every possible exception, much less gone through
> any effort to ensure that all possible exceptions were listed.

I'll acknowledge that the wording is ambiguous.

>> Consider a hypothetical implementation of memcpy() that checks its
>> arguments, causing a segfault if either s1 or s2 is a null pointer.
>> You would assert, I presume, that such an implementation would
>> be non-conforming?

I see you've decided to ignore that.

> Consider a not-so-hypothetical C compiler which requires functions to be
> written out as:
>
>     int foo(bar)
>       int bar;
>     {
>        printf("%d", bar);
>     }
>
> rather than what is now the more fashionable
>
>     int foo(int bar)
>     {
>        printf("%d", bar);
>     }
>
> There were a lot of implementations like that in 1988.  Would you brand
> them all as non-conforming?

Of course they're non-conforming.  They conformed to the language as
it existed at the time (though even in 1988 support for prototypes
was becoming widespread), but not to any language definition pubished
since 1989.

No doubt there's some connection between that and what I was talking
about, but you haven't chosen to share your reasoning.

>                              There is nothing wrong with a standard
> requiring implementations to do something they wouldn't otherwise do--
> that's part of the *point* of standards.  Even on your hypothetical
> implementation, do you think that the usefulness would be in any way
> impaired by requiring that it check for a size of zero before validating
> the pointers?

Probably not, but that's beside the point.  As I've said, it would have
been reasonable for the standard to state that memcpy(NULL, NULL, 0) has
well defined behavior.  But that's not what the standard says, at least
not explicitly.  There's probably a case to be made that it's implied,
but given the actual wording, in my opinion there's a stronger case that
the behavior is undefined (even if every existing implementation happens
to have the same behavior, which may or may not be the case).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95069

Fromsupercat@casperkitty.com
Date2016-10-18 09:43 -0700
Message-ID<1c6a99e7-93b9-4a27-9201-aa5b6e7985aa@googlegroups.com>
In reply to#95068
On Tuesday, October 18, 2016 at 11:14:01 AM UTC-5, Keith Thompson wrote:
> supercat writes:
> >> Consider a hypothetical implementation of memcpy() that checks its
> >> arguments, causing a segfault if either s1 or s2 is a null pointer.
> >> You would assert, I presume, that such an implementation would
> >> be non-conforming?
> 
> I see you've decided to ignore that.

The Standard does not impose any requirements upon how an implementation
processes *any* program, other than the One, which does not contain any
#error directives.  So nothing memcpy could do would make an implementation
non-conforming under a literal reading of the Standard if the One Program
did not use memcpy, or did so in a way that happened to behave normally.

I would say that treating memcpy(any,any,0) as a no-op is a behavior which
programmers should be entitled to expect from any quality implementation
which has not been specifically requested to identify ways in which a
program might fail on inferior implementations, and I would consider that
such requests are generally best handled via non-conforming modes, rendering
the question of conformance for them irrelevant.

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


#95073

FromKeith Thompson <kst-u@mib.org>
Date2016-10-18 11:31 -0700
Message-ID<ln8ttlecgh.fsf@kst-u.example.com>
In reply to#95069
supercat@casperkitty.com writes:
> On Tuesday, October 18, 2016 at 11:14:01 AM UTC-5, Keith Thompson wrote:
>> supercat writes:
>> >> Consider a hypothetical implementation of memcpy() that checks its
>> >> arguments, causing a segfault if either s1 or s2 is a null pointer.
>> >> You would assert, I presume, that such an implementation would
>> >> be non-conforming?
>> 
>> I see you've decided to ignore that.
>
> The Standard does not impose any requirements upon how an implementation
> processes *any* program, other than the One, which does not contain any
> #error directives.  So nothing memcpy could do would make an implementation
> non-conforming under a literal reading of the Standard if the One Program
> did not use memcpy, or did so in a way that happened to behave normally.

The One Program argument is irrelevant.

> I would say that treating memcpy(any,any,0) as a no-op is a behavior which
> programmers should be entitled to expect from any quality implementation
> which has not been specifically requested to identify ways in which a
> program might fail on inferior implementations, and I would consider that
> such requests are generally best handled via non-conforming modes, rendering
> the question of conformance for them irrelevant.

So you think the standard *should* specify that memcpy(NULL, NULL, 0)
is a well defined no-op.  I have no particular problem with that.

And if you think the question of conformance is irrelevant, feel free
not to participate in such discussions.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95076

Fromsupercat@casperkitty.com
Date2016-10-18 12:49 -0700
Message-ID<384fb8c2-e3df-48f6-80e2-9d1991f5a20e@googlegroups.com>
In reply to#95073
On Tuesday, October 18, 2016 at 1:30:16 PM UTC-5, Keith Thompson wrote:
> supercat writes:
> > The Standard does not impose any requirements upon how an implementation
> > processes *any* program, other than the One, which does not contain any
> > #error directives.  So nothing memcpy could do would make an implementation
> > non-conforming under a literal reading of the Standard if the One Program
> > did not use memcpy, or did so in a way that happened to behave normally.
> 
> The One Program argument is irrelevant.

Would an implementation that mapped memcpy() to memmove(), and defined
a large automatic array for use as a temporary buffer be conforming (on
some systems, a bottom-up copy will be more than twice as fast as a top-
down copy).  Does anything in the Standard say how much a program must
be able to have on the stack when calling memcpy(), or about what memcpy()
would have to do if stack space is exhausted?

The authors of the Standard explicitly recognize in the rationale the
possibility that implementations may be simultaneously conforming and
useless.  I see no reason to believe that implementations where memcpy()
would kill the stack in nearly all of the cases a program might try to
use it would not fall into the "conforming but useless" category.  Would
you argue that such implementations were not conforming?  On what basis?

> So you think the standard *should* specify that memcpy(NULL, NULL, 0)
> is a well defined no-op.  I have no particular problem with that.
> 
> And if you think the question of conformance is irrelevant, feel free
> not to participate in such discussions.

The authors of the Standard didn't think it was necessary to prevent the
authors of implementations from pointlessly impairing their usefulness,
and I can't think of anyplace where the Standard expends ink doing so.

BTW, would you regard the following version of memcpy as conforming or
non-conforming:

    void *memcpy(void *dest, void const *src, size_t n)
    {
      unsigned char *d = dest;
      unsigned char const *s = src;
      for (size_t i=0; i<n; i++)
        d[n-1-i] = s[i];
    }

It copies all n bytes from the object pointed to by src to the object
pointed to by dest.  On some implementations (e.g. the Cosmac 1802)
an unrolled loop that reversed the sequence of bytes as it copied them
would be almost 50% faster than one which output them in order, and for
some purposes a reversing copy operation would be just fine (e.g. if code
copies data to an unsigned char buffer and later copies it back, without
using the copy in the buffer for any other purpose).

The authors of the Standard may have intended to force implementations for
the 1802 to accept the extra 50% performance overhead of writing data out
in the same order as it was read, but the documentation for memcpy() doesn't
specify that.  Would the description of memcpy() be meaningful to anyone
who doesn't "read between the lines"?  And is there any reason why someone
trying to read between the lines would expect that copying N bytes from one
object to another would be allowed to have any observable effect beyond N
reads and N writes?

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


#95074

FromKeith Thompson <kst-u@mib.org>
Date2016-10-18 12:03 -0700
Message-ID<lnzim1cweq.fsf@kst-u.example.com>
In reply to#95069
supercat@casperkitty.com writes:
> On Tuesday, October 18, 2016 at 11:14:01 AM UTC-5, Keith Thompson wrote:
>> supercat writes:
>> >> Consider a hypothetical implementation of memcpy() that checks its
>> >> arguments, causing a segfault if either s1 or s2 is a null pointer.
>> >> You would assert, I presume, that such an implementation would
>> >> be non-conforming?
>> 
>> I see you've decided to ignore that.
>
> The Standard does not impose any requirements upon how an implementation
> processes *any* program, other than the One, which does not contain any
> #error directives.  So nothing memcpy could do would make an implementation
> non-conforming under a literal reading of the Standard if the One Program
> did not use memcpy, or did so in a way that happened to behave normally.
>
> I would say that treating memcpy(any,any,0) as a no-op is a behavior which
> programmers should be entitled to expect from any quality implementation
> which has not been specifically requested to identify ways in which a
> program might fail on inferior implementations, and I would consider that
> such requests are generally best handled via non-conforming modes, rendering
> the question of conformance for them irrelevant.

Let's take another look at the actual wording in the description of
memcpy().  N1570 7.24.2.1p2:

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

You claim that memcpy(NULL, NULL, 0) should copy 0 characters,
and therefore should not misbehave if the first and/or second
argument is a null pointer.  But the standard says those characters
are copied from "the object" to "the object".  From what object,
and to what object, are 0 characters copied?

The description makes no sense unless there actually are objects
pointed to by s2 and by s1.  The standard does not describe the
behavior of memcpy(NULL, NULL, 0), therefore the behavior is
undefined.

The current wording suggests that the authors of the standard did *not*
intend to define the behavior of memcpy(NULL, NULL, 0).  Either they
intended to leave the behavior undefined, or they didn't think of that
particular case.

And again, if you think the behavior *should* be defined, I have no
problem with that.  If you think that implementations *should* treat
memcpy(NULL, NULL, 0) as a no-op, I have no problem with that either
(such behavior is of course conforming under either interpretation).
If you wish to advocate changing the wording in the next edition of
the C standard so that memcpy with n==0 is a well-defined no-op even
if either s1 or s2 is a null pointer, I won't object (though I would
first ask for a survey of the behavior of existing implementations).
But the standard simply does not define the behavior of memcpy(NULL,
NULL, 0), so even if we either ignore the "such as" clause in
7.1.4p1 or interpret it in some other way, the behavior is undefined.

(I would also have no problem with either leaving the wording as
it is, or with adding wording that states more explicitly that
the behavior is undefined.  Here I'm not disagreeing with you;
I'm just not sharing your preference.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

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


#95024

FromJerry Stuckle <jstucklex@attglobal.net>
Date2016-10-17 17:06 -0400
Message-ID<nu3egu$h8g$2@jstuckle.eternal-september.org>
In reply to#94996
On 10/17/2016 11:59 AM, supercat@casperkitty.com wrote:
> On Sunday, October 16, 2016 at 7:44:47 AM UTC-5, Jerry Stuckle wrote:
>> Forcing library functions to test for a null pointer would preclude
>> using them for these functions.
> 
> I don't think anyone is arguing that if memcpy is given a *non-zero length*
> it should not require both pointers to be valid.  If the length is zero,
> however, the Standard specifies no reason why memcpy should do *anything*
> with its other arguments.  While it might be possible for an implementation
> to achieve the indicated behavior by checking for a null argument, I would
> not expect any implementation would use null-argument checking for that
> purpose rather than simply exiting early in the case where length is zero.
> 

Oh, I don't argue about what it should do with a zero length.  The
questions came up as to what to do if one or both pointers were NULL.

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

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


#95028

Fromsupercat@casperkitty.com
Date2016-10-17 14:55 -0700
Message-ID<f0d8c344-3374-4f56-9ef3-d97a58ff4aeb@googlegroups.com>
In reply to#95024
On Monday, October 17, 2016 at 4:07:04 PM UTC-5, Jerry Stuckle wrote:
> On 10/17/2016 11:59 AM, supercat wrote:
> > On Sunday, October 16, 2016 at 7:44:47 AM UTC-5, Jerry Stuckle wrote:
> >> Forcing library functions to test for a null pointer would preclude
> >> using them for these functions.
> > 
> > I don't think anyone is arguing that if memcpy is given a *non-zero length*
> > it should not require both pointers to be valid.  If the length is zero,
> > however, the Standard specifies no reason why memcpy should do *anything*
> > with its other arguments.  While it might be possible for an implementation
> > to achieve the indicated behavior by checking for a null argument, I would
> > not expect any implementation would use null-argument checking for that
> > purpose rather than simply exiting early in the case where length is zero.
> 
> Oh, I don't argue about what it should do with a zero length.  The
> questions came up as to what to do if one or both pointers were NULL.

I don't think anyone here is arguing about any cases where the length is
non zero and one or both pointers is null.  Those are, and should be,
regarded as UB.  The sole question is whether a length of zero should
be sufficient to guarantee that the function will not do anything,
regardless of what pointers might be given to it.  Note that it would
be easier for the Standard to allow all pointer arguments when length
is zero than for it to clarify the behavior of:

    unsigned char foo[16];
    memcpy(dest, foo+16-n, n);

where n might be zero without handling all zero-length cases.

BTW, the N1570 wording is also ambiguous about situations where the source
and destination of memmove are the *same* object. The exact wording is:

   If copying takes place between objects that overlap, the behavior
   is undefined.

Two pointers that identify the same object don't identify overlapping
objectS, but I've read many claims that behavior would be undefined in
that case.  Other places in the Standard where similar rules would apply
explicitly specify that when things overlap the overlap must be exact;
a footnote to that effect would have been helpful.


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


Page 2 of 5 — ← Prev page 1 [2] 3 4 5  Next page →

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


csiph-web