From: James Kanze on
Andrei Alexandrescu (See Website For Email) wrote:
> James Kanze wrote:
> > Andrei Alexandrescu (See Website For Email) wrote:
> >> I think it's one thing to have a wrong numeric value and one very
> >> different thing to have a program in which all hell breaks looks due to
> >> random overwriting of memory.

> > But nobody's really disagreeing. Being able to accidentally
> > randomly overwrite memory is hardly what I would call a feature.
> > (Being able to do it intentionally, e.g. with a
> > reinterpret_cast, is a necessary feature if you want to develope
> > kernel code, but that's a different issue.)

> > On the other hand, faced with a serious program error (e.g.
> > inconsistent values resulting from a race condition), having all
> > hell break loose is certainly preferrable to silently continuing
> > and pretending that all is well. And issuing a market order to
> > buy when our customer said sell.

> The problem is that the hell could break loose by also issuing a market
> order to buy when our customer said sell.

> The problem with a program is not that it crashes - that would be great
> - but that it can do anything, including not crashing.

> I guess the set of "all hell breaks loose" is much larger, and includes,
> the set "there is one incorrect value". I am sitting here in amazement I
> have so much trouble getting this point across.

Certainly. The only point I'm trying to make (here---there seem
to be multiple issues being discussed in parallel) is that even
with Java's "defined behavior", all hell can break loose. That
both are really "undefined behavior".

Except that we're not really discussing the undefined behavior I
find in Java. I agree that requiring error checking is a good
thing. And that C++ has too much undefined behavior, especially
in a lot of cases where there's absolutely no need for it.
Somehow, the argument has gotten away from my statement that all
languages have some forms of undefined behavior.

And I suspect that despite all of the niggling, you, David and I
would fundamentally agree that the problem in C++, in such
cases, isn't that you might crash, but that you can't count on
crashing. I'd even go further and say that I prefer the Java
solution of consistently doing the wrong thing to that of C++,
which results in inconsistent and untestable behavior.
Undefined behavior is bad, and C++ has far too much of it.

On the other hand, it's impossible to eliminate it entirely;
some of it comes directly from the hardware we run on, and
eliminating other cases (e.g. some of the threading issues)
really does impose unacceptably high run-time costs.

And that some undefined behaviors in C++ are there explicitly to
allow implementors to define them in a way that makes sense on
their platform.

[...]
> > I'm not sure how such personal anecdotes relate to the undefined
> > behavior issue, however. I don't think that there's any doubt
> > that Java has a lot less undefined behavior than C++: you claim
> > zero, and I claim that there are a very few special cases, where
> > as C++ has it all over the place.

> I am eager to hear about the few special cases, and I have tried to
> substantiate my point with what I found on the net. Would somebody
> please oblige.

Try dropping the power supply to the CPU chip by 20%, and see
how "defined" the behavior is.:-)

Try doing any multithreaded programming without proper
synchronization, and you'll get unpredictable results. The
language standard doesn't specify what happens globally, even if
it tries to specify most individual accesses. And if what
happens isn't defined, how can you say that it isn't
"undefined".

--
James Kanze (Gabi Software) email: james.kanze(a)gmail.com
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Al on
Hi there,

Bo Persson wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Gabriel Dos Reis wrote:
>>> "Andrei Alexandrescu (See Website For Email)"
>>> <SeeWebsiteForEmail(a)erdani.org> writes:
>>>
>>> [...]
>>>
>>>> There might be a terminology confusion here, which I'd like to
>>>> clear from the beginning:
>>>>
>>>> 1. A program "has undefined behavior" = effectively anything could
>>>> happen as the result of executing that program. The metaphor with
>>>> the demons flying out of one's nose comes to mind. Anything.
>>> Why is not that the value of the computation?
>>>
>>>> 2. A program "produces an undefined value" = the program could
>>>> produce an unexpected value, while all other values, and that
>>>> program's integrity, are not violated.
>>>>
>>>> The two are fundamentally different because in the second case
>>>> you can still count on objects being objects etc.;
>>> I don't see anything fundamental in that difference.
>> It's very simple. In one case you have a program that preserves its
>> own guarantees (e.g. there's no random overwriting of memory), but
>> which has one numerical value that's invalid; that can't corrupt
>> memory because there's no pointer forging. In the other case you
>> can't count on pretty much anything.
>
> But what if that one value, incorrect and unpredictable, is part of an
> airliner's auto pilot, or a nuclear weapons launch system?
>
> Wouldn't nasal demons be an advantage, in practice?

Well, I don't see how C++'s approach, i.e., anything can happen,
including expressly crashing the plane into the ground, or launching all
the nukes available intentionally, is _at all_ better than Java's
approach, i.e., one undefined numerical quantity with zero memory
corruption.

It is pretty evident to me that the Plane/Nuke example is a strawman for
the real argument, which is that Java has a certain degree of provable
integrity and well-defined bounds for `undefined' behavior, and C++ doesn't.

In other words, it is defined what exactly is undefined, when and where
(specifically, during non-atomic reads or writes, plus whatever others
it may define).

Moreover, I believe because of these guarantees, Java actually has a
chance of self-diagnosis and recovery, whereas by this time, the C++
program probably segfaulted and crashed and burnt. I don't think this is
something to be proud of (not saying that you are :).

I can see how this spectacle could help in debugging (a kind of flare-up
to make you pay attention) but relying on this process is a fragile
proposition, because the chance of the bug crashing your program is
basically random in the general case; specially with the kinds of memory
tricks that new operating systems are introducing to deter buffer
overrun exploits and malicious stack manipulation.

As I said before, I don't think a wild-west mentality will help the
language. Better, more restrictive and more specific definitions of
undefined behavior are badly needed.

Cheers,
-Al.





--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andrei Alexandrescu (See Website For Email) on
Bo Persson wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>>It's very simple. In one case you have a program that preserves its
>>own guarantees (e.g. there's no random overwriting of memory), but
>>which has one numerical value that's invalid; that can't corrupt
>>memory because there's no pointer forging. In the other case you
>>can't count on pretty much anything.
>
>
> But what if that one value, incorrect and unpredictable, is part of an
> airliner's auto pilot, or a nuclear weapons launch system?
>
> Wouldn't nasal demons be an advantage, in practice?

Sure it would. As I said, the problem with a program with violated
memory is that rhinodaemonsitis (that's the technical term for the
condition) is actually only one of many possible behaviors; such a
program can produce any number of incorrect and unpredictable values...
including one :o).

Andrei

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andrei Alexandrescu (See Website For Email) on
David Abrahams wrote:
> "Andrei Alexandrescu (See Website For Email)"
>>It's very simple. In one case you have a program that preserves its own
>>guarantees (e.g. there's no random overwriting of memory), but which has
>>one numerical value that's invalid; that can't corrupt memory because
>>there's no pointer forging. In the other case you can't count on pretty
>>much anything.
>>
>>Explaining this any better is beyond my abilities.
>
>
> Let me try to help. I think you didn't mean to say "preserves its own
> guarantees," or at least that's a confusing way to put it. The
> *program's* guarantees, as I see it, are the ones made by the author
> of the program to himself and to his users, and in the presence of a
> programming error, those guarantees are out the window. In a language
> without undefined behavior, the guarantees of the underlying system
> are still there in spite of programming errors. In other words,
> executing "x + 1" still adds 1 to the value of x, and doesn't call a
> sorting routine (or whatever).

Great, thanks.

> That said, even in a system with no undefined behavior, we have no
> idea what the value of x (or anything else in our program) is after a
> programming error, so the ability to continue on with the program
> executing the instructions you thought you were giving it originally
> is not as valuable as it might at first seem.

It's not "anything else in our program". It's "anything else in our
program that was affected by x" and because (say in Java) races only
happen on numbers and because there's no pointer forging, that reduces
to "any other number that was affected by x", which considerably reduces
the rot in the program and the difficulty in spotting it. I guess all I
can say is that I tend to see that guarantee as much more valuable. :o)


Andrei

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andrei Alexandrescu (See Website For Email) on
David Abrahams wrote:
> Jean-Marc Bourguet <jm(a)bourguet.org> writes:
>>"Andrei Alexandrescu (See Website For Email)"
>><SeeWebsiteForEmail(a)erdani.org> writes:
>>
>>
>>>Well the only thing I can add is that in my limited experience,
>>>debugging Java programs is much easier because there's never the case
>>>that a dangling pointer misteriously overwrites some object it wasn't
>>>supposed to.
>>
>>Instead you are writing to an object which was supposed to be out of
>>existence for a long time. In my experience, that give you the same kind
>>of elusive bugs. Excepted that purify can't help you
>
>
> I want to emphasize that point: when nothing is truly illegal (like
> those things that C++ says cause undefined behavior), there's no way a
> tool like Purify can tell you that the program did something wrong.

But in a memory-safe program you don't even need Purify to tell you that
the program did something wrong. A logging module would suffice, and the
proof is in the trace.

The important tidbit that makes it all work is that bugs anywhere in the
program can't mess the logging subsystem.

Let's face it. Memory safety is too nice a property. If the argument is
that it leads to messier languages and slower programs, I'd agree. But
IMHO the arguments brought in this thread didn't carry much weight.

So my answer to "Purify can't tell you..." is "Because you don't need
Purify".

>>and that random behaviour including crashes are replaced by
>>deterministic, often plausible but wrong results.
>
>
> Of course that can happen in a system with undefined behavior, too.
> That said, it looks like a wash to me: incorrect programs have
> different characteristics under the two systems but neither one wins
> in terms of debuggability.

The memory-safe program wins because it never overwrites arbitrary
memory; so all objects unaffected by a bug respect their invariants.


Andrei

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]