This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: pointer <-> integer conversion warnings (bogus -Wall warnings)




	Dautrevaux@microprocess.com

	just try to use a ix86 (x >= 3) in segmented mode: pointers
	are 48 bits (segment + offset) while both size_t and ptrdiff_t
	(that were not proposed but could have been) are 32 bits as no
	object can be bigger than a 4Gb segment.

Sure.  Similarly, I was thinking of future systems with a huge address
space, a smaller per-process address space, and virtual memory
hardware that would be slightly exotic by today's common expectations.

	 However for such a system I don't think "x = (int)p" could
	 have ANY useful meaning which will NOT loss some importabnt
	 daat needed to be able to successfully do "p = (void*)x"
	 later

Let's suppose that the value being converted back and forth between
the two variables is not an address, but a range-limited integer.
My understanding is that:

	1. The standards do not _guarantee_ that the round trip
	   conversion from such an integer to pointer to integer
	   gives the same integer (unless the integer is 0).  In an
	   absolute sense, you're right that it's not portable.

	2. One intention of the default conversion in the language is
	   that, for a small enough, not necesarilly 0 integer, the
	   round trip will give the same integer.  It's hard to
	   imagine any implementation that won't, in fact, get this
	   "right", treating:

			p = (void *)x;

	   as equivalent to:

			p = (void *)((char *)0 + x);

	   and

			x = (int)p;

	   as equivalent to:

			x = (int)((char *)p - (char *)0);

	   If we want to be extra careful using this feature, it's 
	   reasonable to make sure that p is of type `void *'.

	   A common and good use for this is a `void *' parameter
	   passed in parallel with a function pointer (a "thunk" or
	   "closure") and propogated blindly to calls through the
	   function pointer.  Callers can pass a pointer to any type
	   or a suitably range-limited integer cast to 'void *'.


	3. The default conversion is, in fact, part of the language.
	   It can be invoked implicitly, or explicitly with a cast.
	   A traditional way to use this feature is to always mark
	   it's intentional uses with a cast: code which invokes it
	   implicitly is a mistake and helpful compilers give warnings
	   about that.

	4. There are all kinds of correctness analyses that can be
	   performed on C programs that go far beyond what you'd
	   expect a C compiler to do.  Some of these are strong enough
	   to only find bugs; some of these will only find code that
	   should be carefully reviewed.  Such analyses are so
	   open-ended, imprecise, and unrelated to compilation, that a
	   good strategy is to package them in tools like `lint'.
	   You might even add extra annotation to your program to help
	   lint-like tools be more accurate.  Three levels of 
	   meaning for "this is clean code" are: 

			a. it compiles
			b. it compiles with all the usual warnings 
			   enabled, without generating any warnings
			c. it passes inspection by <your favorite lint tools>

Historically GCC has had the nice property that it includes, as an
option, the ability to generate some warnings that older compilers
left for lint.  `printf' format checking is a nice example.  I even
appreciate adding `panic' calls in unreachable code where GCC can't
figure out that it is unreachable ("return from non-void function"
errors).

However, such features never kept GCC from providing the levels of
checking (a) and (b) in the list above.  Now, with the
pointer<->integer conversion warnings enabled by default and by
'-Wall', level (b) is gone.  Simply rethinking what options it takes
to enable the warnings would restore the traditional and useful
behavior, but I'm assured it's "not going to happen" and that I'd
better just "live with it".


	So only the double cast could be used to silent the
	"differing-sizes" warning.

When I first wrote this message, I said:

	Correct use of the double cast trick is only available to code
	that wants to rely on `intptr_t'.  It's a nice side-effect of
	the way the warning is implemented that the double cast trick
	works, but that's not a reason to enable the warning by
	default, or to not provide an option that does what `-Wall'
	did only a few years ago (the GCC branch I use, which doesn't
	have this bug, comes from 1999).

but thinking further about it, the double cast trick isn't even 
guaranteed to work in the presence of `intptr_t' since aren't we
only guaranteed that `intptr_t' is large enough -- not that it isn't
too large?  (That's not a rhetorical question: I don't have a C99 spec.)
(C99 has known-width integer types, right?  Are those of a specific
width?  or just a specific minimum width?)

	> On the other hand, heck, _why_not_ just make GCC less of a
	> real C compiler in _just_one_more_ way.  Who cares?  What
	> difference does it make, _really_?  Especially if it means
	> _rth_wins_!

	Don't follow you there. 

Well, I thought rth's "live with it" was pretty much over the top.  It
points to a long-standing attitude problem with GCC (that long
predates rth's involvement).  It points to more recent problems with
figuring out the design of GCC now that it's an element of commercial
services: would I have been told to "live with it" if I said "Here's
$250,000, please give me some -W options that work in the more
traditional way and can we please reconsider the defaults"?  I replied
in kind.  Such is email.

Someone off-list said "You should make patches for this."  First,
a reply like "live with it" suggest to me that such patches won't
be accepted.  Second, there's a design issue here -- it's a question
larger in scope than just "what changes would fix this specific bug".

	I think the efforts of *all* GCC
	developpers is to make GCC a *more* real C compiler, not a
	less one, and to solve all the cases where it is not :-) And
	BTW I care! I've lost too many days in debugging small errors
	that should have generated warnings if the compilers I used
	then (some years ago) had been smart enough to warn me that I
	was losing daat in a conversion I was thinking was safe
	reading the code, like "x = (int)p;" where it happens that x
	is a short but you have to go up 40 plines to notice it ;-(

	Of course perhaps we don't have the same idea of what a real C
	compiler is; for me it's a compiler that hepls me writing
	*good* code and avoiding dangerous constructs.

Support for levels (a) and (b) of the three levels of clean code
listed above is something I consider to be an essential property of a
real C compiler: a conceptually simple entity that is easy for
programmers to control and that has a natural relationship to the
language, sometimes augmented with fancy optimizations and combined
(in tasteful ways) with features from tools like `lint'.  Trying to
force me to change public interfaces to perfectly reasonable
libraries, switch to C99 at too early a date, or break code that uses
those interfaces in order to shut up a default and `-Wall' warning
that's inspired by the frustrations someone had porting Linux to
alpha contributes to the sensation of using a C compiler maintained by
people who don't like C.  But then, I'm the sort of dinosaur who
thinks it will be a stunning improvment the day that GCC distributions
start including a _second_ compiler that's similar in size and
complexity to, say, lcc or the Plan 9 compiler.  That, and an
extensible `lint'.

-t


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]