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

            Bug ID: 120045
           Summary: analyzer: False positive with guarded NULL dereference
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: ibuclaw at gcc dot gnu.org
  Target Milestone: ---

This triggers a warning:
```
char *newarrayU(unsigned size, unsigned length)
{
    if (length == 0 || size == 0)
        return 0;
    char *ptr = (char*)__builtin_malloc(size * length);
    if (!ptr)
        __builtin_unreachable();
    return ptr;
}

char *newarrayiT(unsigned size, unsigned length)
{
    char* result = newarrayU(size, length);
    unsigned count = (size * length);

    while (1)
      {
        if (count == 0) break;
        *result = '0';
        result++;
        count-- ;
      }

    return result;
}
```


```
warning: dereference of NULL ‘result’ [CWE-476] [-Wanalyzer-null-dereference]
   19 |         *result = '0';
      |         ~~~~~~~~^~~~~
  ‘char* newarrayiT(unsigned int, unsigned int)’: events 1-2
    │
    │   11 | char *newarrayiT(unsigned size, unsigned length)
    │      |       ^~~~~~~~~~
    │      |       |
    │      |       (1) entry to ‘newarrayiT’
    │   12 | {
    │   13 |     char* result = newarrayU(size, length);
    │      |                    ~~~~~~~~~~~~~~~~~~~~~~~
    │      |                             |
    │      |                             (2) calling ‘newarrayU’ from
‘newarrayiT’
    │
    └──> ‘char* newarrayU(unsigned int, unsigned int)’: events 3-4
           │
           │    1 | char *newarrayU(unsigned size, unsigned length)
           │      |       ^~~~~~~~~
           │      |       |
           │      |       (3) entry to ‘newarrayU’
           │......
           │    4 |         return 0;
           │      |                ~
           │      |                |
           │      |                (4) ‘0’ is NULL
           │
    <──────┘
    │
  ‘char* newarrayiT(unsigned int, unsigned int)’: events 5-8
    │
    │   13 |     char* result = newarrayU(size, length);
    │      |                    ~~~~~~~~~^~~~~~~~~~~~~~
    │      |                             |
    │      |                             (5) return of NULL to ‘newarrayiT’
from ‘newarrayU’
    │......
    │   18 |         if (count == 0) break;
    │      |         ~~                   
    │      |         |
    │      |         (6) following ‘false’ branch (when ‘count != 0’)... ─>─┐
    │      |                                                                │
    │      |                                                                │
    │      |┌───────────────────────────────────────────────────────────────┘
    │   19 |│        *result = '0';
    │      |│        ~~~~~~~~~~~~~        
    │      |│                |
    │      |└───────────────>(7) ...to here
    │      |                 (8) ⚠️  dereference of NULL ‘result’
    │
```

I can't see the dereference ever being possible however between these three
conditions.

if (length == 0 || size == 0) return NULL;

unsigned count = (size * length);

if (count == 0) break;

When NULL is returned, then count is also guaranteed to be zero.

Reply via email to