[PATCH] C undefined behavior fix
Dennis Ferguson
dennis@juniper.net
Sat Jan 5 09:56:00 GMT 2002
> On Sat, Jan 05, 2002 at 10:25:29AM +1100, Paul Mackerras wrote:
> > In other words, _hiding_ some information from the compiler turns
> > undefined behaviour into implementation-defined behaviour. Weird.
>
> No, it's still undefined (do you know what "foo" + 5 points to?).
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, then both device drivers and memory allocators often
depend on being able to do that fairly freely. The math isn't limited
to addition and subtraction either, paged memory allocators tend to
also like to do multiplies and divides (or, at least, shifts and
masks).
Such code isn't portable to all architectures which could support
a C compiler (this is system programming, after all), but can be written
to be portable to those which share a few common characteristics in
their address representation. If the characteristics we're depending
on are linear byte addressing and/or memory-mapped device registers,
the number of architectures you can support with the same piece of code
is quite large.
> It just happens to work.
Well, something has to work since such code sometimes has to be
written. What is scaring me, however, is the implication that the
only proper way to do this is:
> Would you _please_ just do the relocation in assembly? Do I need
> to write the code myself in order to end this thread for good?
I don't get it, this still just computes "foo" + 5. If you didn't know
what "foo" + 5 pointed to when computing it in C you also wouldn't know
what it pointed to in assembler. If computing this in C caused an
aliasing problem then computing it in assembler would cause the
same problem. This doesn't fix anything, it just hides the potential
breakage from the compiler more completely.
But while it doesn't fix anything, what it does do is force me to
replace a single piece of C code which will work just fine on a dozen
different processors with a dozen assembly versions doing the same
computations. If you are willing to write and maintain the dozen
versions for me then I guess this is still okay, but I think I'll
have to agree with the original poster that C apparently isn't the
system implementation language it once was.
Sometimes computations like this need to be done, and I think there
needs to be a way to do this with gcc in C which won't stop working
as the compiler gets smarter. I don't think the method even needs
to disable optimizations which assume no aliasing; if I know what
"foo" + 5 points to then I'll also know enough to either guarantee
that no aliasing is occuring or to put enough volatile declarations
in there to disable the optimizations. I just need a way to tell the
compiler I know what I'm doing in C rather than hiding what I'm doing
in assembly, the latter is a disaster.
So how can I do this in C in a way which doesn't "just happen to work"?
I've got a bunch of code I'd like to repair now that I know the
traditional cast to unsigned long can't be relied upon, and I'd like
to fix it in a way which stays fixed.
Thanks,
Dennis Ferguson
More information about the Gcc
mailing list