<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/105560>105560</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            False positive: core.NullDereference on a const, non-null pointer member
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          GuB-42
      </td>
    </tr>
</table>

<pre>
    With the following code

```C++
struct A {
        void test(bool doSet, int v);
        int *tPtr = nullptr;
        int val = 0;
        int * const nonNullPtr = &val;
};

#if 1

void A::test(bool doSet, int v) {
        if (doSet) tPtr = nonNullPtr;
        *(tPtr ? tPtr : nonNullPtr) = v;
}

#else

int main() {
        A a;
        a.test(false, 42);
        return 0;
}

#endif
```

With options 

```
--analyze --analyzer-output text -Xanalyzer -analyzer-checker=core.NullDereference -Xclang -analyzer-checker=core,debug.ExprInspection
```

I get

```
<source>:12:30: warning: Dereference of null pointer [core.NullDereference]
   12 |         *(tPtr ? tPtr : nonNullPtr) = v;
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
<source>:11:6: note: Assuming 'doSet' is true
   11 |         if (doSet) tPtr = nonNullPtr;
 |             ^~~~~
<source>:11:2: note: Taking true branch
   11 |         if (doSet) tPtr = nonNullPtr;
      | ^
<source>:12:4: note: Assuming field 'tPtr' is null
   12 | *(tPtr ? tPtr : nonNullPtr) = v;
      |           ^~~~
<source>:12:4: note: '?' condition is false
<source>:12:30: note: Dereference of null pointer
   12 |         *(tPtr ? tPtr : nonNullPtr) = v;
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
1 warning generated.
```

https://godbolt.org/z/vE7hWbWjh

There is no way for nonNullPtr to be NULL besides memory corruption , it is const and initialized to a valid target.

If A::test() is defined and used in the same translation unit, the warning disappears. It can be seen by removing the #else directive in the example code. For building a practical example that still shows the warning, have the A::test() definition and main() in different files.

Tested on various clang versions, including 11, 16, 18 and trunk. Also with clang-tidy.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0Vl2PmzgX_jXOzVEQmADJBRfMZPKqUlW90nbV3hp8CG6NjWzDdHoxv31lJ5mQNM12V90IETDn4zlffsysFXuFWJLsgWTbBRtdp035v_FhuaKLWvOX8pNwHbgOodVS6meh9tBojiTekrg63vP4cD0S-uCvsGqdGRsHFZDi4SS9mbTg4NA6Qte11hK4_gMdoY8glIOJ0A1Jz9J-jdDK_d8ZIOkW1Cjl4My1yMRk-Bzf0IVGK-tAafVhlPJkiNB8YvIsXmxnquFOU9FCMl8K0CuS-utuBBcBixYIXR9lNnAO5Q3QHDShFaHro9DuJF3Npb39dAvTBfhL5CjtRX08sJ4JRej6Gl4FbO6fRcfIWuZt0EdY0auaGHSjUfNc_-hfcdFetcZcJLSUHpzQysLNRjq8LpdMMfnyHeHtySz16IbRgcNvDpafT8twFmg6bL6iIem20QYjn7ctGmzRoGoQlp8bydT-pwqEPnKsx3309G0w75QdsPFA74TzDvbo7oRB0kerR9MgSZ9IWiWUpFUa-7I-M6OE2vvHOUTdhk6HQQvl0ADJHm6FQrJj4gEgoUCKRzj9_k0fHTVnVl7v_Ej29Pp6O76EpFV-8ObQ_1fWjr3fOAgtjpNQgLDgzIjnCJIL3_9gbi70Qgwe2z10dI7uI_vqsXkwUBummu53YHpLJsmeft4Gq5tpagVK7pPlQqFCrnxDXFf791T5lK9fREloQdKdR9VoxYWfDY_vsGH8Tb-fbNxp9v-mo3-xk5PTRMIeFRrmkEd3Br9zbrCeEOiO0N1e81pLF2mzJ3T3ndDd9FR0n-pPX7q50scODYaKanhmL9BqM2cnp6FG-PDn-_dQoxUcLfTYa_MCjTZmDJsmBLZx3siB3ZjiIJRwgknxHbk3wjwreq5lZo8uutiv2isa85kTFji2QiEP1kaL3mQgfst6BGeYspIF96MSgfD8x1PCuLBsGJAZG8E7Bw1TPg6LqKB-AYO9nsKUdQhHhgIujN9bJzw5wm-sHySG80UEO22gHoXkXo_BYFjjRMPkm5jrmAPrhJRgO_1s53g8vI5NGNZ-jDaEeuhdH-2MHIUCLtrQnA5aIdFe5O4jWocctIKJGaFHCwc2mdBYT2eHc0Ajx4A6Sfx7kof7OrhyZlRfI6ik1fDseTDoL53gL9GClynfpBu2wDIp6IrmabLJF11ZI9-s2DpO8qLI122e83yTrBsax8Uqq-tsIUoa01W8pklSZJssjzJEGmcM11ldr9tNS1Yx9kzISMqp9y26ENaOWCZxluXxQrIapQ2nQEoVPkP4Sij1h0JTeqVlPe4tWcVSWGfPZpxwEsudn34YtBW-nn4ub3KvT_ehZX1GlFbLC57rsa_RLEYjy6vREq4b66jRPaE77_r4txyM_oKNI3QXAFtCd8eIppL-FQAA__9xiDrN">