[PATCH] C undefined behavior fix

dewar@gnat.com dewar@gnat.com
Fri Jan 4 19:32:00 GMT 2002


> You may be used to Ada, where the language took a different tack: instead
> of having "implementation specific" behaviour, the language itself was
> extended. That's not how C works.

That just comes of not knowing Ada. In fact Ada has virtually the same
approach as C, well not quite, there are four situations

erroneous (like C undefined)
implementation dependent
implementation defined (as in C)
bounded error (considered an error, but the possible effects are enumerated)

The fourth category was introduced in Ada 95, partly to deal with the issue
of trying to limit acceptable behavior. The second category is like
implementation defined but does not require documentation. For example
the order of evaluation of functoin arguments is implementation dependent,
but not implementation defined (because it would be too big of a burden
for an implementation to document its choices, which typically come from
the depth of the register allocator).

> So says a language layer.

It is you who are (unconvincingly) trying to play language lawyer here and
justify your position from the standard, when this is not possible. You
would do better to take a pragmatic view here, rather than a formal language
view. After all you don't consider yourself a language lawyer :-)

> Welcome to the real world, where language lawyering is secondary, and
> working programs (in the face of limitations of the languages) are
> important.

Well actually I spend my time in that real world, working with customers
writing large critical applications, so I am perfectly well aware of the
real world. I have also written several commercial real-time kernels,
and complete operating systems, so I can perfectly well put on the
pragmatic hat.

The trouble is that these days, with highly optimizing compilers, and
advanced architectures doing all sorts of strange stuff, the "real world"
cannot afford so casually to dismiss language lawyering as secondary. Why
not? Because the compiler you use comes with a significant legal department
well versed in the contractual requirements of the standard. If you come
to the compiler with expectations not grounded in the contract, then you
are likely to be surprised (after all this whole discussion comes from you
being surprised!)

> But the C language has exactly the notion of "implementation defined"
> issues that _allow_ the programmer to take advantage of knowing more about
> the machine and the environment than the language lawyers did. Thats' the
> whole _point_ of "implementation defined" vs "undefined".

The notion of implementation defined *allows* but does not *require* a
compiler to do sensible things in these situations. You can't have a
requirement that only sensible things are allowed, because no one can
define formally what sensible means.

That means that when we come to something that is implementation defined,
we have to take a purely pragmatic viewpoint (something I have been arguing
here for a while, but it is *you* who seems to be fixated on arguing your
position from the language standard).

Once again, the C standard *allows* a compiler to do what you want, whatever
that is (we still don't have a clear statement), because it allows a compiler
to do whatever it wants.

Furthermore, it seems resaonable to assume that what you want is sensible,
though I can't be sure, because you have not defined it precisely, and sometim

things that seem sensible on first glance turn out to be meaningless nonsense
when subjected to strenuous semantic scrutiny. You may say that you think it
is a mistake made by language lawyers to worry about strenuous semantic
scrutiny, but the fact of the matter is that modern opimizing compilers
WILL subject your program to strenuous semantic scrutiny whether you like
it or not. The issue of what are or are not permissble transformations of
programs is a crucial one these days (back in the old days of naive
compilers, none of them attempted any significant transformations any way,
so these issues simply did not apply).

You can't have it both ways. If you want to play language lawyer and argue
your position from the C standard, then you have to:

  a) stay in that domain, and not try to weasle out wearing your pragmatic
  teashirt when the going gets rough.

  b) expect that arguments in this domain will be answered in that domain.

If you want to take a pragmatic view that says "hey, the standard is not
the issue here", then fine, but in that case:

  a) simply recognize that the standard is permissive enough to allow
     anything one might reasonably want to do at a pragmatic level.

  b) stop trying to argue that the standard somehow supports your choice
     more than it supports someone elses choice when the fact of the matter
     is that the standard is deliberately written NOT to favor any particular
     solution.
     
The phrase "implementation defined" means "the standard does not specify
what happens here, it is up to the implementation". Now you argue that it
should do something sensible. The trouble is that one person's sensible is
another persons idiotic choice. After all the choice that you don't like
is justified simply as a sensible choice that allows high performance.
If you are in the high performance arena, that's an important criterion
(wasn't it you arguing that compilers should be able to do whatever they
wanted with floating-point, regardless of the standard :-)

This discussion may seem off topic, but actually I think it is a fundamental
discussion to have and resolve in any compiler implementation project.
There are good arguments on both sides here, and it is not easy to do the
necessary semantic definition. The important point is that the standard
does NOT take sides here. It deliberately gives no guidance, except to
ask us to please document what we decide on!

Robert Dewar



More information about the Gcc mailing list