Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sun, 13 Jan 2013 08:29:20 -0600
From: Rob Landley <rob@...dley.net>
To: musl@...ts.openwall.com
Subject: Re: NULL

On 01/12/2013 07:31:14 AM, Rich Felker wrote:
> On Sat, Jan 12, 2013 at 12:56:08AM -0600, Rob Landley wrote:
> > >The original reason I left NULL with pointer type was to catch the
> > >other idiotic error:
> > >
> > >    str[len]=NULL;
> > >
> > >i.e. confusion of NULL with ASCII NUL.
> >
> > They're both 0. If the optimizer can't convert the type down when
> > handed a constant assignment, the optimizer should be shot.
> 
> No. ASCII nul is an integer 0. NULL is a null pointer constant, which
> may be an integer constant expression 0 or may be (void *)0.

Ah right, possible warning. (Behavior's guaranteed correct in this  
instance, but the compiler complains anyway.)

> > >However, this raises a good
> > >question: short of C11 _Generic, is it even possible for a program  
> to
> > >detect whether NULL has integer or pointer type?
> >
> > The C99 standard says that NULL has pointer type. Thus when you pass
> 
> No it does not. We have addressed this multiple times already.

You read the standard as saying a pointer constant does not need  
pointer type. *shrug* Ok...

> > it in varargs, it should be a long on any LP64 system which is
> > basically "everything but windows" for about 20 years now.
> 
> Actually the type doesn't matter to correct programs. The question is
> whether we want to coddle incorrect programs, and the answer folks
> seem to be leaning towards is yes, in which case 0L would be the right
> definition to accomplish this.

I read "incorrect programs" and "c++ programs" as synonymous, but I'm  
biased.

> > >I know of one way, but it's very obscure:
> >
> > You can do sizeof(NULL) and (char *)(NULL+1)-(char *)(NULL) to get
> > the size of the type it points to?
> 
> NULL+1 is a constraint violation if NULL has pointer type (since the
> only pointer type it's permitted to have is void *).

Compile time probe to set a constant with 0 for void? (I've lost track  
of the entrance to the rathole: why do we need this info?)

So it's not required to be a pointer, but it's required to be a void  
pointer. Weird. (I'm something like 3 years stale on any sort of deep  
reading of the standards.)

> > Not sure what question you're asking...
> >
> > >int null_is_ptr_type()
> > >{
> > >	char s[1][1+(int)NULL];
> > >	int i = 0;
> > >	return sizeof s[i++], i;
> > >}
> >
> > (int)NULL is 0 according to C99 so the NULL in there has no effect.
> 
> It does. (int)0 is an integer constant expression. (int)(void *)0
> happens to be semantically constant, but it's not an integer constant
> expression. Therefore, depending on the definition of NULL, s may be a
> regular array type or a variable-length array type. In the latter
> case, s[i++] has VLA type and thus sizeof is required to evaluate its
> argument. GCC versions prior to 4.5 were buggy in this regard.

Really?

Toybox main.c is doing:

   #define NEWTOY(name, opts, flags) opts ||
   #define OLDTOY(name, oldname, opts, flags) opts ||
   static const int NEED_OPTIONS =
   #include "generated/newtoys.h"
   0;  // Ends the opts || opts || opts...

Which basically boils down to either:

   NEED_OPTIONS = "STRING" || NULL || "STRING";

Or:

   NEED_OPTIONS = NULL || NULL || NULL;

Then it does:

   if (NEED_OPTIONS) call_option_parsing_stuff();

And then dead code elimination zaps the option parsing stuff if it's  
only ever called behind and if (0). I tested this to make sure it  
worked. Years ago I actually upgraded tinycc to make that behave the  
same way gcc behaved so it could build this. (Yes, I could make it a  
compile probe setting a config symbol before the main build, but I  
didn't _need_ to.)

So I think you're saying is that the behavior I'm depending on changed?

Sigh. Yup. When I build toybox with just "true", gcc 4.2.1 (last gpl  
release) drops out parse_optflag() but the ubuntu host toolchain no  
longer does.

So A) your test is unreliable, B) the optimization I'm depending on is  
unreliable. And it's unreliable _even_ if I replace "NULL" with 0 so it  
_is_ clearly saying if (0) as a constant? What the...?

Hang on, I'm initializing this as a global so that it will FAIL if it's  
not a constant. (And it still doesn't fail. What's failed is dead code  
elimination in current gcc is no longer removing functions that can  
never be accessed, so I have to go figure out what the right compiler  
flags are called this week. SIGH.)

So fond of gcc. The LFS guys are currently discussing the 4.7.2 release  
or whatever it is that just came out and requires a C++ compiler on the  
host. (I'd link to the archives but their website is half-migrated  
right now.)

> > And referring to "i++" and "i" in the same statement is explicitly
> > undefined behavior (comma is not a sequence point, the compiler is
> 
> Comma is a sequence point.
> 
> > free to evaluate those in any order and different optimization flags
> > _will_ change that order; I got bit by that many moons ago).
> 
> No, you were doing something else wrong. To my knowledge there has
> never been a compiler that did not honor the comma operator sequence
> point, certainly not any GCC or clang.

I went and looked it up again: the comma operator and the commas in  
function arguments are not the same thing. (They _used_ to be, but bad  
optimizers broke it often enough the standards body caved.) Commas in  
function calls are not sequence points (c99 3.19), commas outside of  
function calls are. Wheee...

> Rich

Rob

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.