On Wed, 2023-06-07 at 19:19 +0200, Benjamin Priour wrote: > Hi, > > I've been mapping where the analyzer is lacking support of the > operator new > different variants. > I've written a bunch of test cases already to demonstrate it, you can > find > them below. > They are not yet formatted for a patch submission, and as some of > them may > require new warnings, I didn't use dg-* directives either.
You can always mark the dg-directives with "xfail" and a comment if the warning isn't implemented yet. > You will notice I included true positives and negatives as well, as I > think > they might spur ideas on some edge cases that may fail. > All that to say I would greatly appreciate your comments if any test > is > wrong, or if you have pointers on additional test cases. Looks great. Note that the results might be affected by exceptions; do any results change for -fexceptions versus -fno-exceptions? > You can also find a godbolt <https://godbolt.org/z/dxj87fxG7> here. > > The most annoying one is the recurrent noisy false positive > -Wanalyzer-possible-null-argument on usage of a new expression. > Although a placement new on a static buffer too short is flagged by > the > middle-end, the analyzer stay quiet. > A placement on a dynamic buffer too short to contain the placement is > never > reported however. See PR105948 > <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105948> Yeah; looks like that will need some extra code in the analyzer to implement; you can ask the region_model what the capacity of the region is; do you have access to the required size of the region at the placement new call? If so then the implementation should be very similar as -Wanalyzer-out-of-bounds (or reuse it?) Dave > > Thanks, > Benjamin > > #include <new> > > struct A > { > int x = 4; > int y = 6; > }; > > void test1() > { > int *x = ::new int; // true negative on -Wanalyzer-possible-null- > argument > int *arr = ::new int[3]; // true negative on > -Wanalyzer-possible-null-argument > A *a = ::new A(); // false positive -Wanalyzer-possible-null-argument > (a > throwing new cannot returns null) > ::delete a; > ::delete x; > ::delete[] arr; > } > > void test_allocators_mismatch() > { > int *a = ::new int; > int *b = ::new int[3]; > > ::delete[] a; /* true positive -Wanalyzer-mismatching-deallocation > flagged > */ > ::delete b; /* true positive -Wanalyzer-mismatching-deallocation > flagged */ > } > > // From clang core.uninitialized.NewArraySize > void test_garbage_new_array() > { > int n; > int *arr = ::new int[n]; /* true positive > -Wanalyzer-use-of-uninitialized-value reported for 'n' */ > /* however nothing is reported for 'arr', even with > '-fno-analyzer-suppress-followups', one could expect a specific > warning */ > ::delete[] arr; /* no warnings here either */ > } > > void test_placement() > { > void *chunk = ::operator new(20); // true negative > -Wanalyzer-possible-null-dereference > A *a = ::new (chunk) A(); > a->~A(); > ::operator delete(chunk); > } > > void test_delete_placement() > { > A *a = ::new A; // false positive -Wanalyzer-possible-null-argument > (throwing new) > int *z = ::new (&a->y) int; > a->~A(); // deconstruct properly > ::operator delete(a); > ::operator delete(z); // nothing from analyzer but got > -Wfree-nonheap-object, even though analyzer also has > Wanalyzer-free-of-non-heap > } > > void test_write_placement_after_delete() > { > short *s = ::new short; > long *lp = ::new (s) long; > ::delete s; > *lp = 12; // true positive -Wanalyzer-use-after-free flagged, as well > as a > wrong -Wanalyzer-null-dereference of lp > } > > void test_read_placement_after_delete() > { > short *s = ::new short; > long *lp = ::new (s) long; > ::delete s; > long m = *lp; // true positive -Wanalyzer-use-after-free flagged, as > well > as a wrong -Wanalyzer-null-dereference of lp > } > > void test_use_placement_after_destruction() > { > A a; > int *lp = ::new (&a.y) int; > a.~A(); > int m = *lp; /* true positive -Wanalyzer-use-of-uninitialized-value, > nothing about use-after-delete though */ > } > > // From clang cplusplus.PlacementNewChecker > void test_placement_size_static() > { > short s; > long *lp = ::new (&s) long; /* nothing from analyzer, but still got > -Wplacement-new= */ > } > > void test_placement_size_dynamic() > { > short *s = ::new short; > long *lp = ::new (s) long; // Nothing reported here at all, would > expect a > -Wanalyzer-placement-new= > ::delete s; > } > > void test_placement_null() > { > int *x = nullptr; > int *p = ::new (x) int; // Placement new on NULL is undefined, yet > nothing > is reported. > ::operator delete(x); > } > > void test_initialization_through_placement() > { > int x; > int *p = ::new (&x) int; > *p = 10; > int z = x + 2; // Everything is fine, no warning emitted > }