2

If there's a bug that triggers undefined behavior in a piece of code, is the undefined behavior consistent each time running it? and changes each time compiling it?

For example if you had some C code that does some string manipulation. You compile it, run it 3 times and the output is consistent of weird characters like ABCE*D-*+ĚĚĚĚĚĚĚĚĚĚĚ. You compile it again and the next time it run it 3 times it just crashes.

I'm sorry if the description is a little ambiguous, as I'm trying to figure this out myself.

1
  • 5
    Undefined behavior is just that: undefined. Don't try to find any consistency or whatever, it could very well depend on the alignment of the moons for all you care. Feb 13, 2016 at 16:19

2 Answers 2

12

No. The consistency of undefined behaviour is undefined.

Speaking practically, when you've caused undefined behaviour by dereferencing a null pointer, you can probably expect fairly deterministic results (segmentation fault) at least on the same computer, because that computer has been constructed to behave that way for null pointer dereferences.

But when you've caused it by dereferencing uninitialised pointers, whether the ensuing dereference is even "physically" possible will depend on what that unspecified, uninitialised value is, which may depend on what code has run before, and with what user inputs, and in what order. Like a dice roll, it's not actually random, but it's also neither fully deterministic nor usefully predictable. Add optimisations into the mix and it's no longer practical to attempt rationalising about any of it.

That's why we tend not to go into any further detail about the causes of specific symptoms of undefined behaviour; there's rarely any point.

7
  • 3
    Also, Windows uses address space randomization, which thwarts determinism
    – Erik Eidt
    Feb 13, 2016 at 17:02
  • 1
    This is probably the least important part of an otherwise solid answer but how is a dice roll “not actually random”?
    – 5gon12eder
    Feb 14, 2016 at 9:20
  • 4
    @5gon12eder - if you could reproduce the exact same circumstances of the die roll (ie, hand position, starting position of the die, the direction of the toss, etc), you should get the same result. It's just that generally there are too many factors for people to control. I do know people that can fairly reliably flip and catch a coin so it ends up on whichever face they want. Feb 14, 2016 at 10:17
  • I don't think that quantum mechanics will collaborate with your deterministic dice roll. Modulo cheating, that is.
    – 5gon12eder
    Feb 14, 2016 at 11:04
  • 1
    @5gon12eder: Yeah exactly what Clockwork said is what I was trying to get at. There's nothing truly random about a dice roll at all, in the technical sense, "quantum mechanics" or not. Feb 14, 2016 at 12:11
-3

According to the published Rationale for the C Standard:

The terms unspecified behavior, undefined behavior, and implementation-defined behavior are used to categorize the result of writing programs whose properties the Standard does not, or cannot, completely describe. The goal of adopting this categorization is to allow a certain variety among implementations which permits quality of implementation to be an active force in the marketplace as well as to allow certain popular extensions, without removing the cachet of conformance to the Standard. [italics in original]

The Standard thus uses the term undefined behavior to refer both to constructs which would generally be meaningless on all implementations, and to constructs which some implementations will process as "popular extensions" but others may not.

Without knowing what your particular code is doing, it could be any of three situations:

  1. Your code is relying upon a compiler to support a "popular extension", but in its present configuration it does not. Some such extensions were documented in the authoritative language specifications that predated the Standard (e.g. the 1974 "C Reference Manual", or K&R's "The C Programming Language", first and second editions) but weren't considered extensions at the time. Instead, judging from the Rationale, the authors of the Standard intended to say that compilers weren't required to behave precisely as earlier earlier specified in corner cases where doing so would be expensive and useless, and didn't think it necessary to explicitly say that compilers should nonetheless support the behaviors when practical and useful but expected compilers to do so whether mandated or not.

  2. The code is accidentally doing something whose effects were never specified anywhere, and would thus be unpredictable.

  3. The code is doing something which the Standard allows implementations to process in two or more different ways, chosen in Unspecified fashion (e.g. given x=f()+g();, implementations are allowed to call f() and then g(), or to call g() and then f(), choosing in whatever manner they see fit), and its behavior is defined by the Standard or the implementation as performing in one of the ways it does.

In situations like yours, the problem is most often #1, #2, or a combination thereof, than #3. While #2 is perhaps more common than #1, compilers that value "optimization" above compatibility with existing code are making #1 increasingly common.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.