Live data from Hacker News

Pointers Are Complicated II, or: We need better language specs

ralfj.de

131–135 of 135 posts

Re: Pointers Are Complicated II, or: We need better language specs

#131

Earlier quoted context omitted.

> What happens when 'a' is allocated to a CPU register? When the & operator is used on 'a' it should mark it as unsafe to place the 'a' on a CPU register - CPU allocation is an optimization and optimizations should never affect how the program behaves (except making it run faster, of course) and as such they should only be applied when the compiler can be sure that they're safe to do so. (and yes, the same applies on…

> When the & operator is used on 'a' it should mark it as unsafe to place the 'a' on a CPU register Not necessarily, as the compiler might be smart enough to adjust the other operations and enregister the a variable anyway. There's no ceiling on how smart the optimiser can be. An extreme case: int a = 42; &a; // do things with 'a' This uses the & operator but doesn't even save the result of the expression, so the com…

Sure, if a compiler can do that with 100% certainty, it can use a register for it. However that '100%' comes after it treats &a as a pointer until the very moment it is '100%' sure.

Also FWIW i was referring to C, not C++. C pointer optimizations can easily chop off your leg, C++ basically adds poison just in case you survive the blood loss.

Re: Pointers Are Complicated II, or: We need better language specs

#132
post #118

Earlier quoted context omitted.

> After all, if you can tell if two pointers to unrelated objects are the same, that means you're willing and able to canonicalize them to a common-denominator representation, in which case you already have an ordering based on that same canonicalization too... why forbid that? UB wasn't meant to forbid anything, it was meant to allow implementers to offer different behaviour. Implementers who want to represent point…

> UB wasn't meant to forbid anything, it was meant to allow implementers to offer different behaviour. That's unspecified behavior, not undefined behavior. Unspecified behavior can literally do anything or nothing at all, including aborting the program nondeterministically. That effectively forbids invocation of UB for the programmer since you can't reason about the program after it's invoked, unless you've verified…

> That's unspecified behavior, not undefined behavior. Unspecified behavior can literally do anything or nothing at all, including aborting the program nondeterministically. That effectively forbids invocation of UB for the programmer since you can't reason about the program after it's invoked, unless you've verified your implementation has actually defined the behavior for you (despite not being required to). That's quite different from unspecified behavior where the implementation is required to pick some sane behavior (often among a set of acceptable behaviors) and stick with it in a self-consistent manner.

It's very hard to make trapping an acceptable implementation for unspecified behaviour while allowing the implementation to do the usual kind of reordering, so the standard doesn't try. That's the original intention behind e.g. null pointer dereference being undefined behaviour - implementations should be permitted to make null pointer dereference trap, but should also be permitted to reorder or optimize out pointer dereferences.

> Implementers already have to implement canonicalization for equality comparisons

No they don't - they can just make comparison return false for pointers of different types or from different segments. Canonicalisation is not the only way to do equality-comparison!

> and they already have to implement casting to uintptr_t too

But the result of that isn't required to have the same comparison semantics as pointers. E.g. if some of your pointers are aligned and you internally represent those without trailing zeroes (like the JVM does) and use that as the integer cast, then some different types of pointer end up casting to the same int, which is fine. But the standard requires those pointers to not compare equal as pointers, so you can't implement pointer comparison like that. (Well, you can implement >= and because those comparisons are undefined behaviour. But you'll have cases where a > You want to linear-search in a list and want equality to work for that? Well I want to binary search in an array/BST and need comparisons to work for that.

Look, I'm not saying I agree with the standards committee here, I'm saying that it's a plausible compromise position for them to have taken. Not being able to do equality comparisons would be way more limiting for users than not being able to do relational comparisons. Having to implement relational comparisons would have been a bit more work for implementers than only having to implement equality comparisons.

Re: Pointers Are Complicated II, or: We need better language specs

#133

Earlier quoted context omitted.

For me it is the third optimization which is incorrect. I mean, if you replace the pointers with array indexes, then you'd end up with something like this after the second optimization: char data[N]; uintptr_t p = rand_int(N); uintptr_t q = rand_int(N); data[q] = 0; data[p] = 0; uintptr_t ip = (p+1); uintptr_t iq = q; if (iq == ip) { data[p+1] = 10; print(data[q]); } Surely no sane compiler would replace the "data[q]…

You're right, and the optimization wouldn't have kicked in in the original example if p and q had been pointers to elements of the same array. However, if they are pointers to different local variables, the compiler knows something else: it knows that p and q do not alias each other, so writes to p can't change the value pointed by q and vice versa. Now, in the original code, there seems to be a write to a pointer ca…

Thanks, that's making it more clear.

Re: Pointers Are Complicated II, or: We need better language specs

#134

Earlier quoted context omitted.

If signed integer overflow is implementation defined rather than undefined then it isn’t an error and we cannot make compiler features that warn or reject when we can prove it will occur. In your case we’ve managed to get the worst of both worlds (a buggy program and no capacity for the compiler to stop you).

For a long time in C's history, for most platforms, int overflow was actually treated as well defined behavior, with many examples suggesting to use tests like x + y In modern C there is simply no portable way to easily check for integer overflow for 64-bit values, even though the vast majority of programs are running on a processor that defines exactly what happens with integer overflow, and even sets a flag that ca…

> even though the vast majority of programs are running on a processor that defines exactly what happens with integer overflow, and even sets a flag that can be tested for in a single jump

Widths matter. Platforms that do this don't overflow both 32 and 64 bit signed integers. So if you want to define signed integer overflow for all signed integer widths then for one (or both) of these widths you need to stick in runtime checks.

Re: Pointers Are Complicated II, or: We need better language specs

#135
post #99

Earlier quoted context omitted.

The compiler isn't __changing any programmer dictated behavior__. There are no UB sourced 'optimizations' being implicitly disabled and none have been expressly enabled. As long as valid code compiles it's on the humans that wrote the code (or that triggered it's writing in some higher level synthesis tool). Expanding on this; I don't want compilers _making_ optimizations based on UB. I want them educating the progra…

So, you want something like, WARNING: p may be NULL (undefined behavior)

That's one way, but I don't want the compiler attempting to out-think whatever wrote the code. If the code has undefined behavior, if the code has a non-obvious transformation that would make it faster (but IE changes the ordering, referenced variables, etc) that should be presented for integration to the source code, NOT silently performed for that single compilation. Never _make_ the optimization for the programmer. It's fine to have it as an error and suggest the optimal variant instead __for human review__.

"I don't want compilers _making_ optimizations based on UB. I want them educating the programmers so that the UB can be eliminated at a human level and correct outcomes are the result, optimized if it makes sense."

Post reply on HN