llvm / llvm/llvm-project

[Analyzer] False positive clang-analyzer-core.UndefinedBinaryOperatorResult

Open
#174,632 7 comments 0 reactions 0 assignees View on GitHub
clang:static analyzer false-positive
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Original issue reported in https://github.com/benhoyt/inih/issues/208 and [openconnect/ocserv!437](https://gitlab.com/openconnect/ocserv/-/merge_requests/437).

This looks like a false positive:
```console
$ git clone https://github.com/benhoyt/inih.git
$
$ scan-build clang -c ini.c
scan-build: Using '/usr/lib/llvm-18/bin/clang' for static analysis
ini.c:164:56: warning: The left operand of '!=' is a garbage value [core.UndefinedBinaryOperatorResult]
164 | if (offset == max_line - 1 && line[offset - 1] != '\n') {
| ~~~~~~~~~~~~~~~~ ^
1 warning generated.
scan-build: Analysis run complete.
scan-build: 1 bug found.
scan-build: Run 'scan-view /tmp/scan-build-2026-01-06-201438-11205-1' to examine bug reports.
$
```

1. I don't understand why the analyser would complain about `line` containing garbage in line [164](https://github.com/benhoyt/inih/blob/8e06f6b77b5d4471bdc6d85ada81b67d37354a5c/ini.c#L164):
```c
if (offset == max_line - 1 && line[offset - 1] != '\n') {
```
but not in previous line [141](https://github.com/benhoyt/inih/blob/8e06f6b77b5d4471bdc6d85ada81b67d37354a5c/ini.c#L141):
```c
offset = strlen(line);
```
2. The `line` char array is filled in [`ini_reader_string`](https://github.com/benhoyt/inih/blob/8e06f6b77b5d4471bdc6d85ada81b67d37354a5c/ini.c#L287-L312) and I fail to see why it wouldn't fill `line`/`str` properly through the `strp` pointer:
```c
/* An ini_reader function to read the next line from a string buffer. This
is the fgets() equivalent used by ini_parse_string(). */
static char* ini_reader_string(char* str, int num, void* stream) {
ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
const char* ctx_ptr = ctx->ptr;
size_t ctx_num_left = ctx->num_left;
char* strp = str;
char c;

if (ctx_num_left == 0 || num < 2)
return NULL;

while (num > 1 && ctx_num_left != 0) {
c = *ctx_ptr++;
ctx_num_left--;
*strp++ = c;
if (c == '\n')
break;
num--;
}

*strp = '\0';
ctx->ptr = ctx_ptr;
ctx->num_left = ctx_num_left;
return str;
}
```

I am running Clang 1.18 as bundled with Ubuntu 24.04:
```console
$ dpkg -l clang-tools
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-=================-==============-============-=================================
ii clang-tools:amd64 1:18.0-59~exp2 amd64 clang-based tools
$
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the warning with `scan-build clang -c ini.c`, then inspect ini.c around line 164 and compare it with the strlen call at line 141. Trace the buffer initialization through ini_reader_string at lines 287-312 and determine why the analyzer reports a garbage value. Done means the reported false positive is explained and the analyzer no longer emits it for this case.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.