[PATCH] D15007: [analyzer] Improve modelling of nullptr_t in the analyzer. Fix PR25414.

Gábor Horváth via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 1 04:42:52 PST 2015


xazax.hun added a comment.

In http://reviews.llvm.org/D15007#298086, @dcoughlin wrote:

> Gabor, thanks for taking a look at this!
>
> I'm not sure `RegionStore::getBinding()` is the right place to put this logic.
>
> First, not all dereferences of a `std::nullptr_t` value go through `getBinding()`, so, for example, the following snippet triggers the assertion even with your patch:
>
>   decltype(nullptr) returnsNullPtrType();
>   void fromReturnType() {
>     ((X *)returnsNullPtrType())->f(); // Crash in analysis!
>   }
>


Thank you for spotting this, I will definitely try the approach you suggested.

> Second, not all locations of type `std::nullptr_t` contain `0`. For example, the following prints "1" on my machine:

> 

>   #include <iostream>

>   

>   int main() {

>     decltype(nullptr) x;

>     std::cout << (bool)x << "\n";

>   }

> 

> 

> That is, a default-initialized (garbage) nullptr_t may not be '0'. Prior to your patch the analyzer would warn here about `x` being uninitialized (when the analyzer is compiled without asserts) -- but with your patch we lose that warning.


I am not entirely sure what the correct behavior is here. According to the standard (2.14.7): "std::nullptr_t is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value." My interpretation is that, the std::nullptr_t does not have a state, it just converts to a null pointer value regardless what value is at the location of the nullptr_t. Regardless what the standard says it looks like the value of std::nullptr_t can be (ab)used in the current clang implementation.

> What do you think about moving your new logic to the symbol value creation methods in SValBuilder? More specifically, you could add the check for nullptr_t to `getRegionValueSymbolVal()`, `conjureSymbolVal()` (both variants), `getConjuredHeapSymbolVal()`, and `getDerivedRegionValueSymbolVal()`. This would let the analyzer warn when it knows there is a garbage value in a location of type nullptr_t but still optimistically assume that the value is is '0' when the value would otherwise be symbolic.

> 

> With this approach we would retain uninitialization warnings about accesses via definitely uninitialized storage:

> 

>   void fromUninitializedLocal() {

>     decltype(nullptr) p;

>     ((X *)p)->f(); // Warn about p being uninitialized

>   }

>   

>   void fromUninitializedLocalStruct() {

>     Type t;

>     ((X *)t.x)->f(); // Warn about t.x being uninitialized.

>   }

> 

> 

> but would warn about about a null access in `returnsNullPtrType()` and would keep the behavior you specify in your `f()` test because `p` is a parameter (and thus its value is symbolic).


I will look into this thank you.


http://reviews.llvm.org/D15007





More information about the cfe-commits mailing list