2

We are using Visual Studio 2015 Update 3 + Cumulative Servicing Release.

The following static code analyzer warning appears always at a specific situation:

operatornew.cpp(5): warning C28182: Dereferencing NULL pointer. 'a' contains the same NULL value as 'Temp_value_#2119' did.
  1. A pointer is dereferenced
  2. That pointer was allocated using array operator new
  3. and zero-initialization

See MWE here:

#include <iostream>
int main(int, char**)
{
  int * a = new int[400]();
  a[0] = 1;

  int * b = new int[400];
  b[0] = 1;

  std::cout << a[0] << std::endl;
  std::cout << b[0] << std::endl;

  delete[] a;
  delete[] b;
  return 0;
}

SCA warning is emmited at line 5.

But when derefencing pointer 'b' - which does not use zero-initialitation - there is no warning.

The warning says, that pointer 'a' is NULL when allocation failed. I would rather expect an exception on allocation failure. So I think pointer 'a' is never NULL in this example.

Is this static code analyzer warning a false positive?

Is there an exception std::bad_alloc when using array operator new with zero-initialization (and MSVC15+Update3)?

  • False positive for me. As a note using `std::vector` in that case should avoid that warning, and you may get rid of manual `delete[]`. – Jarod42 Oct 24 '17 at 08:20
  • One could use a smart pointer as well and the warning mysteriously vanishes. But our code base is huge and changing all occurences into smart pointers takes ages. – Christoph Thien Oct 24 '17 at 08:34
  • It is a false positive. Try to use a more progressive code analyzer, for example, PVS-Studio. – AndreyKarpov Oct 24 '17 at 11:28
  • We have PVS-Studio now and it performs really great in static code analysis. – Christoph Thien Jul 05 '18 at 06:09
  • does visual studio 2022 uses a code analyzer better than the code analyzer of visual studio 2015 ( So that is the reason why when i try to compile ( compile and run ) the code which is wrote in the question ( using visual studio 2022 ) the warning ( C28182 ) does not appear ) ? @Jarod42 – Fady Hany Jul 06 '22 at 10:55
  • @FadyHany: New versions (try to) does improvement, so I would say yes. If that particular warning has been improved, I don't know. (Seems yes, as you cannot reproduce the issue :-) ). – Jarod42 Jul 06 '22 at 11:16
  • when you said " False positive for me. As a note using `std::vector` in that case should avoid that warning, and you may get rid of manual delete[]. " you said " and you may get rid of manual delete[]. " you mean that when we use `std::vector` we do not have to write ( by ourselves ) in our code delete[] but it was written in the code of built-in `std::vector` . So we still use ( new and delete[] ) even if we use `std::vector` , right ? @Jarod42 – Fady Hany Jul 06 '22 at 11:46
  • @FadyHany: `std::vector` will do the allocation under the wood (It would not call `new int[400]` but would allocate enough place and would do *placement-new* for the different `int`, but that is just detail). – Jarod42 Jul 06 '22 at 11:52
  • Can you explain this " (It would not call new int[400] but would allocate enough place and would do placement-new for the different int, but that is just detail). " ? and does " under the wood " mean ( secretly ) ? @Jarod42 – Fady Hany Jul 06 '22 at 11:58
  • @FadyHany: Look at [how-is-c-stdvector-implemented](https://stackoverflow.com/questions/2096571/how-is-c-stdvector-implemented) or some `std::vector` implementations for details. – Jarod42 Jul 06 '22 at 12:24
  • does " under the wood " mean ( secretly ) ? @Jarod42 – Fady Hany Jul 06 '22 at 12:25
  • Typo -> *"Under the hood"*. *"secret"* has for me a meaning of hiding and should not be known, whereas I would mean more something that is a details/internal of implementation. – Jarod42 Jul 06 '22 at 12:36
  • in the link you mentioned the second answer said " If your implementation simply ended up doing new Foo[10] then you'd just have constructed 10 instances of Foo. Instead it uses its allocator to allocate and deallocate raw memory (without constructing objects) " but when i try to compile ( compile and run ) this code : class test { public: test() { cout << "test" << endl; } }; int main() { vectorX(10); return 0; } the output : test test test test test test test test test test – Fady Hany Jul 06 '22 at 12:41
  • ?????? @jarod42 – Fady Hany Jul 06 '22 at 12:42
  • @FadyHany: Answers from links are indeed not good quality IMO :-( . `std::vector` has `reserve`, and so `reserve(10);` won't call `new T[10];`, but something like `new std::aligned_storage[10]`, and doing *placement new* when needed. – Jarod42 Jul 06 '22 at 13:18
  • std::vector uses std::allocator to allocate the memory and in this link : https://cplusplus.com/reference/memory/allocator/allocate/ In the standard default allocator, the block of storage is allocated using ::operator new one or more times, and throws bad_alloc if it cannot allocate the total amount of storage requested. So now are you convinced of my opinion ? @Jarod42 – Fady Hany Jul 06 '22 at 13:27
  • ?????? @jarod42 – Fady Hany Jul 06 '22 at 14:15
  • @FadyHany: `new Test[42]` allocates, but also call constructors of `Test` (so not compatible with `reserve`). `allocator{}.allocate(42)` would just allocate (it would allocate a aligned buffer of `char`/`byte` ) and **not** call constructor (of `Test`); you need [`construct`](https://cplusplus.com/reference/memory/allocator/construct/) (which is basically a placement new) afterward. – Jarod42 Jul 06 '22 at 15:00
  • the allocator uses ::operator new and it does not call the constructors like this code : #include using namespace std; class test { public: test() { cout << "test" << endl; } }; int main() { test* p = (test*)::operator new (sizeof(test)); return 0; } @Jarod42 – Fady Hany Jul 06 '22 at 15:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/246201/discussion-between-jarod42-and-fady-hany). – Jarod42 Jul 06 '22 at 15:24

0 Answers0