Potential undefined behavior in `src_rep_t_clz_impl()` due to missing zero check (`__builtin_clz(0)`)
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## **Affected file**
`llvm-project/compiler-rt/lib/builtins/fp_extend.h` (line 69 - 71)
### Code:
```c
static inline int src_rep_t_clz_impl(src_rep_t a) {
return __builtin_clz(a) - 16;
}
```
---
## **Issue description**
This implementation may invoke **undefined behavior (UB)** when `a == 0`.
According to GCC documentation:
> “If x is 0, the result of `__builtin_clz(x)` is undefined.”
Therefore, if `src_rep_t_clz_impl()` is ever called with `a == 0`, the expression `__builtin_clz(a)` would produce undefined results.
Even if current call paths avoid zero inputs, it is safer to protect against this case explicitly, since such UB has led to subtle compiler misoptimizations in the past.
A related example is **[GCC Bug 101175 – "builtin_clz generates wrong bsr instruction"](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101175)**, where the undefined behavior of `__builtin_clz(0)` caused incorrect code generation on x86 due to instruction combining (BSR/LZCNT).
Add a simple zero guard to prevent undefined behavior:
```c
static inline int src_rep_t_clz_impl(src_rep_t a) {
if (a == 0)
return (int)(sizeof(src_rep_t) * 8); // Return full bit-width for zero
return __builtin_clz((unsigned)a) - 16;
}
```
This ensures:
- No UB when `a == 0`
- Defined, consistent behavior across all platforms
- Maintains existing performance and semantics for valid inputs
---
## **Additional notes**
- The literal subtraction `-16` assumes that `src_rep_t` is 16 bits and that `unsigned int` is 32 bits.
If these assumptions ever change, this hardcoded constant could become incorrect.
Consider deriving it from `sizeof(unsigned)` and `sizeof(src_rep_t)` for portability:
```c
return __builtin_clz((unsigned)a)
- ((sizeof(unsigned) * 8) - (sizeof(src_rep_t) * 8));
```
---
Contributor guide
Research direction
Start in llvm-project/compiler-rt/lib/builtins/fp_extend.h at src_rep_t_clz_impl() and inspect its callers to confirm whether zero can reach the function. Run the relevant compiler-rt tests, then add coverage for zero and verify that the result remains unchanged for nonzero inputs while avoiding undefined behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100