https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116060

            Bug ID: 116060
           Summary: -fanalyzer -fdiagnostics-text-art-charset=unicode
                    replaces typedef'ed type with "int" in some cases
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: azoff at gcc dot gnu.org
  Target Milestone: ---

For some targets, the type int32_t is a simple typedef to "int", others can
typedef to for example "long".

When running the c-c++-common/analyzer/out-of-bounds-diagram-8.c with glibc
(x86_64-linux-gnu), the test passes, but running it with newlib (arm-none-eabi)
fails.

On newlib, int32_t is typedef'ed to "long int".

In the c-c++-common/analyzer/out-of-bounds-diagram-8.c file, the expected
output is suppose to contain "int" and not "int32_t".
Consider the following small test case (simplified out-of-bounds-diagram-8.c):


$ cat foo.c
typedef INT32_TYPE int32_t;
typedef unsigned long size_t;
void test2 (size_t size)
{
  int32_t *buf = (int32_t *) __builtin_malloc (size * sizeof(int32_t));
  if (!buf) return;

  buf[size + 1] = 42;
  __builtin_free (buf);
}


$ gcc foo.c -fdiagnostics-plain-output -fanalyzer
-fdiagnostics-text-art-charset=unicode -S -o /dev/null -DINT32_TYPE=long
foo.c: In function 'test2':
foo.c:15:17: warning: heap-based buffer overflow [CWE-122]
[-Wanalyzer-out-of-bounds]
foo.c:11:30: note: (1) capacity: 'size * 4' bytes
foo.c:13:6: note: (2) following 'false' branch (when 'buf' is non-NULL)...
foo.c:15:6: note: (3) ...to here
foo.c:15:17: note: (4) write of 4 bytes at offset 'size * 4 + 4' exceeds the
buffer

                                                 ┌───────────────────────┐
                                                 │write of '(int32_t) 42'│
                                                 └───────────────────────┘
                                                             │
                                                             │
                                                             v
  ┌───────────────────────────────┐              ┌───────────────────────┐
  │buffer allocated on heap at (1)│              │   after valid range   │
  └───────────────────────────────┘              └───────────────────────┘
  ├───────────────┬───────────────┤├─────┬──────┤├───────────┬───────────┤
                  │                      │                   │
    ╭─────────────┴────────────╮     ╭───┴───╮     ╭─────────┴─────────╮
    │capacity: 'size * 4' bytes│     │4 bytes│     │overflow of 4 bytes│
    ╰──────────────────────────╯     ╰───────╯     ╰───────────────────╯


As can be seen above, the "write of" box mentions "int32_t", and I think this
is the correct behavior.


$ gcc foo.c -fdiagnostics-plain-output -fanalyzer
-fdiagnostics-text-art-charset=unicode -S -o /dev/null -DINT32_TYPE=int
foo.c: In function 'test2':
foo.c:15:17: warning: heap-based buffer overflow [CWE-122]
[-Wanalyzer-out-of-bounds]
foo.c:11:30: note: (1) capacity: 'size * 4' bytes
foo.c:13:6: note: (2) following 'false' branch (when 'buf' is non-NULL)...
foo.c:15:6: note: (3) ...to here
foo.c:15:17: note: (4) write of 4 bytes at offset 'size * 4 + 4' exceeds the
buffer

                                                     ┌───────────────────┐
                                                     │write of '(int) 42'│
                                                     └───────────────────┘
                                                               │
                                                               │
                                                               v
  ┌───────────────────────────────┐                  ┌───────────────────┐
  │buffer allocated on heap at (1)│                  │ after valid range │
  └───────────────────────────────┘                  └───────────────────┘
  ├───────────────┬───────────────┤├───────┬────────┤├─────────┬─────────┤
                  │                        │                   │
    ╭─────────────┴────────────╮       ╭───┴───╮     ╭─────────┴─────────╮
    │capacity: 'size * 4' bytes│       │4 bytes│     │overflow of 4 bytes│
    ╰──────────────────────────╯       ╰───────╯     ╰───────────────────╯


So, by simply changing the base type from "long" to "int", we now suddenly have
different content in the "write of" box.

Wouldn't it make more sense if the box would always mention "int32_t" as that's
the type used in the code?
If the current implementation is correct, how can the test case be adapted to
PASS when int32_t is not typedef'ed to "int"?

Note: out-of-bounds-diagram-8.c is just one of many test cases that fail for
newlib/arm-none-eabi.

Reply via email to