https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128368
Bug ID: 128368
Summary: analyzer: null_terminated_string_arg misses
unterminated buffers with symbolic access(read_only)
size, braced char initializers, and globals
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: analyzer
Assignee: dmalcolm at gcc dot gnu.org
Reporter: 220245569 at seu dot edu.cn
CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
Target Milestone: ---
Target: *-*-*
Reproducer
----------
$ cat trigger.c
typedef __SIZE_TYPE__ size_t;
extern char *strict_fn (const char *p, size_t n)
__attribute__((null_terminated_string_arg (1)));
extern char *bounded_fn (const char *p, size_t n)
__attribute__((null_terminated_string_arg (1),
access (read_only, 1, 2)));
char g_unterm[3] = "abc";
char *control_strict (size_t n)
{
char buf[3] = "abc";
return strict_fn (buf, n); /* warns as expected */
}
char *bug_symbolic_size (size_t n)
{
char buf[3] = "abc";
return bounded_fn (buf, n); /* case 1: no warning */
}
char *bug_braced_init (size_t n)
{
char buf[4] = { 'a', 'b', 'c', 'd' };
return strict_fn (buf, n); /* case 2: no warning at -O2 */
}
char *bug_global_array (size_t n)
{
return strict_fn (g_unterm, n); /* case 3: no warning */
}
Compile flag: x86_64-linux-gnu-gcc -O2 -fanalyzer -S trigger.c
# Only control_strict emits -Wanalyzer-out-of-bounds; bug_symbolic_size,
# bug_braced_init (at -O1/-O2), and bug_global_array emit no warning.
Root cause
----------
1. Symbolic size in access(read_only, ptr_idx, size_idx)
(check_one_function_attr_null_terminated_string_arg,
gcc/analyzer/region-model.cc:2603-2639):
read_bytes (..., limit_sval, nullptr) returns SK_UNKNOWN when limit_sval is
symbolic (:5141). Because line 2620 only falls back to
check_for_null_terminated_string_arg when limited_sval is SK_POISONED, the
else branch repeats read_bytes (again SK_UNKNOWN) and returns at line 2638.
2. Folded braced initializers (svalue_byte_range_has_null_terminator_1,
region-model.cc:4419-4430): at -O1/-O2, {'a','b','c','d'} is folded into a
4-byte INTEGER_CST store, for which svalue_byte_range_has_null_terminator_1
returns TS_UNKNOWN because it only inspects 1-byte INTEGER_CSTs.
3. Global arrays (scan_for_null_terminator_1, region-model.cc:4838-4851):
base_reg->can_have_initial_svalue_p () is true for MEMSPACE_GLOBALS, so
non-const global arrays return an unknown svalue without scanning their
DECL_INITIAL.
Suggested Fix
-------------
1. In check_one_function_attr_null_terminated_string_arg
(region-model.cc:2620),
also call check_for_null_terminated_string_arg when limited_sval is
SK_UNKNOWN.
2. In svalue_byte_range_has_null_terminator_1 (region-model.cc:4419), inspect
multi-byte INTEGER_CST bindings via native_encode_expr.