125

I've seen the terms "IB" and "UB" used several times, particularly in the context of C++. I've tried googling them, but apparently those two-letter combinations see a lot of use. :P

So, I ask you...what do they mean, when they're said as if they're a bad thing?

cHao
  • 84,970
  • 20
  • 145
  • 172
  • 9
    If you decide to roll back someone else's edits, please make sure that your spelling, punctuation and grammar are perfect. Rolling back edits that are a substantial improvement over the original text is pointless. – Robert Harvey Nov 01 '12 at 15:40

5 Answers5

155

IB: Implementation-defined Behaviour. The standard leaves it up to the particular compiler/platform to define the precise behaviour, but requires that it be defined.

Using implementation-defined behaviour can be useful, but makes your code less portable.

UB: Undefined Behaviour. The standard does not specify how a program invoking undefined behaviour should behave. Also known as "nasal demons" because theoretically it could make demons fly out of your nose.

Using undefined behaviour is nearly always a bad idea. Even if it seems to work sometimes, any change to environment, compiler or platform can randomly break your code.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • 13
    I'm still waiting for a demon flying out of someone's nose because of using undefined behaviour in C++. I guess it will happen when the first compilers fully comply with the new C++ standard. – OregonGhost May 04 '10 at 15:41
  • 4
    @OregonGhost: I guess you're right. I've seen it happen with unicorns a couple times, but never demons. – Thomas May 04 '10 at 15:44
  • @Thomas: I'd accept Unicorns as well. Doesn't matter if one horn or two horns, like many demons have. – OregonGhost May 04 '10 at 15:45
  • 36
    @OregonGhost - the standard does not specify how many horns a demon should have. – DVK May 04 '10 at 15:53
  • I've always hated the 'nasal demons' example of undefined behavior. Can't someone come up with a more entertaining yet less goofy allegory (or metaphor or simile or whatever the 'nasal demons' thing is)? – Michael Burr May 04 '10 at 16:45
  • 1
    Well, interrupting the service because a 2GB memory dump is being written to the disk which considerably slow things down is not goofy enough I am afraid :( – Matthieu M. May 04 '10 at 17:24
  • 6
    @Michael Burr: I prefer "catch fire". It's evidently catastrophic, and it has at least a vague air of plausibility (computer hardware does sometimes catch fire, admittedly for reasons of hardware rather than software failure in the case of any system you'd be reading this thread on). – Steve Jessop May 04 '10 at 17:59
  • @MichaelBurr: I use "playing Beethoven 9th" for this purpose. – Alexandre C. Oct 10 '12 at 12:11
  • 1
    It's funny how no one having answered this question has less reputation than 30k. –  Nov 01 '12 at 15:44
  • @H2CO3: Well, the question *is* two and a half years old... :) – cHao Nov 20 '12 at 18:25
  • @cHao there are users who don't earn any points during several years, so it might not be an error to mention this :) –  Nov 20 '12 at 18:27
  • @MichaelBurr: I tend to invoke the notion of black holes forming spontaneously. – Lightness Races in Orbit Jan 24 '13 at 21:27
  • @SteveJessop: Nowadays, UB negates the laws of time and causality, and that's my preferred phraseology. One would think that UB couldn't possibly do anything worse than rewrite all RAM (including the stack) with arbitrary content and jump to an arbitrary location, but in a Harvard-architecture machine with non-writable code store (common in the embedded world) the consequences of such behavior would be bounded [indeed, some systems need to be coded to limit damage caused by such failures]. Undefined Behavior can have consequences beyond those that could result from even that fault model. – supercat Jul 31 '15 at 18:10
  • @supercat Yesterday I was observer of case where UB caused by out-of-bound array access and attempt to call upon a pointer there in inside of loop caused ca before that system was unresponsible as it allocated dozen times more dynamic memory than it had physical and was protected by gdb from being killed by systemtastrophic damage because of cooler fans, controlled by software\firmware stopped. Disadvantage of von Neumann's architecture :P – Swift - Friday Pie May 24 '19 at 13:56
  • 1
    @Swift-FridayPie: Attempting function calls through "accidentally" invalid pointers is a form of Undefined Behavior whose consequences should be expected to be severe, without any predictable bound (in some forms of low-level code, function calls through pointers that aren't regarded as valid by the Standard, but are deliberately crafted for a particular purpose, may be necessary to fulfill that purpose). One problem with the popularity of high-level languages is that they've pushed out Harvard architectures which require that I/O port addresses be included within the instruction, since... – supercat May 24 '19 at 16:22
  • 1
    ...such designs make it possible to guarantee that certain sequences of I/O operations cannot occur without intervening safety checks, even if all of RAM becomes corrupt and code jumps to an arbitrary address. – supercat May 24 '19 at 16:25
  • @supercat I dunno, if you familiar with Qt framework and traditional "style" books offer, but it contains so much of questionable or outright asking for UB design, that my head hurts. One array out bout use of pointer and they ended with something disastrous, because library have own strange implementation of dynamic vtable formed by code. Sadly most of devs follow Qt books like a Bible. – Swift - Friday Pie May 25 '19 at 12:29
  • @Swift-FridayPie: I'm not familiar with Qt. Does it treat the language as a form of high-level assembler, something the authors of the Standard have explicitly said they did not want to preclude, or do its issues go beyond that? – supercat May 25 '19 at 14:25
  • I thought "Intended Behaviour". – kmchmk Jun 13 '19 at 10:21
24

Implementation-defined behavior and Undefined behavior

The C++ standard is very specific about the effects of various constructs, and in particular you should always be aware of these categories of trouble:

  • Undefined behavior means that there are absolutely no guarantees given. The code could work, or it could set fire to your harddrive or make demons fly out your nose. As far as the C++ language is concerned, absolutely anything might happen. In practical terms, this generally means that you have an unrecoverable bug. If this happens, you can't really trust anything about your application (because one of the effects of this undefined behavior might just have been to mess up the memory used by the rest of your app). It's not required to be consistent, so running the program twice might give different results. It may depend on the phases of the moon, the color of the shirt you're wearing, or absolutely anything else.

  • Unspecified behavior means that the program must do something sane and consistent, but it is not required to document this.

  • Implementation-defined behavior is similar to unspecified, but must also be documented by the compiler writers. An example of this is the result of a reinterpret_cast. usually, it simply changes the type of a pointer, without modifying the address, but the mapping is actually implementation-defined, so a compiler could map to a completely different address, as long as it documented this choice. Another example is the size of an int. The C++ standard doesn't care if it is 2, 4 or 8 bytes, but it must be documented by the compiler

But common for all of these is that they're best avoided. When possible, stick with behavior that is 100% specified by the C++ standard itself. That way, you're guaranteed portability.

You often have to rely on some implementation-defined behavior as well. It may be unavoidable, but you should still pay attention to it, and be aware that you're relying on something that may change between different compilers.

Undefined behavior, on the other hand, should always be avoided. In general, you should just assume that it makes your program explode in one way or another.

Rob
  • 5,223
  • 5
  • 41
  • 62
jalf
  • 243,077
  • 51
  • 345
  • 550
  • 1
    UB should be avoided *if you care about portability*. A particular implementation can define what happens for specific undefined behavior, and in some cases (especially device drivers and smaller embedded systems) you need to use those things. – Jerry Coffin May 04 '10 at 15:53
  • 3
    @Jerry: No, UB should be avoided *if it is entirely undefined*. If the platform/implementation/runtime/compiler gives further guarantees, then you can rely on the behavior and lose portability. But then it's no longer quite as undefined... Most of the time, though, you have no such guarantees, and undefined is just undefined, and should be avoided at all costs. – jalf May 04 '10 at 15:55
  • "consistent" might be a misleading description of unspecified behavior. It has to be consistent with the general context of the operation, for example if an expression has "unspecified value" then the result must *be* a value, if you store it then the stored value must thereafter compare equal to itself, and so on. But unspecified results need not be consistent over time (same output for same input if you run it again), or even deterministic. – Steve Jessop May 04 '10 at 18:02
  • "no longer quite as undefined" - it's exactly as undefined *by the standard*, and UB is a short-hand meaning undefined by the standard. In your example it's defined by the implementation. For that matter you could rely on behaviour that isn't defined by the standard *or* the implementation, if you've checked the object code and don't plan to recompile ever again ;-) – Steve Jessop May 04 '10 at 18:08
  • "must thereafter compare equal to itself". Hmm, unless it's a NaN. Anyway, it must have whatever behavior is required of its type. – Steve Jessop May 04 '10 at 18:25
8
  • IB: is implementation defined behavior - the compiler must document what it does. Performing a >> operation on a negative value is an example.

  • UB: undefined behavior - the compiler can do what ever, including simply crashing or giving unpredictable results. Dereferencing a null pointer falls into this category, but also subtler things like pointer arithmetic that falls outside the bounds of an array object.

Another related term is 'unspecified behavior'. This is kind of between implementation defined and undefined behaviors. for unspecified behavior, the compiler must do something according to the standard, but exactly which choices the standard gives it is up to the compiler and need not be defined (or even consistent). Things like order of evaluation of sub-expressions falls in this category. The compiler can perform these in whatever order it likes, and could do it differently in different builds or even in different runs of the same build (unlikely, but permitted).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
4

The short version:

Implementation-defined behaviour (IB): Correctly programmed but indeterminate*

Undefined behaviour (UB): Incorrectly programmed (i.e. a bug!)

*) "indeterminate" as far as the language standard is concerned, it will of course be determinate on any fixed platform.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • If the standard indicates that an action invokes Implementation-Defined Behavior, implementations are required to specify a *consistent* behavior resulting from that action. Unfortunately, there is no category of behavior for which an implementation would be required to specify possible consequences, but would not be required to have any particular consequence occur consistently. – supercat Jul 31 '15 at 18:18
3

UB: Undefined Behavior

IB: Implementation-defined Behavior

DevSolar
  • 67,862
  • 21
  • 134
  • 209
missingfaktor
  • 90,905
  • 62
  • 285
  • 365