[PATCH] C undefined behavior fix

mike stump mrs@windriver.com
Sat Jan 5 20:37:00 GMT 2002


Your message doesn't indicate an understanding of the problem yet.

> Date: Sat, 05 Jan 2002 09:55:50 -0800
> From: Dennis Ferguson <dennis@juniper.net>

> 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).

This isn't the problem at hand.

> I don't get it, this still just computes "foo" + 5.  If you didn't
> know what "foo" + 5 pointed to

The problem isn't that we don't know, the problem is that we _do_
know.  And what we know, isn't what the user expected.

> when computing it in C you also wouldn't know what it pointed to in
> assembler.

By washing the variable though assembler, we inform the compiler that
in fact it doesn't know.  When, and only when the optimizer doesn't
know, will it do the right thing.

> If computing this in C caused an aliasing problem then computing it
> in assembler would cause the same problem.

No.  Try it.  Inform the compiler that it doesn't know, say by washing
it though volatile, and watch it generate the right code.

> This doesn't fix anything, it just hides the potential breakage from
> the compiler more completely.

Nope.  This is a misunderstanding.

> 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.

Use volatile if you want.  Use any construct for which you can inform
the compiler that it doesn't know.  Casting isn't such an operation,
as we have seen.

It is the users responsibility to inform the compiler what it is
doing.  The case at hand is the case of moving the entire string pool
around in memory, and then using it at a different address than where
the compiler knew the string pool would be.

Nowhere in the code was the compiler informed of this, if you
disagree, point to it, tell us.  What we will tell you, is that the
compiler _must_ be informed about such things.

Inform it, and will will work with you instead of against you.  For
example, try:

inline void *foo(void *vp) { void *volatile v; v = vp; return v; }

ctrcpy (
char buf[100];

inline void *foo(void *vp) { void *volatile v; v = vp; return v; }

int main() {
  strcpy (buf, foo("hithere lksjdf lfdlkfd lkjsdfl lkjadsl kadl jkkjsadl kjaldkjasldkj aldskj alkjdlaskjd lakjdlaskd l adjlfdkjslkjfd ljfd "+20));
}

and notice that the compiler does the right thing.  Try it without the
call to foo, and watch it do the wrong thing.

volatile means, you may otherwise think you know what I am doing, but
trust me, you have no clue as to what really is going on.



More information about the Gcc mailing list