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.

Reply via email to