[RFC] Add command line flag to make pointer subtraction defined

I’m working on better support for MSVC compatibility in Clang, specifically for kernel-mode compilation (/kernel or -fms-kernel).

Kernel codebases are mature and sometimes deviate from standard C/C++ requirements. For example, C and C++ require two pointers to point to elements of the same array (or one past the end) when subtracting them. To enforce this behavior, Clang currently does two things:

  • For array element access, it generates inbounds GEP instructions. Moving the result of an inbounds GEP outside the array bounds is undefined behavior.

  • For pointer subtraction, it emits the sdiv exact operation. This operation may later be lowered to ashr exact when the object size is a power of two. Both of them result in poison value when %op1 is not divisible by %op2 according to LLVM Language Reference Manual — LLVM 23.0.0git documentation

The first issue can now be mitigated in Clang with the -fwrapv-pointer command-line option. However, there is currently no option to mitigate the second issue.

To address this, a new flag called -fstable-pointer-subtraction is proposed. Here is the PR link:

When used, this flag replaces sdiv exact instruction with plain sdiv, which behavior is defined for any positive value of %op2. Combining this new flag with -fwrapv-pointer would make pointer subtraction fully defined.

1 Like

Just curious: what is a concrete use case where this happens?

According to spec, the result of sdiv exact is a poison value in case %op1 is not divisible by %op2. At the moment this doesn’t actually result in UB on any platform, I know of, however the goal is to provide some sort of guarantee this isn’t going to happen in future versions of compiler. The same kind of guarantee is already used for signed overflows via -fwrapv: signed overflow is real UB in C/C++, and optimizer do rely on it in ways that can produce broken code if the program depends on wrapping semantics.

What I meant was: what (real-world) code performs pointer subtraction on too large types? Or is this a purely preventive measure for some hypothetical code? What is the underlying motivation here?

Note that in C/C++, casting to a type with a higher alignment is (also) UB, so relaxing here will probably only help with subtracting struct pointers?

1 Like

Well, there is a plenty of code in kernel and boot loader, that does pointer arithmetic over externally defined layouts rather than ordinary well-typed C objects. In such code it is not unusual to have a pointer which is not naturally aligned.

The underlying motivation is that sdiv exact introduces an additional optimizer-visible assumption: that the address difference is divisible by sizeof(T). I’m asking if there should be a way to guarantee that this assumption is not introduced, similarly to how -fwrapv prevents relying on signed-overflow UB even though signed overflow is UB in C/C++.