# Getelementptr inbounds: inbounds of which allocation?

**URL:** <https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024>\
**Category:** IR & Optimizations\
**Created:** [May 16, 2024, 6:02am UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024 "2024-05-16T06:02:12Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![RalfJung](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/ralfjung/32/14079_2.png) [@RalfJung](https://discourse.llvm.org/u/RalfJung)\
**Post date:** [May 16, 2024, 6:02am UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024/1 "2024-05-16T06:02:12Z")

</div>

The docs for `getelementptr inbounds` say

> The base pointer has an _in bounds_ address of an allocated object, which means that it points into an allocated object, or to its end.

The phrase “_an_ allocated object” here makes it sound like this could be _any_ allocated object. Is that correct? What I would have expected is that it has to be _the_ allocated object that the base pointer is derived from.

More concretely, consider this code – using C syntax for readability, but this is meant to represent LLV IR:

```auto
int a = 0, b = 0;
uintptr_t a_addr = (uintptr_t)&a;
uintptr_t b_addr = (uintptr_t)&b;
// Non-inbounds pointer arithmetic that produces a pointer
// derived from `a` with the address of `b`.
int *a2 = getelementptr(a, (b_addr - a_addr)/sizeof(int));
// Inbounds pointer arithmetic on `a2`.
int *a3 = getelementptr_inbounds(a2, 1);

```

Is `a3` poison or not? Under LangRef as written, I would expect “no”, since `a2` and `a2 + 1` are inbounds if _some_ allocated object, namely `b`. But it’s the wrong allocated object! `a2` is derived from `a` and so that’s the only allocated object it can ever access, and so it’s the only allocated object that should ever matter. So probably `a3` should be poison, and the LangRef should be updated?

Cc @nikic – do you know if any optimization cares either way?

Cc @nlopes – what does Alive do?

---

<div class="post-metadata">

**Author:** ![nhaehnle](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/nhaehnle/32/23079_2.png) [@nhaehnle](https://discourse.llvm.org/u/nhaehnle)\
**Post date:** [May 16, 2024, 6:55pm UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024/2 "2024-05-16T18:55:54Z")

</div>

Certainly anything that relies on `llvm::getUnderlyingObject` would expect `a3` to point into `a`.

+1 to the expectation that `a3` is poison.

---

<div class="post-metadata">

**Author:** ![brunodf](https://avatars.discourse-cdn.com/v4/letter/b/c6cbf5/32.png) [@brunodf](https://discourse.llvm.org/u/brunodf)\
**Post date:** [May 17, 2024, 9:45am UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024/3 "2024-05-17T09:45:37Z")

</div>

I would think that using `a2` / `a3` for memory access would violate the LLVM IR [pointer aliasing rules](https://llvm.org/docs/LangRef.html#pointer-aliasing-rules) saying “Any memory access must be done through a pointer value associated with an address range of the memory access”, and in the example the `a2`/`a3` pointer values (according to the rules) are associated with the storage of `a` while they point to the storage of `b` ?

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/ralfjung/32/14079_2.png) [@RalfJung](https://discourse.llvm.org/u/RalfJung)\
**Post date:** [May 17, 2024, 4:03pm UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024/4 "2024-05-17T16:03:18Z")

</div>

> [@brunodf](#):
>
> I would think that using `a2` / `a3` for memory access

Yeah that would definitely be UB, but that’s not the question I asked. I asked specifically about the value of `a3`.

If we want to talk about memory accesses, let me extend the example:

```c
int a = 0, b = 0;
uintptr_t a_addr = (uintptr_t)&a;
uintptr_t b_addr = (uintptr_t)&b;
intptr_t diff = (b_addr - a_addr)/sizeof(int);
// Non-inbounds pointer arithmetic that produces a pointer
// derived from `a` with the address of `b`.
int *a2 = getelementptr(a, diff);
// Inbounds pointer arithmetic on `a2`.
int *a3 = getelementptr_inbounds(a2, 1);
// Move back to a.
int *a4 = getelementptr(a3, -diff-1);
// Now load.
int _val = *a4;

```

Is that load allowed? `a4` is derived from `a` and points at the right thing (`a+diff+1-diff-1 == a`), so if no poison gets in the way then the answer is yes. But of course if `a3` is poison then `a4` is poison and loading from it is UB.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea1.discourse-cdn.com/flex021/user_avatar/discourse.llvm.org/ralfjung/32/14079_2.png) [@RalfJung](https://discourse.llvm.org/u/RalfJung)\
**Post date:** [June 15, 2024, 8:58am UTC](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds-of-which-allocation/79024/5 "2024-06-15T08:58:15Z")

</div>

I made a PR for this, reviews would be welcome. 🙂

> <https://github.com/llvm/llvm-project/pull/95650>
>
> As discussed \[here\](https://discourse.llvm.org/t/getelementptr-inbounds-inbounds…-of-which-allocation/79024), we need the pointer to be inbounds of \*the\* allocated object the pointer is based on, not just any allocated object.
