Re: fun with ?:

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Al Viro wrote:
> On Tue, May 22, 2007 at 04:24:49PM -0700, Josh Triplett wrote:
>> Makes sense, except that in C you can assign a void pointer to an arbitrary *
>> without a warning, so why can't conditional expressions do the equivalent?
> 
> {in sparse it's obviously not true due to address_space, but that hadn't
> affected C standard decisions; the rest applies to standard C}
> 
> For one thing, no, you can't (pointers to functions have every right to
> be unrelated to void *).  For another, you are not guaranteed that
> conversion from void * to int * will not yield undefined behaviour.
> It is OK if the value of void * is properly aligned; then you know
> that conversion back to void * will give the original pointer.  Otherwise
> you are in nasal demon country.  The other way round (int * to void *
> to int *) you are always safe.
> 
> Rationale: systems that have pointers to words and char smaller than word.
> There you can very well have pointers to void and pointers to less-than-word
> objects bigger than pointers to anything word-sized or bigger (e.g. they
> can be represented as word address + bit offset).  Conversion to the latter
> will lose offset and compiler is allowed to throw up on that at runtime.

Go Cray go.

> Moral: void * -> int * may lose parts of value and trigger undefined behaviour;
> int * -> void * loses information about type, is always revertible and always
> safe.  In assignment operator it's your responsibility to make sure that
> void * you are converting to int * is properly aligned (anything that started
> its life as int * will be).  In ?: C could
> 	* lose type information, allowing any values (result is void *); if
> you are sure that it's well-aligned, you can cast void * argument to int *
> or cast the result.
> 	* require the void * argument to be well-aligned, keep the type.
> 
> The former makes more sense...

Fair enough.

>>> Again, null pointer constant is not the same thing as null pointer to void.
>> I see.  I find it very strange that (void *)0 and (void *)(void *)0 have
>> different behavior.  I also find it strange that conditional expressions can't
>> convert void * to an arbitrary pointer as assignment can.
> 
> It would be nicer if C had __null__ as the *only* null pointer constant
> (with flexible type) and could refuse to accept anything else.  Too late
> for that, unfortunately.  As for conversions - see above.

Agreed; that seems far saner.  (Or, as long as we wishfully redefine the
original C spec, just NULL or null, sans underscores.)

>>> BTW, there's another painful area: what do we do to somebody who uses
>>> (void *)(69 + 1 - 70) as null pointer constant?  Currenly sparse doesn't
>>> recognize it as such; C standard does.  IMO the right thing to do is
>>> to add a flag that would switch to full-blown standard rules in that area
>>> ("integer constant expression returning 0" instead of basically "0 in some
>>> layers of ()") and flame to the crisp any wanker caught at actually doing
>>> that.  Any suggestions re sufficiently violent warning messages?
>> I didn't know that the C standard actually *required* constant folding.
>> Interesting.  Would it add excessively to compilation time to apply the usual
>> Sparse constant folding here?  If so, and if you really think this case
>> matters, let's have an option to turn on this constant folding, and warn
>> whenever we see it.
> 
> Usual sparse constant folding is _almost_ OK, provided that we play a bit
> with evaluate_expression() and let it decide if subexpression is an integer
> constant expression.  No prototype changes, we just get a global flag
> and save/restore it around sizeof argument handling and several other
> places.  It's actually pretty easy.  And if we get "it is an integer
> constant expression", well, then caller can call expand stuff.

Sounds reasonable to me.  Possibly better written as some kind of generic
parse-tree-walking operation, but this approach should work fine.

> "Almost" bit above refers to another bit of insanity, fortunately easily
> handled; we need division by zero to raise no error and just yield "the
> entire thing is not an integer constant expression with value 0".  That's
> exactly what longjmp() is for...

$ egrep -r 'setjmp|longjmp' ~/src/sparse/*
$

Let's keep it that way, please. :) Evaluation almost certainly should warn for
a compile-time divide-by-zero regardless, though we don't want to warn twice
for the same expression.  With the global "check for integer constant
expression" flag set, if evaluation encounters a compile-time divide-by-zero,
evaluation could just set a divided_by_zero flag.  Or something like that.

> Speaking of C standard, if you need access to the current one - yell.

I use http://c0x.coding-guidelines.com/ , which has the C99 spec and some
subsequent updates.

- Josh Triplett


Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux