Live data from Hacker News

Everything in C is undefined behavior

blog.habets.se

711–720 of 748 posts

Re: Everything in C is undefined behavior

#711
post #699
post #268

Earlier quoted context omitted.

Exactly, this is very old C++ on display in this article. It’s certainly not as safe as a language like Rust, but quite a lot of undefended behavior and things that will shoot yourself in the foot have been changed over the last 10 years. Most C++ today will be immediately obvious and not accidentally mixed up with C.

Unfortunely most C++ today keeps making use of C idioms, including at companies with seat at WG21 table.

[deleted]

Re: Everything in C is undefined behavior

#712

Earlier quoted context omitted.

I'm saying that string search algorithms are _not_ a legitimate use case for unaligned loads.

You didn’t really say that, but feel free to share any reasons you might have to think so. I don’t see any reason why it wouldn’t be perfectly fine on recent hardware, where unaligned loads are just as fast, and the cache pressure is identical for a linear search algorithm.

I asked where is the part about unaligned pointers in your string processing example. Saying that you want to load multiple bytes at a time does not imply at all that you have to do unaligned loads.

Doing unaligned loads using SSE or AVX might have been possible on Intel architectures for a long time, but it is still a little bit slower afaik. But anyway when you get into sub-architecture specific details like that, you've essentially left C-land, and you're essentially doing assembler level programming.

Re: Everything in C is undefined behavior

#713

Earlier quoted context omitted.

But did the rust compiler assume that the integer would not overflow? It did so in Debug mode where runtime checks were added. If it's not the case in Release mode, does that mean semantics are different between Debug and Release?

The semantics are well-defined in both modes. You can predict exactly what will happen in either case. In C, the semantics are not defined at all , you can't predict what will happen and it's allowed to change between compilations of the same source. It will probably get omitted, since Undefined Behavior isn't allowed by the C abstract machine, but sadly compilers are allowed to emit code for UB in the source (partly…

UB is a runtime property. As far as you can statically verify some code parts, you can see UB at compile time, but the point of UB is exactly that it is about stuff you can't predict, or that is hard to predict as a compiler.

Now why you can cook up trivial artificial examples where a compiler will remove some code sections based on statically detected UB, instead of printing an error, you have to ask the compiler authors.

> The semantics are well-defined in both modes.

So they're not the same? So the behaviour is not uniquely defined by the source code alone, but is actually _very_ different based on compile mode? Between two modes whose point was never to have different semantics, but to have the _same_ semantics while being debuggable vs being fast?

> You can predict exactly what will happen in either case. In C, the semantics are not defined at all, you can't predict what will happen and it's allowed to change between compilations of the same source.

You can make the same "predictability" argument for C, you can easily write a compiler that has semantics exactly laid out. Case in point: -fwrapv. Case in point: UBSAN.

Re: Everything in C is undefined behavior

#714

Earlier quoted context omitted.

But did the rust compiler assume that the integer would not overflow? It did so in Debug mode where runtime checks were added. If it's not the case in Release mode, does that mean semantics are different between Debug and Release?

> But did the rust compiler assume that the integer would not overflow? It did not. > It did so in Debug mode where runtime checks were added. It didn't assume in that case either. It did a well defined thing: add checks. > If it's not the case in Release mode, does that mean semantics are different between Debug and Release? Strictly speaking, the language doesn't know about "release mode", as that's a Cargo thing.…

So in Rust, you are actually specificing TWO programs with a single source? Those Rust users are surely too clever for my liking!

You can tune a C compiler as well to have a very specific defined behaviour for integer overflow. You can add -fwrapv or you can add UBSAN.

The user never intended overflow to happen, because if they did, they could have used something like __builtin_mul_overflow() or whatever. Or they are an emotionally unstable user with destructive tendencies. The user also never intended the program to abort with a (nicely formatted) error message, unless they are a very very sad depressed nihilistic user who also never runs their program in Release mode.

To say that overflow would be defined in Rust is at least half a lie. We could agree that cargo has a choice of diagnostic policy though, a policy how to handle what is essentially a state with no defined or useful path forward, or in other words, UB.

Throwing errors might be a wanted property to detect oversights. C ecosystem has UBSAN too! But essentially the same is still true: Basic arithmetic operations are not closed over the numbers 0..2^N. Rust doesn't have a (unique and useful) definition for those operations for a subset of numbers. Even if you claim the operations are defined (say wrapping arithmetic in Release mode), it's not what the programmer wants. Probably the majority of algorithms work over natural numbers or integer numbers. These algorithms don't work when the arithmetic on integers modulo 2^N.

So the user has to constrain the set of valid inputs, and do manual sanitization, just like in C.

Re: Everything in C is undefined behavior

#715

Earlier quoted context omitted.

It means the C standard does not specify what the program does. Other documents may still specify what the program does. And the program definitely still does something, whether specified or not.

> And the program definitely still does something, whether specified or not. No. It most definitely does not mean this. Go read the series this is part of: https://blog.llvm.org/2011/05/what-every-c-programmer-should... It is absolutely critical that people programming in C understand what real compilers in the real world do.

Are you saying the programs in the blog post don't do things? I think they do things. The whole blog post is talking about which things they do.

Re: Everything in C is undefined behavior

#716
post #9

Anyone who uses the construction "C/C++" doesn't write modern C++, and probably isn't very familiar with the recent revisions despite TFA's claims of writing it every day for decades. Far from being just "C with classes", modern C++ is very different than C. The language is huge and complex, for sure, but nobody is forced to use all of it. No HN comment can possibly cover all the use cases of C++ but in general, unle…

> the upshot is you never need to deal with the Rust community In the end, everything comes down to culture war.

I've never noticed an issue with this using any of those three languages

Re: Everything in C is undefined behavior

#717

Earlier quoted context omitted.

> But did the rust compiler assume that the integer would not overflow? It did not. > It did so in Debug mode where runtime checks were added. It didn't assume in that case either. It did a well defined thing: add checks. > If it's not the case in Release mode, does that mean semantics are different between Debug and Release? Strictly speaking, the language doesn't know about "release mode", as that's a Cargo thing.…

So in Rust, you are actually specificing TWO programs with a single source? Those Rust users are surely too clever for my liking! You can tune a C compiler as well to have a very specific defined behaviour for integer overflow. You can add -fwrapv or you can add UBSAN. The user never intended overflow to happen, because if they did, they could have used something like __builtin_mul_overflow() or whatever. Or they are…

> You can tune a C compiler as well to have a very specific defined behaviour for integer overflow. You can add -fwrapv or you can add UBSAN.

This is an example of a compiler flag that adds definition to undefined behavior, which is of course, legal to do. That doesn't change that in the standard, it is undefined behavior, and in Rust, it is not.

> To say that overflow would be defined in Rust is at least half a lie.

In the context of "undefined behavior", it is not a lie at all.

> So the user has to constrain the set of valid inputs, and do manual sanitization, just like in C.

No, because the consequences of how the two languages define these behaviors are very, very different.

Re: Everything in C is undefined behavior

#718
post #104
post #79

Earlier quoted context omitted.

Ada 83 has no UB on call stack overflow, from the reference manual : http://archive.adaic.com/standards/83lrm/html/lrm-11-01.html "STORAGE_ERROR This exception is raised in any of the following situations: (...) or during the execution of a subprogram call, if storage is not sufficient."

So it's just as useful as when your stack area ends with a page that will segfault on access, or your CPU will raise an interrupt if stack pointer goes beyond a particular address? It's not safe though because throwing an exception, panicking, etc, is still a denial of service. It's just more deterministic than silently overwriting the heap instead. If the program is critical then you need to be able to statically pr…

A reliable 'denial-of-service' is better than silently doing the wrong thing.

> If the program is critical then you need to be able to statically prove the full size of the stack, which you can do with C and C++ with the right tools and restrictions.

Only for specific implementations; and neither C nor C++ standard guarantee that your program won't overflow the stack anyway. (Have a look, the standard says nothing about stack overflows, they still occur in practice with supposedly compliant compilers. So it seems that there are no rules about when they can happen.)

Re: Everything in C is undefined behavior

#719
post #528
post #107

Earlier quoted context omitted.

That’s true in other languages as well. Any programmatic task can end up being an exploit vector.

Yeah, but only in C* can those errors end up as more UB. * terms and limits may apply.

Many other languages also have UB. But almost none is as trigger happy as C and C++ are.

Re: Everything in C is undefined behavior

#720

Earlier quoted context omitted.

The thing is that the actual compiler behaviour matters more for real-world projects than what the C standard says. E.g. the C standard was always retroactive, it merely tried to reign in wildly different compiler behaviour at the time when the standard was new. It mostly succeeded, but still the most useful C and C++ compiler features are living in non-standard extensions.

Unaligned access being fine in one architecture, but not in others would create separate dialects, regardless of being blessed by ISO C. Just don't do unaligned access, it's a dialect that doesn't exist currently, and should never exist.

> Unaligned access being fine in one architecture, but not in others would create separate dialects, regardless of being blessed by ISO C.

That doesn't mean unaligned access would need to be UB. It could be implementation defined. Or could just be defined to result in an error on all machines.

Post reply on HN