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


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

setting pointers to NULL and testing question.

Started byG G <gdotone@gmail.com>
First post2016-06-12 16:21 -0700
Last post2016-06-16 21:39 -0700
Articles 20 on this page of 86 — 20 participants

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


Contents

  setting pointers to NULL and testing question. G G <gdotone@gmail.com> - 2016-06-12 16:21 -0700
    Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-13 00:50 +0100
      Re: setting pointers to NULL and testing question. G G <gdotone@gmail.com> - 2016-06-12 17:03 -0700
      Re: setting pointers to NULL and testing question. Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-06-12 20:25 -0600
        Re: setting pointers to NULL and testing question. James Kuyper <jameskuyper@verizon.net> - 2016-06-12 22:57 -0400
          Re: setting pointers to NULL and testing question. Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-06-13 10:03 -0600
            Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-15 14:43 -0700
        Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-13 08:06 -0700
          Re: setting pointers to NULL and testing question. Richard Damon <Richard@Damon-Family.org> - 2016-06-16 08:27 -0400
            Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-16 06:27 -0700
              Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-16 07:31 -0700
              Re: setting pointers to NULL and testing question. Richard Damon <Richard@Damon-Family.org> - 2016-06-18 13:39 -0400
                Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-18 11:37 -0700
                  Re: setting pointers to NULL and testing question. Richard Damon <Richard@Damon-Family.org> - 2016-06-18 17:17 -0400
                    Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-18 17:22 -0700
        Re: setting pointers to NULL and testing question. James Kuyper <jameskuyper@verizon.net> - 2016-06-13 14:10 -0400
          Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-13 11:28 -0700
          Re: setting pointers to NULL and testing question. Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2016-06-13 12:31 -0600
      Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-12 19:38 -0700
        Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-13 07:35 +0100
      Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-13 11:40 +0100
        Re: setting pointers to NULL and testing question. BartC <bc@freeuk.com> - 2016-06-13 11:56 +0100
          Re: setting pointers to NULL and testing question. Martin Shobe <mashobe9@gmail.com> - 2016-06-13 06:22 -0500
            Re: setting pointers to NULL and testing question. BartC <bc@freeuk.com> - 2016-06-13 12:39 +0100
              Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-13 15:22 +0100
                Re: setting pointers to NULL and testing question. BartC <bc@freeuk.com> - 2016-06-13 17:34 +0100
                  Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-13 19:31 +0100
                    Re: setting pointers to NULL and testing question. BartC <bc@freeuk.com> - 2016-06-13 20:17 +0100
                      Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-13 12:47 -0700
                        Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-15 16:44 -0700
                          Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-15 17:20 -0700
        Re: setting pointers to NULL and testing question. Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-06-13 04:01 -0700
          Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-16 12:57 -0700
        Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-13 12:18 +0100
          Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-13 14:01 +0200
            Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-13 14:15 +0100
              Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-13 15:37 +0200
                Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-13 14:48 +0100
          Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-13 15:43 +0100
    Re: setting pointers to NULL and testing question. Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-06-12 17:54 -0700
    Re: setting pointers to NULL and testing question. John Bode <jfbode1029@gmail.com> - 2016-06-14 08:36 -0700
      Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-14 16:41 +0100
      Re: setting pointers to NULL and testing question. Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-06-14 09:01 -0700
      Re: setting pointers to NULL and testing question. "James R. Kuyper" <jameskuyper@verizon.net> - 2016-06-14 13:25 -0400
        Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-14 10:48 -0700
          Re: setting pointers to NULL and testing question. Ian Collins <ian-news@hotmail.com> - 2016-06-15 08:24 +1200
            Re: setting pointers to NULL and testing question. "James R. Kuyper" <jameskuyper@verizon.net> - 2016-06-14 16:57 -0400
              Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-14 14:29 -0700
                Re: setting pointers to NULL and testing question. BartC <bc@freeuk.com> - 2016-06-14 22:41 +0100
                  Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-14 15:16 -0700
                    Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-15 00:25 +0100
                      Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-14 16:58 -0700
                      Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-15 09:28 +0200
                        Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-15 09:57 -0700
                Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-15 09:23 +0200
                  Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-15 08:35 +0100
                    Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-15 08:37 +0100
                    Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-15 10:42 +0200
                      Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-15 13:28 +0100
                  Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-15 11:41 -0700
                  Re: setting pointers to NULL and testing question. raltbos@xs4all.nl (Richard Bos) - 2016-06-15 19:43 +0000
                    Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-15 13:09 -0700
                    Re: setting pointers to NULL and testing question. David Brown <david.brown@hesbynett.no> - 2016-06-15 22:31 +0200
                    Re: setting pointers to NULL and testing question. Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-06-15 17:11 -0400
                      Re: setting pointers to NULL and testing question. raltbos@xs4all.nl (Richard Bos) - 2016-06-18 20:44 +0000
                        Re: setting pointers to NULL and testing question. Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-06-18 17:20 -0400
          Re: setting pointers to NULL and testing question. Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-06-14 23:22 -0700
            Re: setting pointers to NULL and testing question. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-06-15 13:23 +0100
        Re: setting pointers to NULL and testing question. John Bode <jfbode1029@gmail.com> - 2016-06-20 13:36 -0700
      Re: setting pointers to NULL and testing question. Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-06-14 14:59 -0400
        Re: setting pointers to NULL and testing question. "James R. Kuyper" <jameskuyper@verizon.net> - 2016-06-14 15:17 -0400
        Re: setting pointers to NULL and testing question. Richard Heathfield <rjh@cpax.org.uk> - 2016-06-14 20:25 +0100
        Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-15 19:48 -0700
          Re: setting pointers to NULL and testing question. Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-06-15 23:25 -0400
            Re: setting pointers to NULL and testing question. James Kuyper <jameskuyper@verizon.net> - 2016-06-16 12:11 -0400
              Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-16 09:25 -0700
              Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-16 21:46 -0700
                Re: setting pointers to NULL and testing question. Gareth Owen <gwowen@gmail.com> - 2016-06-17 06:13 +0100
                  Re: setting pointers to NULL and testing question. Robert Wessel <robertwessel2@yahoo.com> - 2016-06-17 02:03 -0500
                    Re: setting pointers to NULL and testing question. Martin Shobe <mashobe9@gmail.com> - 2016-06-17 07:07 -0500
                  Re: setting pointers to NULL and testing question. supercat@casperkitty.com - 2016-06-17 03:18 -0700
                  Re: setting pointers to NULL and testing question. James Kuyper <jameskuyper@verizon.net> - 2016-06-17 09:16 -0400
                    Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-21 11:03 -0700
                  Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-21 10:58 -0700
                Re: setting pointers to NULL and testing question. Keith Thompson <kst-u@mib.org> - 2016-06-21 11:28 -0700
            Re: setting pointers to NULL and testing question. Tim Rentsch <txr@alumni.caltech.edu> - 2016-06-16 21:39 -0700

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


#88991 — setting pointers to NULL and testing question.

FromG G <gdotone@gmail.com>
Date2016-06-12 16:21 -0700
Subjectsetting pointers to NULL and testing question.
Message-ID<31b753b3-2d70-40f3-885e-2a75b98cf739@googlegroups.com>
when should a pointer to set to NULL and test whether
it is NULL?

[toc] | [next] | [standalone]


#88992

FromRichard Heathfield <rjh@cpax.org.uk>
Date2016-06-13 00:50 +0100
Message-ID<njksgm$8mt$1@dont-email.me>
In reply to#88991
On 13/06/16 00:21, G G wrote:
> when should a pointer to set to NULL and test whether
> it is NULL?

That's an excellent question.

A pointer can be in any of three states:

(1) a null pointer;
(2) a valid pointer to an existing object or function;
(3) indeterminate.

In which of these states can we legitimately test a pointer (compare its 
value to some other value)? Answer: state 1 (a null pointer) and state 2 
(a valid pointer), but NOT state 3.

There are two things we want to avoid:

(1) trying to dereference a null pointer;
(2) trying to dereference an indeterminate pointer.

Here comes the answer to your second question.

We can avoid dereferencing a null pointer easily, simply by testing 
before dereferencing. Thus, if there is any possibility that a pointer 
might have a null value, we should test before dereferencing:

if(p != NULL)
{
   *p ...
}

This is not necessary if the pointer /cannot/ be a null pointer:

int i = 42;
int *p = &i;
*p ... is fine, without the test, because p can't be null, because &i 
can't be null.

Now for your first question.

What we /can't/ do is test an indeterminate pointer in this way. If p is 
indeterminate, simply comparing it to NULL invokes undefined behaviour 
(which, in this case, is Very Bad).

What we /can/ do is ensure that we are never put into that position. So 
we should always make sure that our pointer is in one of three states:

(1) a null pointer (because we can test this);
(2) a valid pointer;
(3) an indeterminate pointer that's just about to go out of scope anyway 
so we don't care.

So let's just pretend that we have a pointer whose initial value we are 
not yet in a position to decide. Set It To NULL!

int *p = NULL;

Later in the code, we can test for this.

if(some_condition)
{
   p = some_function_yielding_a_pointer(args);
}
if(p != NULL)
{
   all is well.

We're not worried about state (2), valid pointers, because they're... 
well, valid.

But what about when we render a pointer /in/valid? This can happen in 
either of two circumstances:

(1) we know for a fact that we're about to go out of scope:

   free(p);
   return z;
}

In that circumstance, setting p to NULL is of course perfectly legal but 
might be regarded in some quarters as being mildly paranoid.

(2) we /don't/ know for a fact that we're about to go out of scope:

   free(p);
   p = NULL;

By doing this, we retain our ability to compare p to NULL. Thus, code 
that comes /after/ this code can safely test p before using it. If we 
didn't do that:

   free(p); /* fine */
   ;        /* haven't set p to NULL - could be a problem later */
   if(p != NULL) /* undefined behaviour */

So the answer to your questions, in brief, is:

(a) we should give a pointer a null value if we don't have a valid value 
to give it (unless it's about to go out of scope);
(b) we should compare a pointer's value to NULL before dereferencing it 
(if there is even the slightest possibility that it might be a null 
pointer).

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

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


#88993

FromG G <gdotone@gmail.com>
Date2016-06-12 17:03 -0700
Message-ID<62624d21-46a0-40ad-a995-136f4254501c@googlegroups.com>
In reply to#88992
WoW! Thanks Richard.
   really helpful.

g.

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


#88995

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2016-06-12 20:25 -0600
Message-ID<1ba8iprfjq.fsf@pfeifferfamily.net>
In reply to#88992
Excellent response, but I do have one question.  You say
Richard Heathfield <rjh@cpax.org.uk> writes:
>
> What we /can't/ do is test an indeterminate pointer in this way. If p
> is indeterminate, simply comparing it to NULL invokes undefined
> behaviour (which, in this case, is Very Bad).

In the C99 standard (note -- I've actually only got a committee draft
from 2005, and don't know what differences the final standard might
have) I find in 6.5.9

3 The == (equal to) and != (not equal to) operators are analogous to the relational
  operators except for their lower precedence.91) Each of the operators yields 1 if the
  specified relation is true and 0 if it is false. The result has type int. For any pair of
  operands, exactly one of the relations is true.

and in 6.5.10

6 Two pointers compare equal if and only if both are null pointers, both are pointers to the
  same object (including a pointer to an object and a subobject at its beginning) or function,
  both are pointers to one past the last element of the same array object, or one is a pointer
  to one past the end of one array object and the other is a pointer to the start of a different
  array object that happens to immediately follow the first array object in the address
  space.92)

So it would seem as if in the case that a pointer is compared to null,
it will compare equal if the pointer is also null, or not equal in all
other circumstances.

The comparison is useless in the case of an indeterminate pointer, of
course, since an indeterminate pointer has a vanishingly small
possibility of being null.  But I'm not seeing why it's undefined
behavior.

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


#88997

FromJames Kuyper <jameskuyper@verizon.net>
Date2016-06-12 22:57 -0400
Message-ID<njl7f6$2kr$1@dont-email.me>
In reply to#88995
On 06/12/2016 10:25 PM, Joe Pfeiffer wrote:
> Excellent response, but I do have one question.  You say
> Richard Heathfield <rjh@cpax.org.uk> writes:
>>
>> What we /can't/ do is test an indeterminate pointer in this way. If p
>> is indeterminate, simply comparing it to NULL invokes undefined
>> behaviour (which, in this case, is Very Bad).
> 
> In the C99 standard (note -- I've actually only got a committee draft
> from 2005, and don't know what differences the final standard might
> have) I find in 6.5.9
> 
> 3 The == (equal to) and != (not equal to) operators are analogous to the relational
>   operators except for their lower precedence.91) Each of the operators yields 1 if the
>   specified relation is true and 0 if it is false. The result has type int. For any pair of
>   operands, exactly one of the relations is true.
> 
> and in 6.5.10
> 
> 6 Two pointers compare equal if and only if both are null pointers, both are pointers to the
>   same object (including a pointer to an object and a subobject at its beginning) or function,
>   both are pointers to one past the last element of the same array object, or one is a pointer
>   to one past the end of one array object and the other is a pointer to the start of a different
>   array object that happens to immediately follow the first array object in the address
>   space.92)
> 
> So it would seem as if in the case that a pointer is compared to null,
> it will compare equal if the pointer is also null, or not equal in all
> other circumstances.
> 
> The comparison is useless in the case of an indeterminate pointer, of
> course, since an indeterminate pointer has a vanishingly small
> possibility of being null.  But I'm not seeing why it's undefined
> behavior.

The sections you are citing refer to the behavior of the comparison
operators. Before those operators can be applied to a pointer value,
that value must be read from the pointer object. Here's what the
standard says about that:

3.19.2:
indeterminate value
either an unspecified value or a trap representation

6.2.6.1p5:
Certain object representations need not represent a value of the object
type. If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type, the
behavior is undefined. ... Such a representation is called
a trap representation.

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


#89022

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2016-06-13 10:03 -0600
Message-ID<1b60tdqdna.fsf@pfeifferfamily.net>
In reply to#88997
James Kuyper <jameskuyper@verizon.net> writes:
<snip my stuff>

> The sections you are citing refer to the behavior of the comparison
> operators. Before those operators can be applied to a pointer value,
> that value must be read from the pointer object. Here's what the
> standard says about that:
>
> 3.19.2:
> indeterminate value
> either an unspecified value or a trap representation
>
> 6.2.6.1p5:
> Certain object representations need not represent a value of the object
> type. If the stored value of an object has such a representation and is
> read by an lvalue expression that does not have character type, the
> behavior is undefined. ... Such a representation is called
> a trap representation.

Ah, OK.  Loading a trap representation itself being undefined behavior
hadn't occurred to me.

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


#89215

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-06-15 14:43 -0700
Message-ID<kfnk2hq5dsd.fsf@x-alumni2.alumni.caltech.edu>
In reply to#89022
Joe Pfeiffer <pfeiffer@cs.nmsu.edu> writes:

> James Kuyper <jameskuyper@verizon.net> writes:
> <snip my stuff>
>
>> The sections you are citing refer to the behavior of the comparison
>> operators.  Before those operators can be applied to a pointer value,
>> that value must be read from the pointer object.  Here's what the
>> standard says about that:
>>
>> 3.19.2:
>> indeterminate value
>> either an unspecified value or a trap representation
>>
>> 6.2.6.1p5:
>> Certain object representations need not represent a value of the object
>> type.  If the stored value of an object has such a representation and is
>> read by an lvalue expression that does not have character type, the
>> behavior is undefined. ... Such a representation is called
>> a trap representation.
>
> Ah, OK.  Loading a trap representation itself being undefined behavior
> hadn't occurred to me.

A better way to think of this is that using an indeterminate
pointer value is undefined behavior, whenever it is used, no
matter where the value comes from.  The reasoning above isn't
exactly right:  a pointer value may be valid when it is read from
a pointer object, and even participate in defined operations, but
become indeterminate "in flight" at some later point, even before
it has been stored.  (Not typical, but possible.)  When a pointer
value becomes indeterminate, even if is just a value somewhere in
an expression being evaluated, any further use of that value
gives undefined behavior.

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


#89021

Fromsupercat@casperkitty.com
Date2016-06-13 08:06 -0700
Message-ID<61d20284-ac0d-432c-bb61-6d0cb54d3c37@googlegroups.com>
In reply to#88995
On Sunday, June 12, 2016 at 9:25:28 PM UTC-5, Joe Pfeiffer wrote:
> The comparison is useless in the case of an indeterminate pointer, of
> course, since an indeterminate pointer has a vanishingly small
> possibility of being null.  But I'm not seeing why it's undefined
> behavior.

The reason that it's undefined behavior is that some machines have hardware
traps which will fire if an attempt is made to load a pointer register with
an invalid pointer.  The authors of the Standard were willing to burden
implementations on such machines with a requirement that loading a null
pointer for purposes of equality comparison must not cause a trap, but were
not willing to impose such a burden for invalid pointers in general.  For
many years, the behavior could be regarded as defined on machines which did
not use such hardware.

More recently, however, it has become fashionable for compilers to use
places where the Standard imposes no requirements as opportunities to change
the meaning of surrounding code.  While something like:

    void adjust_size(size_t new_size)
    {
      void *temp = realloc(data_store, new_size);
      if (!temp) FATAL_ERROR("Couldn't resize");
      if (temp != data_store)
      {
        data_store = temp;
        recalculate_pointers();
      }
    }

used to be a helpful optimization in cases where a realloc would be
unlikely to move an object, and where code could handle the object-not-
moved case more efficiently than the object-moved case.  A hyper-modern
compiler, however, could recognize that reaching the second "if" with
temp not equal to "NULL" would invoke Undefined Behavior, and thus
replace the above code with:

    void adjust_size(size_t new_size)
    {
      realloc(data_store, new_size);
      FATAL_ERROR("Couldn't resize");
      if (data_store)
      {
        data_store = 0;
        recalculate_pointers();
      }
    }

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


#89259

FromRichard Damon <Richard@Damon-Family.org>
Date2016-06-16 08:27 -0400
Message-ID<%Ww8z.12636$C_1.1578@fx13.iad>
In reply to#89021
On 6/13/16 11:06 AM, supercat@casperkitty.com wrote:
> On Sunday, June 12, 2016 at 9:25:28 PM UTC-5, Joe Pfeiffer wrote:
>> The comparison is useless in the case of an indeterminate pointer, of
>> course, since an indeterminate pointer has a vanishingly small
>> possibility of being null.  But I'm not seeing why it's undefined
>> behavior.
>
> The reason that it's undefined behavior is that some machines have hardware
> traps which will fire if an attempt is made to load a pointer register with
> an invalid pointer.  The authors of the Standard were willing to burden
> implementations on such machines with a requirement that loading a null
> pointer for purposes of equality comparison must not cause a trap, but were
> not willing to impose such a burden for invalid pointers in general.  For
> many years, the behavior could be regarded as defined on machines which did
> not use such hardware.
>

Wrong, maybe by someone ignoring the Standard they could 'regard' the 
behavior as defined. Unless the implementation formally documents this 
behavior, the behavior is undefined (and if documented, the use of that 
behavior makes the implementation dependent). In many case as you 
describe, the undefined behavior is benign, but it is still undefined.

This is your common fallacy, something 'worked' a given way which you 
liked, so you assume that that result of undefined behavior must be th 
definition, and when it changes you blame the implementation for 
breaking a promise it never made. This attitude has caused more problems 
in the history of programming, resulting in the canonical faults like 
the assumption that int = 16 bits, int smaller than long, int = 32 bits, 
int equivalent to long, ints could hold pointers, longs could hold 
pointers, etc.

All of these were commonly held beliefs, and many programmers wrote 
code, erroneously, assuming them, only to have the code break on the 
next generation of machines.

If you want promises beyond what the standard provides, fine, document 
the language extensions you need and use implementations that are 
DOCUMENTED to provide those. Just realize that you now can only use 
implementation that are documented to provide those extensions.

You have repeatedly made this complaint, it used to work this way (never 
promised, but YOU ASS-U-ME it) and now it doesn't work on later 
implementations, so you blame the Standard and Implementation for not 
keeping a promise they never made.

The strangest part of the complaint, is that the implementations that 
you rail against actually do DOCUMENT ways to invoke them to have most 
of the things you want them to have, but you seem to refuse to use that. 
They also are specifically NOT 'Standards Compliant' in their default 
mode of execution, but have some non-compliant extensions to the 
language enabled by default, so you really NEED to read the 
documentation to properly use them.

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


#89263

Fromsupercat@casperkitty.com
Date2016-06-16 06:27 -0700
Message-ID<87d98c39-391b-4e2a-9060-1fa472edc879@googlegroups.com>
In reply to#89259
On Thursday, June 16, 2016 at 7:27:49 AM UTC-5, Richard Damon wrote:
> This is your common fallacy, something 'worked' a given way which you 
> liked, so you assume that that result of undefined behavior must be th 
> definition, and when it changes you blame the implementation for 
> breaking a promise it never made. This attitude has caused more problems 
> in the history of programming, resulting in the canonical faults like 
> the assumption that int = 16 bits, int smaller than long, int = 32 bits, 
> int equivalent to long, ints could hold pointers, longs could hold 
> pointers, etc.

> All of these were commonly held beliefs, and many programmers wrote 
> code, erroneously, assuming them, only to have the code break on the 
> next generation of machines.

If a simplistic compiler for a language for a particular platform, fed a
particular piece of source code X, will yield 100% reliable machine code
to perform that task with a certain degree of performance, then if the
language is any good there should be a piece of source code Y which is
can be guaranteed to yield those results without significant sacrifices
in performance or readability.

If one regards the C language as inheriting the traits of the platforms
upon which it runs, it's a good language.  If one does not, it's a
crummy language.

> If you want promises beyond what the standard provides, fine, document 
> the language extensions you need and use implementations that are 
> DOCUMENTED to provide those. Just realize that you now can only use 
> implementation that are documented to provide those extensions.

Many things which are undefined today were well-defined in C89.  Why should
a compiler have been expected to document that of struct "foo" has a field
"x" of type "int" at offset 12, and struct "bar" has a field with the same
name and offset, then casting to "foo" a pointer to either type and accessing
field "x" will access the same thing, given that

  1. That behavior was specified in C74
  2. No compilers since had deviated from it

With regard to two's-complement integers, they are mathematically
incapable of overflow in the same way as unsigned integers, since the
two's-complement integers of any given size form an abstract algebraic
ring which is isomorphic to the unsigned integers of the same size.

> The strangest part of the complaint, is that the implementations that 
> you rail against actually do DOCUMENT ways to invoke them to have most 
> of the things you want them to have, but you seem to refuse to use that. 
> They also are specifically NOT 'Standards Compliant' in their default 
> mode of execution, but have some non-compliant extensions to the 
> language enabled by default, so you really NEED to read the 
> documentation to properly use them.

I object in part to the notion that things were never defined, when in
fact programmers were merely expecting that traditional defined behaviors
would continue, at least until the better alternatives behave available.

I would also suggest that in many cases the level of optimization that
can be achieved by completely revoking the guarantees would be inferior to
the level that could be achieved by weakening them but not eliminating
them altogether.

Do you disagree with either point?

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


#89275

Fromsupercat@casperkitty.com
Date2016-06-16 07:31 -0700
Message-ID<d94e00a3-e3ad-475e-a94a-35f34a3aabbb@googlegroups.com>
In reply to#89263
On Thursday, June 16, 2016 at 8:27:22 AM UTC-5, supe...@casperkitty.com wrote:
> > The strangest part of the complaint, is that the implementations that 
> > you rail against actually do DOCUMENT ways to invoke them to have most 
> > of the things you want them to have, but you seem to refuse to use that. 
> > They also are specifically NOT 'Standards Compliant' in their default 
> > mode of execution, but have some non-compliant extensions to the 
> > language enabled by default, so you really NEED to read the 
> > documentation to properly use them.

A further objection is that a good language should make it practical to
write code which is highly unlikely to become undefined in any future
version of the language.  That could be accomplished by ensuring that
for every construct upon which the Standard imposes no requirements but
for which there is no practical alternative, an implementation describes
a version that will work "forever" along with a directive to indicate that
all uses of the old form have been replaced with the new form.  As it is,
though, there are a number of forms of UB that are required in many kinds
of practical programming which gcc doesn't yet "punish", but for which it
does not so far as I can tell provide a clean alternative either.  How can
one use gcc to write or work with code which requires such constructs and
have any confidence that a gcc maintainers won't break it in a future
version of gcc just because they can?

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


#89539

FromRichard Damon <Richard@Damon-Family.org>
Date2016-06-18 13:39 -0400
Message-ID<FHf9z.2464$HD2.31@fx37.iad>
In reply to#89263
On 6/16/16 9:27 AM, supercat@casperkitty.com wrote:
> On Thursday, June 16, 2016 at 7:27:49 AM UTC-5, Richard Damon wrote:
>> This is your common fallacy, something 'worked' a given way which you
>> liked, so you assume that that result of undefined behavior must be th
>> definition, and when it changes you blame the implementation for
>> breaking a promise it never made. This attitude has caused more problems
>> in the history of programming, resulting in the canonical faults like
>> the assumption that int = 16 bits, int smaller than long, int = 32 bits,
>> int equivalent to long, ints could hold pointers, longs could hold
>> pointers, etc.
>
>> All of these were commonly held beliefs, and many programmers wrote
>> code, erroneously, assuming them, only to have the code break on the
>> next generation of machines.
>
> If a simplistic compiler for a language for a particular platform, fed a
> particular piece of source code X, will yield 100% reliable machine code
> to perform that task with a certain degree of performance, then if the
> language is any good there should be a piece of source code Y which is
> can be guaranteed to yield those results without significant sacrifices
> in performance or readability.
>
> If one regards the C language as inheriting the traits of the platforms
> upon which it runs, it's a good language.  If one does not, it's a
> crummy language.
>

100% Reliable requires something to PROMISE that it will always work. 
The hardware documentation for the processor may make the promise that 
the given sequence of assembly instructions are 'Reliable', but unless 
you have something which PROMISES that a given Statement will generate a 
given assembly sequence (which the Standard doesn't, and in fact CAN'T) 
you are not 'Reliable', but just counting on happenstance.

>> If you want promises beyond what the standard provides, fine, document
>> the language extensions you need and use implementations that are
>> DOCUMENTED to provide those. Just realize that you now can only use
>> implementation that are documented to provide those extensions.
>
> Many things which are undefined today were well-defined in C89.  Why should
> a compiler have been expected to document that of struct "foo" has a field
> "x" of type "int" at offset 12, and struct "bar" has a field with the same
> name and offset, then casting to "foo" a pointer to either type and accessing
> field "x" will access the same thing, given that
>
>   1. That behavior was specified in C74
>   2. No compilers since had deviated from it
>
> With regard to two's-complement integers, they are mathematically
> incapable of overflow in the same way as unsigned integers, since the
> two's-complement integers of any given size form an abstract algebraic
> ring which is isomorphic to the unsigned integers of the same size.

I have worked on machines that for 16 bit two's complement numbers, 
32767+1 was NOT -32768, on one machine it was 32767 and on another it 
was a trap. The definition (that the standard uses) of signed numbers 
does NOT define them as a ring (like it does for unsigned)
>
>> The strangest part of the complaint, is that the implementations that
>> you rail against actually do DOCUMENT ways to invoke them to have most
>> of the things you want them to have, but you seem to refuse to use that.
>> They also are specifically NOT 'Standards Compliant' in their default
>> mode of execution, but have some non-compliant extensions to the
>> language enabled by default, so you really NEED to read the
>> documentation to properly use them.
>
> I object in part to the notion that things were never defined, when in
> fact programmers were merely expecting that traditional defined behaviors
> would continue, at least until the better alternatives behave available.

For something to be DEFINED, someone has to give a DEFINITION. Just 
because something has seemed to work, doesn't make it a law that it MUST 
work. History is full of people who assume that things that 'just seem 
to work' will continue to work to their detriment.

>
> I would also suggest that in many cases the level of optimization that
> can be achieved by completely revoking the guarantees would be inferior to
> the level that could be achieved by weakening them but not eliminating
> them altogether.
>
> Do you disagree with either point?
>

I don't know well enough what options are really available for 
optimization, as that is not my field of expertise. It does seem logical 
to me that making no promises about behavior in a situation should give 
the compiler more options than a partial promise, as anything that could 
be done with the latter, could also have been done in the former. Maybe 
in the strange cases you like to propose where you don't care about 
getting right answers, just limited undefined behavior, the partial 
promises might be useful. I will observe that the writers of the 
compilers seem to disagree with you, and think that the typical 
programmer wants the better optimizations and is willing to avoid 
undefined behavior to get it.

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


#89543

Fromsupercat@casperkitty.com
Date2016-06-18 11:37 -0700
Message-ID<3b8e8a97-10fb-49cd-9e9d-e7e20d1b0aac@googlegroups.com>
In reply to#89539
On Saturday, June 18, 2016 at 12:39:57 PM UTC-5, Richard Damon wrote:
> On 6/16/16 9:27 AM, supercat wrote:
> > If a simplistic compiler for a language for a particular platform, fed a
> > particular piece of source code X, will yield 100% reliable machine code
> > to perform that task with a certain degree of performance, then if the
> > language is any good there should be a piece of source code Y which is
> > can be guaranteed to yield those results without significant sacrifices
> > in performance or readability.
> >
> > If one regards the C language as inheriting the traits of the platforms
> > upon which it runs, it's a good language.  If one does not, it's a
> > crummy language.
> 
> 100% Reliable requires something to PROMISE that it will always work. 
> The hardware documentation for the processor may make the promise that 
> the given sequence of assembly instructions are 'Reliable', but unless 
> you have something which PROMISES that a given Statement will generate a 
> given assembly sequence (which the Standard doesn't, and in fact CAN'T) 
> you are not 'Reliable', but just counting on happenstance.

If a simplistic compiler would generate 100% reliable machine code to
perform a task, that would suggest that making a compiler capable of
generating such machine code should not be overly difficult (since even
a simplistic compiler can do it).  The simplistic compiler may be forgoing
other optimizations that could offer a 50% performance boost, but if by
so doing it enables a programmer to make a hot loop run four times as fast,
I'd suggest that time spent on those other optimizations is not well-
spent.

> > Many things which are undefined today were well-defined in C89.  Why should
> > a compiler have been expected to document that of struct "foo" has a field
> > "x" of type "int" at offset 12, and struct "bar" has a field with the same
> > name and offset, then casting to "foo" a pointer to either type and accessing
> > field "x" will access the same thing, given that
> >
> >   1. That behavior was specified in C74
> >   2. No compilers since had deviated from it
> >
> > With regard to two's-complement integers, they are mathematically
> > incapable of overflow in the same way as unsigned integers, since the
> > two's-complement integers of any given size form an abstract algebraic
> > ring which is isomorphic to the unsigned integers of the same size.
> 
> I have worked on machines that for 16 bit two's complement numbers, 
> 32767+1 was NOT -32768, on one machine it was 32767 and on another it 
> was a trap. The definition (that the standard uses) of signed numbers 
> does NOT define them as a ring (like it does for unsigned)

Did the hardware platforms and/or compilers document the behaviors in
question?  I would be rather surprised if they didn't.

If one is running code on a hardware platform which does not perform
signed arithmetic using an algebraic ring, then it would of course be
unreasonable to expect that math would behave in such a fashion.  How
many twentieth-century implementations do you know of where:

1. The underlying hardware performed wrapping two's-complement math.

2. The compiler's generated code would not always generate values whose
   lower bits matched the arithmetically-correct ones (with the caveat
   that temporary values may sometimes hold "extra" precision, so the
   value might not be truncated to the range of the type)?

3. No deviations from the wrapping two's-complement math behaviors were
   noted in the compiler documentation?

I've certainly seen plenty of compilers which document ways in which math
might deviate from silent-wraparound behavior (though for compilers of that
era even the possibility that temporary values could exceed the range of
"int" would have been regarded as an oddity worth noting).  Is there any
evidence that it would have been considered "acceptable" for compilers of
that era that targeted silent-wraparound hardware to implement contrary
semantics without documenting it?

Why do you suppose the authors of the C Standard would have considered
the fact that the majority of then-current implementations treated signed
math as an algebraic ring except cases where the result was used in a way
where upper bits would matter, if they didn't feel that implementations
made any promise in that regard?

> > I object in part to the notion that things were never defined, when in
> > fact programmers were merely expecting that traditional defined behaviors
> > would continue, at least until the better alternatives behave available.
> 
> For something to be DEFINED, someone has to give a DEFINITION. Just 
> because something has seemed to work, doesn't make it a law that it MUST 
> work. History is full of people who assume that things that 'just seem 
> to work' will continue to work to their detriment.

In C74, given:

   struct s1 { int x,y; float z; ];
   struct s1 *p1 = ...;

the meaning of p1->y was defined as being equivalent to

    (int*)( [[offset of y]] + (char*)p1)

Would a guarantee of such behavior in compilers implementing subsequent
dialects of C have been regarded as an "extension", or merely a
continuation of established behavioral practice?

> > I would also suggest that in many cases the level of optimization that
> > can be achieved by completely revoking the guarantees would be inferior to
> > the level that could be achieved by weakening them but not eliminating
> > them altogether.
> >
> > Do you disagree with either point?
> >
> 
> I don't know well enough what options are really available for 
> optimization, as that is not my field of expertise. It does seem logical 
> to me that making no promises about behavior in a situation should give 
> the compiler more options than a partial promise, as anything that could 
> be done with the latter, could also have been done in the former. Maybe 
> in the strange cases you like to propose where you don't care about 
> getting right answers, just limited undefined behavior, the partial 
> promises might be useful. I will observe that the writers of the 
> compilers seem to disagree with you, and think that the typical 
> programmer wants the better optimizations and is willing to avoid 
> undefined behavior to get it.

A lot of people have historically been willing to tolerate applications
which core-dump when given invalid data, and such people would probably
have said that they don't care what a program does when given invalid data
because they would expect that memory protections would ensure that the
program will do nothing worse than producing bad data or dumping core.
Do you think such people would be happy if the program e.g. randomly
changed a few bytes here and there on disk?  The only reason people don't
think they care what a program does when given invalid input is that they
assume its behavior will stay within some bounds.  I suspect the number of
people who would be willing to tolerate a program which would have truly
disastrous consequences if fed invalid input is actually quite low.  Would
you disagree?

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


#89570

FromRichard Damon <Richard@Damon-Family.org>
Date2016-06-18 17:17 -0400
Message-ID<oTi9z.5960$9s2.3340@fx41.iad>
In reply to#89543
On 6/18/16 2:37 PM, supercat@casperkitty.com wrote:
> On Saturday, June 18, 2016 at 12:39:57 PM UTC-5, Richard Damon wrote:
>> On 6/16/16 9:27 AM, supercat wrote:
>>> If a simplistic compiler for a language for a particular platform, fed a
>>> particular piece of source code X, will yield 100% reliable machine code
>>> to perform that task with a certain degree of performance, then if the
>>> language is any good there should be a piece of source code Y which is
>>> can be guaranteed to yield those results without significant sacrifices
>>> in performance or readability.
>>>
>>> If one regards the C language as inheriting the traits of the platforms
>>> upon which it runs, it's a good language.  If one does not, it's a
>>> crummy language.
>>
>> 100% Reliable requires something to PROMISE that it will always work.
>> The hardware documentation for the processor may make the promise that
>> the given sequence of assembly instructions are 'Reliable', but unless
>> you have something which PROMISES that a given Statement will generate a
>> given assembly sequence (which the Standard doesn't, and in fact CAN'T)
>> you are not 'Reliable', but just counting on happenstance.
>
> If a simplistic compiler would generate 100% reliable machine code to
> perform a task, that would suggest that making a compiler capable of
> generating such machine code should not be overly difficult (since even
> a simplistic compiler can do it).  The simplistic compiler may be forgoing
> other optimizations that could offer a 50% performance boost, but if by
> so doing it enables a programmer to make a hot loop run four times as fast,
> I'd suggest that time spent on those other optimizations is not well-
> spent.
>

Your case shows that it is possible FOR THAT MACHINE to generate such 
code. And the Standard does not prohibit an implementation from do so. 
What the Standard does not do, that you want to insist, is that the 
implementation MUST do so. The issue is that on some machine (now more 
rare than before) it is very expensive to do so. The Standards Committee 
long ago had a decision to make, do we define the C language to be 
usable on a wide assortment of machines, and not mandate highest level 
of promises on them, (leaving this possible to a more restricted 
standard, somewhat lie POSIX) or defining the language in a more 
restricted manner for only a more limited range of machines. The 
committee took the lead from the original authors of the language to 
keep the definition broad.

There is NOTHING in the Standard to prohibit an implementation for 
making such a promise, and I would imagine that if there was enough 
demand, it would be present. In fact, since GCC is open source, and you 
seem such an expert on how to optimize code, why don't YOU develop an 
option for GCC to provide it.


>>> Many things which are undefined today were well-defined in C89.  Why should
>>> a compiler have been expected to document that of struct "foo" has a field
>>> "x" of type "int" at offset 12, and struct "bar" has a field with the same
>>> name and offset, then casting to "foo" a pointer to either type and accessing
>>> field "x" will access the same thing, given that
>>>
>>>   1. That behavior was specified in C74
>>>   2. No compilers since had deviated from it
>>>
>>> With regard to two's-complement integers, they are mathematically
>>> incapable of overflow in the same way as unsigned integers, since the
>>> two's-complement integers of any given size form an abstract algebraic
>>> ring which is isomorphic to the unsigned integers of the same size.
>>
>> I have worked on machines that for 16 bit two's complement numbers,
>> 32767+1 was NOT -32768, on one machine it was 32767 and on another it
>> was a trap. The definition (that the standard uses) of signed numbers
>> does NOT define them as a ring (like it does for unsigned)
>
> Did the hardware platforms and/or compilers document the behaviors in
> question?  I would be rather surprised if they didn't.

Yes they did. But their existence is a disproof of your assertion.
>
> If one is running code on a hardware platform which does not perform
> signed arithmetic using an algebraic ring, then it would of course be
> unreasonable to expect that math would behave in such a fashion.  How
> many twentieth-century implementations do you know of where:
>
> 1. The underlying hardware performed wrapping two's-complement math.
>
> 2. The compiler's generated code would not always generate values whose
>    lower bits matched the arithmetically-correct ones (with the caveat
>    that temporary values may sometimes hold "extra" precision, so the
>    value might not be truncated to the range of the type)?
>
> 3. No deviations from the wrapping two's-complement math behaviors were
>    noted in the compiler documentation?
>
> I've certainly seen plenty of compilers which document ways in which math
> might deviate from silent-wraparound behavior (though for compilers of that
> era even the possibility that temporary values could exceed the range of
> "int" would have been regarded as an oddity worth noting).  Is there any
> evidence that it would have been considered "acceptable" for compilers of
> that era that targeted silent-wraparound hardware to implement contrary
> semantics without documenting it?
>
> Why do you suppose the authors of the C Standard would have considered
> the fact that the majority of then-current implementations treated signed
> math as an algebraic ring except cases where the result was used in a way
> where upper bits would matter, if they didn't feel that implementations
> made any promise in that regard?

The C Standard did NOT base promises on 'majority', but on what could be 
reasonably expected to be achievable on all practical machines. Thus 
(unless C11 changed this) it doesn't even require 2s complement to be 
used. It does provide some types (which are optional) that, if present, 
are 2s complement, but even with these, EXPLICITLY defines 2s complement 
as undefined behavior, so don't mandate the ring behavior.

The standard has no words that require an implementation to behave more 
definitely just because the hardware has some desirable behavior (and 
also doesn't prohibit it from making additional promises based on the 
hardware).

>
>>> I object in part to the notion that things were never defined, when in
>>> fact programmers were merely expecting that traditional defined behaviors
>>> would continue, at least until the better alternatives behave available.
>>
>> For something to be DEFINED, someone has to give a DEFINITION. Just
>> because something has seemed to work, doesn't make it a law that it MUST
>> work. History is full of people who assume that things that 'just seem
>> to work' will continue to work to their detriment.
>
> In C74, given:
>
>    struct s1 { int x,y; float z; ];
>    struct s1 *p1 = ...;
>
> the meaning of p1->y was defined as being equivalent to
>
>     (int*)( [[offset of y]] + (char*)p1)
>
> Would a guarantee of such behavior in compilers implementing subsequent
> dialects of C have been regarded as an "extension", or merely a
> continuation of established behavioral practice?

C74 was obsoleted, and as I remember only really defined for a 
particular machine. K&R changed many things including this, 
INTENTIONALLY. If you want to write in C74, go ahead an find a copy of 
it and us it, good luck finding a machine to run it. For STANDARDS, 
C89/C90 is the first version, which was largely based on K&R C which was 
NOT standardized as there were multiple (incompatible) dialects derived 
from K&R, which was one of the motivations to develop a standard.
>
>>> I would also suggest that in many cases the level of optimization that
>>> can be achieved by completely revoking the guarantees would be inferior to
>>> the level that could be achieved by weakening them but not eliminating
>>> them altogether.
>>>
>>> Do you disagree with either point?
>>>
>>
>> I don't know well enough what options are really available for
>> optimization, as that is not my field of expertise. It does seem logical
>> to me that making no promises about behavior in a situation should give
>> the compiler more options than a partial promise, as anything that could
>> be done with the latter, could also have been done in the former. Maybe
>> in the strange cases you like to propose where you don't care about
>> getting right answers, just limited undefined behavior, the partial
>> promises might be useful. I will observe that the writers of the
>> compilers seem to disagree with you, and think that the typical
>> programmer wants the better optimizations and is willing to avoid
>> undefined behavior to get it.
>
> A lot of people have historically been willing to tolerate applications
> which core-dump when given invalid data, and such people would probably
> have said that they don't care what a program does when given invalid data
> because they would expect that memory protections would ensure that the
> program will do nothing worse than producing bad data or dumping core.
> Do you think such people would be happy if the program e.g. randomly
> changed a few bytes here and there on disk?  The only reason people don't
> think they care what a program does when given invalid input is that they
> assume its behavior will stay within some bounds.  I suspect the number of
> people who would be willing to tolerate a program which would have truly
> disastrous consequences if fed invalid input is actually quite low.  Would
> you disagree?
>
>

The only real form of security is to stop someone from doing something 
wrong before they do it, not to minimize the damage they can do. If you 
avoid letting Undefined Behavior from happening, then you have promises 
from the Standard on what you program will do. If you don't get a 
promise you want from the Standard, you can possible get a promise from 
some additional standard or documented by the implementation, then you 
can trust in those promises but you then are dependent on more than the 
standard (which is ok if you know it). A lot of programs have been 
written that do undefined behavior, and the programmer figured the 
results were benign and left it, and THAT causes security issues. You 
shouldn't blame the make of the tools if the user hasn't been using it 
right.

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


#89582

Fromsupercat@casperkitty.com
Date2016-06-18 17:22 -0700
Message-ID<acc944b7-220a-4fa0-9fe7-597dd3550e61@googlegroups.com>
In reply to#89570
On Saturday, June 18, 2016 at 4:17:16 PM UTC-5, Richard Damon wrote:
> Your case shows that it is possible FOR THAT MACHINE to generate such 
> code. And the Standard does not prohibit an implementation from do so. 
> What the Standard does not do, that you want to insist, is that the 
> implementation MUST do so. The issue is that on some machine (now more 
> rare than before) it is very expensive to do so. The Standards Committee 
> long ago had a decision to make, do we define the C language to be 
> usable on a wide assortment of machines, and not mandate highest level 
> of promises on them, (leaving this possible to a more restricted 
> standard, somewhat lie POSIX) or defining the language in a more 
> restricted manner for only a more limited range of machines. The 
> committee took the lead from the original authors of the language to 
> keep the definition broad.

The notion that the world only needed two kinds of C implementations
(freestanding and embedded) is one of the most preposterous notions ever.
What was and is needed is a collection of dialects, which have some
unifying features, so that code which won't benefit from architectural
guarantees that are only available on 99% of machines will be able to run
on 100% of machines, including the 1% that can't offer the guarantee, but
code whose performance would be improved by using such features can do so
at the expense of reduced compatibility.

> There is NOTHING in the Standard to prohibit an implementation for 
> making such a promise, and I would imagine that if there was enough 
> demand, it would be present. In fact, since GCC is open source, and you 
> seem such an expert on how to optimize code, why don't YOU develop an 
> option for GCC to provide it.

Compilers that mirrored the underlying hardware very closely used to be
the norm, and those that deviated were careful to note such deviation.  If
a programmer noted that a platform's hardware worked a certain way and the
compiler writer didn't document the compiler as doing anything different,
the fact that the code worked was not "happenstance".

I don't think the different parts of gcc of different vintages would be
compatible with each other, or else I'd pair a somewhat older optimization
engine with a code generator for the ARM Cortex-m0 and m3 series (which I
don't think were supported when some of the optimizations started getting
too aggressive).

> > Did the hardware platforms and/or compilers document the behaviors in
> > question?  I would be rather surprised if they didn't.
> 
> Yes they did. But their existence is a disproof of your assertion.

My assertion is that those two's-complement implementations which didn't
document contrary behavior would generate a result whose lower bits were
correct, without side-effects (I wouldn't expect that implementations which
don't always truncate the result to the size of the operands would document
that behavior, but would not be terribly surprised if there were some for
platforms where some operations work with values longer than "int" would
sometimes keep extra precision without documenting it).

> > If one is running code on a hardware platform which does not perform
> > signed arithmetic using an algebraic ring, then it would of course be
> > unreasonable to expect that math would behave in such a fashion.  How
> > many twentieth-century implementations do you know of where:
> >
> > 1. The underlying hardware performed wrapping two's-complement math.
> >
> > 2. The compiler's generated code would not always generate values whose
> >    lower bits matched the arithmetically-correct ones (with the caveat
> >    that temporary values may sometimes hold "extra" precision, so the
> >    value might not be truncated to the range of the type)?
> >
> > 3. No deviations from the wrapping two's-complement math behaviors were
> >    noted in the compiler documentation?
> >
> I've certainly seen plenty of compilers which document ways in which math
> might deviate from silent-wraparound behavior (though for compilers of that
> era even the possibility that temporary values could exceed the range of
> "int" would have been regarded as an oddity worth noting).  Is there any
> evidence that it would have been considered "acceptable" for compilers of
> that era that targeted silent-wraparound hardware to implement contrary
> semantics without documenting it?

Sure.  Evidence of code getting broken when fed to implementations which
met the aforementioned description.  If any significant number of such
implementations existed, that should have happened fairly often, and some
evidence of it should exist.

> > Why do you suppose the authors of the C Standard would have considered
> > the fact that the majority of then-current implementations treated signed
> > math as an algebraic ring except cases where the result was used in a way
> > where upper bits would matter, if they didn't feel that implementations
> > made any promise in that regard?
> 
> The C Standard did NOT base promises on 'majority', but on what could be 
> reasonably expected to be achievable on all practical machines. Thus 
> (unless C11 changed this) it doesn't even require 2s complement to be 
> used. It does provide some types (which are optional) that, if present, 
> are 2s complement, but even with these, EXPLICITLY defines 2s complement 
> as undefined behavior, so don't mandate the ring behavior.

The C89 rationale observes that on two's-complement silent-wraparound
implementations, i.e. the majority of then-current implementations, the
behavior of most operators is identical when given signed and unsigned
operands is identical except when BOTH of the following conditions apply:

  1. The MSB of the result is set.

  2. The result is promoted to a longer type, used as the left operand
     of >>, or as either operand of %, /, or any comparison operator.

Why do you suppose the authors of the rationale would have mentioned the
second condition, if they didn't believe that the implementations in
question defined behavior in cases where the first condition applied but
the second one did not?

I can see how such an observation would have been relevant if the authors
of the Standard expected that the observation would hold true of future
implementations, but can't see why they would have thought it relevant
otherwise.  Can you offer any other suggestion?

> The standard has no words that require an implementation to behave more 
> definitely just because the hardware has some desirable behavior (and 
> also doesn't prohibit it from making additional promises based on the 
> hardware).

That is true.  It also has no words which imply that it describes
everything that is required for an implementation to be good and useful
for all of the purposes to which the language might be put.

> C74 was obsoleted, and as I remember only really defined for a 
> particular machine. K&R changed many things including this, 
> INTENTIONALLY. If you want to write in C74, go ahead an find a copy of 
> it and us it, good luck finding a machine to run it. For STANDARDS, 
> C89/C90 is the first version, which was largely based on K&R C which was 
> NOT standardized as there were multiple (incompatible) dialects derived 
> from K&R, which was one of the motivations to develop a standard.

C compilers existed prior to C89, which made provisions to allow for
architectures that would not have been practical with C74 (I'm not sure
which concessions were made by which intervening language documents,
though don't think all originated with C89).  In C74, there was a well-
defined relationship between integers and pointers.  Some hardware
platforms could not practically support such a relationship, and
loosening the rules meant that code which did not rely upon such a
relationship could run on hardware which didn't support it.  On the
other hand, I don't think the notion that pre-existing code which relied
upon such a relationship before the guarantee was waived shouldn't work
the same way *on hardware platforms where the relationship holds*.

> > A lot of people have historically been willing to tolerate applications
> > which core-dump when given invalid data, and such people would probably
> > have said that they don't care what a program does when given invalid data
> > because they would expect that memory protections would ensure that the
> > program will do nothing worse than producing bad data or dumping core.
> > Do you think such people would be happy if the program e.g. randomly
> > changed a few bytes here and there on disk?  The only reason people don't
> > think they care what a program does when given invalid input is that they
> > assume its behavior will stay within some bounds.  I suspect the number of
> > people who would be willing to tolerate a program which would have truly
> > disastrous consequences if fed invalid input is actually quite low.  Would
> > you disagree?
> 
> The only real form of security is to stop someone from doing something 
> wrong before they do it, not to minimize the damage they can do. If you 
> avoid letting Undefined Behavior from happening, then you have promises 
> from the Standard on what you program will do. If you don't get a 
> promise you want from the Standard, you can possible get a promise from 
> some additional standard or documented by the implementation, then you 
> can trust in those promises but you then are dependent on more than the 
> standard (which is ok if you know it). A lot of programs have been 
> written that do undefined behavior, and the programmer figured the 
> results were benign and left it, and THAT causes security issues. You 
> shouldn't blame the make of the tools if the user hasn't been using it 
> right.

In many cases, DEFINING constraints on otherwise-undefined behaviors would
reduce the amount of both source and machine code required to limit the
consequences of a program receiving invalid input.  If a video player
receives a corrupt batch of data, how important is it that it display
some particular exact combination of pixels?  How important is it that
it not allow the creator of that corrupt batch of data to take over the
machine?  I would suggest that a good language should make it easy for a
programmer to achieve the second without requiring the CPU to waste time
on the first.

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


#89026

FromJames Kuyper <jameskuyper@verizon.net>
Date2016-06-13 14:10 -0400
Message-ID<njmsv5$tsr$1@dont-email.me>
In reply to#88995
On 06/12/2016 10:25 PM, Joe Pfeiffer wrote:
...
> In the C99 standard (note -- I've actually only got a committee draft
> from 2005, and don't know what differences the final standard might
> have) I find in 6.5.9

If you're interested in C99, the best source to use is n1256.pdf. It
contains the final C99 standard, plus the modifications that were
approved as Technical Corrigenda 1, 2, and 3. While those modifications
were officially approved, the version of the standard with those
modifications carried out never has been. Despite the lack of approval,
it is more useful than the official standard because it includes those
modifications.

At the top of every page of n1256 except the first, it says "Septermber
7, 2007", and as of 2009-09-21, according to Lawrence Jones (the C
committee's secretary), the only  defects in n1256.pdf that had been
reported between those two dates have been:

1) The typo in "Septermber 7, 2007".

2) "the predefined macro __STDC_MB_MIGHT_NEQ_WC__ should appear in
6.10.8p2 (optional predefined macros) rather than p1 (required
predefined macros)."


Personally, I tend to pay more attention to n1570.pdf, a draft which is
almost identical to the final C2011 standard. The only known defect it
contains is that in two locations, it claims that _Alignof() can be
applied to an expression, just like sizeof. In the final approved
standard, it can only be applied to a type.

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


#89029

FromKeith Thompson <kst-u@mib.org>
Date2016-06-13 11:28 -0700
Message-ID<lna8ip3pv3.fsf@kst-u.example.com>
In reply to#89026
James Kuyper <jameskuyper@verizon.net> writes:
[...]
> Personally, I tend to pay more attention to n1570.pdf, a draft which is
> almost identical to the final C2011 standard. The only known defect it
> contains is that in two locations, it claims that _Alignof() can be
> applied to an expression, just like sizeof. In the final approved
> standard, it can only be applied to a type.

That's not *quite* an accurate description of the defect.  The
grammar in 6.5.3 clearly indicates _Alignof, unlike sizeof, cannot
be applied to an expression.  (I've never seen an explanation for
this restriction.)  The defect is that 6.3.2.1p3 lists the operand
of _Alignof as one of the contexts where an array expression is
not converted to a pointer.  That was corrected in the published
C11 standard.

Another defect in N1570 is that the definitions of __STD_VERSION__
and __STDC_LIB_EXT1__ are incorrect (both are shown as `201ymmL`,
with the "ymm" in italics).  This error also appears in the published
C11 standard, but it was corrected in the first (and so far only)
Technical Corrigendum (both are now `201112L`).

-- 
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]


#89031

FromJoe Pfeiffer <pfeiffer@cs.nmsu.edu>
Date2016-06-13 12:31 -0600
Message-ID<1b1t41q6sq.fsf@pfeifferfamily.net>
In reply to#89026
James Kuyper <jameskuyper@verizon.net> writes:


> On 06/12/2016 10:25 PM, Joe Pfeiffer wrote:
> ...
>> In the C99 standard (note -- I've actually only got a committee draft
>> from 2005, and don't know what differences the final standard might
>> have) I find in 6.5.9
>
> If you're interested in C99, the best source to use is n1256.pdf. It
> contains the final C99 standard, plus the modifications that were
> approved as Technical Corrigenda 1, 2, and 3. While those modifications
> were officially approved, the version of the standard with those
> modifications carried out never has been. Despite the lack of approval,
> it is more useful than the official standard because it includes those
> modifications.

Just got it -- thanks.

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


#88996

FromKeith Thompson <kst-u@mib.org>
Date2016-06-12 19:38 -0700
Message-ID<lntwgx4xux.fsf@kst-u.example.com>
In reply to#88992
Richard Heathfield <rjh@cpax.org.uk> writes:
> On 13/06/16 00:21, G G wrote:
>> when should a pointer to set to NULL and test whether
>> it is NULL?
>
> That's an excellent question.
>
> A pointer can be in any of three states:
>
> (1) a null pointer;
> (2) a valid pointer to an existing object or function;

(2a) a valid pointer just past the end of an array object.  (A non-array
object is treated as an array of length 1.)

> (3) indeterminate.

[...]

-- 
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]


#88998

FromRichard Heathfield <rjh@cpax.org.uk>
Date2016-06-13 07:35 +0100
Message-ID<njlk7u$v7m$1@dont-email.me>
In reply to#88996
On 13/06/16 03:38, Keith Thompson wrote:
> Richard Heathfield <rjh@cpax.org.uk> writes:
>> On 13/06/16 00:21, G G wrote:
>>> when should a pointer to set to NULL and test whether
>>> it is NULL?
>>
>> That's an excellent question.
>>
>> A pointer can be in any of three states:
>>
>> (1) a null pointer;
>> (2) a valid pointer to an existing object or function;
>
> (2a) a valid pointer just past the end of an array object.  (A non-array
> object is treated as an array of length 1.)
>
>> (3) indeterminate.
>
> [...]

Thank you for the correction. Our *four* main weapons are...

-- 
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within

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


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

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


csiph-web