X-Git-Url: https://git.ralfj.de/web.git/blobdiff_plain/78e44b8e3962fbd2c8e89369b5b73ccd39035d6f..9fbe3ff304532d5adea51828c613468904c66f23:/personal/_posts/2020-12-14-provenance.md?ds=sidebyside diff --git a/personal/_posts/2020-12-14-provenance.md b/personal/_posts/2020-12-14-provenance.md index ee3f5b6..78e2538 100644 --- a/personal/_posts/2020-12-14-provenance.md +++ b/personal/_posts/2020-12-14-provenance.md @@ -1,6 +1,6 @@ --- title: "Pointers Are Complicated II, or: We need better language specs" -categories: rust research +categories: rust research programming forum: https://internals.rust-lang.org/t/pointers-are-complicated-ii-or-we-need-better-language-specs/13562 license: CC BY-SA 4.0 license-url: https://creativecommons.org/licenses/by-sa/4.0/ @@ -55,10 +55,12 @@ int sum_up(int i, int j, unsigned int n) { // optimized version {% endhighlight %} However, that transformation is actually incorrect. If we imagine a caller using this function as `sum_up(INT_MAX, 1, 0)`, then this is a perfectly correct way to call `sum_up`: the loop is never entered, so the overflowing addition `INT_MAX+1` is never performed. -However, after the desired optimization, the program now causes a signed integer overflow, which is UB (Undefined Behavior) and thus May Never Happen! +However, after the desired optimization, the program now causes a signed integer overflow, which is UB (Undefined Behavior) and thus May Never Happen![^signed-int-overflow] [^loop]: If you are a regular reader of my blog, you will recognize this as the same optimization that already played a crucial role in [a previous post of mine]({% post_url 2020-07-15-unused-data %}). Loop-invariant code motion is a great optimization to look at when considering corner cases of IR semantics. +[^signed-int-overflow]: If you are coming here with a Rust mindset, imagine `i + j` was written as `i.unchecked_add(j)`. + One might be tempted to ignore this problem because the UB on integer overflow is a compiler-only concept; every target supported by the compiler will do the obvious thing and just produce an overflowing result. However, there might be other compiler passes running after the optimization we are considering. One such pass might inline `sum_up`, and another pass might notice the `INT_MAX+1` and replace it by `unreachable` since UB code is "by definition" unreachable, and another pass might then just remove all our code since it is unreachable. @@ -121,7 +123,8 @@ This program has two possible behaviors: either `ip` (the address one-past-the-e Or the two are equal, in which case the program will print "10" (`iq` is the result of casting `q` to an integer, so casting it back will yield the original pointer, or at least a pointer pointing to the same object / location in memory). The first "optimization" we will perform is to exploit that if we enter the `if` body, we have `iq == ip`, so we can replace all `iq` by `ip`. -Subsequently the definition of `ip` is inlined: +The assignment thus becomes `*(char*)ip = 10`. +Subsequently, the definition of `ip` is inlined: {% highlight c %} char p[1], q[1] = {0}; uintptr_t ip = (uintptr_t)(p+1);