[PATCH] C undefined behavior fix

Linus Torvalds torvalds@transmeta.com
Sat Jan 5 11:18:00 GMT 2002


On Sat, 5 Jan 2002, Richard Henderson wrote:
> On Sat, Jan 05, 2002 at 09:55:50AM -0800, Dennis Ferguson wrote:
> > Sometimes I know what "foo" + 5 points to.  If we're talking about
> > the more general case of converting pointers to an integer representation
> > of their bits, doing math on that, and converting the result back
> > to a pointer ...
>
> We're not talking about the general case.  An object that the compiler
> knows about (either global, file scope static, or on the stack) must be
> involved.

Can you limit it down enough to be useful, then?

The compiler knows about a lot of objects. There are real and very valid
uses for converting to integers, doing math, and converting back to a
pointer as a _generic_ operation on things. Sometimes those pointers come
from the heap, but other times they won't.

For example, the kernel knows about the notion of "page boundaries", and
it _knows_ about issues like turning an address into a "page+offset"
thing. Most of the time that happens with pages that the kernel has
allocated on its own, but the kernel keeps track of pages that were by the
compiler too (well, mostly it's the linker that did the actual allocation,
but they _are_ global objects that the compiler knew about) and it does
arithmetic on those addresses too.

I bet you don't really consider that unreasonable - you might well even
have written some of the alpha code yourself. Think of how the kernel
converts back and forth between virtual kernel addresses and "struct page
*". Where the virtual address can quite often be something like
"zero_page[]" that the compiler knows about.

(For edification of other people, we're talking very much about code like

	#define virt_to_pfn(x) \
		(((unsigned long)(x) - PAGE_OFFSET) >> PAGE_SHIFT)
	#define pfn_to_virt(pfn) \
		((void *)(((pfn) << PAGE_SHIFT) + PAGE_OFFSET))

and using the page nr as an index into arrays etc - not just arithmetic,
but indexing with it, and converting both ways).

Clearly a C compiler is very much supposed to allow that kind of pointer
arithmetic: that's largely the whole point of being able to cast pointers
to their integer representations, and it's supported by both traditional C
(and it is _not_ a "compilers were bad back then" issue - it's a "that's
what C was written for" thing), as well as being the accepted normal
behaviour of C.

I agree that the compiler should have room to optimize - and I think you
have all the room you have by virtue of the undefined nature of pointer
arithmetic. I'm a firm supporter of having a C compiler that can do as
well as possible.

But I also think the strength of C is that it has _not_ yet been corrupted
by the "high-level" people who think language constructs cannot be meant
for things that the compiler doesn't understand. So the C language very
much also offers the ability to do things that the compiler _isn't_ able
to understand, through the implementation-defined nature of the integer
conversion.

And when the compiler doesn't understand something, it shouldn't _think_
that it does. That way lies madness.

			Linus



More information about the Gcc mailing list