Unicorn with delicious cookie
Nous utilisons des cookies pour améliorer votre expérience de navigation. En savoir plus
Accepter
to the top
>
>
>
Why it is bad idea to check result of m…

Why it is bad idea to check result of malloc call with assert

20 Fév 2024
Author:

The pointer returned by malloc needs to be checked before use. Using the assert macro to check the pointer would be wrong. In this article, we'll investigate why this is a bad programming tip.

When I say malloc, I mean not only this function, but also calloc, realloc, _aligned_malloc, _recalloc, strdup, and so on.

The malloc function returns a null pointer if it's unable to allocate a memory buffer of the specified size. So, it's better to check if a pointer is equal to NULL before dereferencing it.

Why this check is mandatory, I have covered in detail in the article: "Four reasons to check what the malloc function returned". If you have the slightest doubt that such a check is necessary, please read the article before continuing this one.

The standard check looks like this:

int *ptr = malloc(sizeof(int) * N);
if (!ptr)
{
  // Handling memory allocation error
}

I prefer explicit comparison, though. It protects the code from typos and makes it a bit more readable (and it's obvious that a pointer is being checked):

if (ptr == NULL)

The most important thing to do is to handle the memory allocation error. The error may appear as follows:

  • a program terminates with a return code (if such behavior is allowed);
  • an operation is rejected, but the program continues working to save the data;
  • if the program controls a device, it shuts down the device (if such behavior is allowed);
  • the library should return a failure status, and the program will decide what to do next;
  • other options depending on the type of the program.

Let's not assume that we can skip the check, because the program will crash anyway if a null pointer is dereferenced. It may not crash. Null pointer dereference is undefined behavior, and its signs can be very surprising to a programmer. I've covered all of this in the article I mentioned earlier.

Now, let's discuss the following anti-pattern:

int *ptr = malloc(sizeof(int) * N);
assert(ptr);
memcpy(ptr, foo, sizeof(int) * N);

Some programmers use the assert macro (or its analogs, such as the ASSERT macro from the MFC library) to check the pointer.

Please note that if the NDEBUG macro is declared, the assert macro turns off (does nothing). An example of an implementation from assert.h:

#ifdef NDEBUG
#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation defined*/
#endif

In reality, this means that in the release version of the program, which should run as fast as possible, the NDEBUG macro is declared and assert is turned into "nothing". As a result, there's no protection against null pointers, and the consequences can be quite unpleasant.

In the debug version of the program, assert works as it should, but it makes no sense in real cases.

Usually, when developers test the debug version of a program, they use simple operation scenarios that don't require large memory allocations. Most likely, severe memory fragmentation won't occur. It's very unlikely that there will be a situation where memory allocation is impossible.

If such a thing really happens, assert indeed detects a null pointer. However, this is almost useless for the debug version of the program. The null pointer dereference shows up immediately anyway. There won't be any tricky undefined behavior issues as there are in optimized code.

So, this is what we have:

  • the assert macro doesn't work where it's supposed to (in release builds);
  • but it works where it's of little relevance (in debug builds).

What happens if you don't declare the NDEBUG macro for release versions?

This is a bad idea. In fact, a memory allocation error always causes an application to crash. Such behavior is unacceptable for many types of applications (especially for libraries). Many developers also use the same macro to implement additional checks throughout the code where it's necessary. So, missing NDEBUG can be considered a bug and then be fixed. Just don't do that.

Never be lazy to write proper crash checks, and users will be grateful. Thank you for reading.

Additional links:

Voir tous les articles

Poll:

Do you use PVS-Studio?

Subscribe
and get the e-book
for free!

book terrible tips
Popular related articles

S'abonner

Comments (0)

close comment form
close form

Remplissez le formulaire ci‑dessous en 2 étapes simples :

Vos coordonnées :

Étape 1
Félicitations ! Voici votre code promo !

Type de licence souhaité :

Étape 2
Team license
Enterprise licence
** En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité
close form
Demandez des tarifs
Nouvelle licence
Renouvellement de licence
--Sélectionnez la devise--
USD
EUR
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
La licence PVS‑Studio gratuit pour les spécialistes Microsoft MVP
close form
Pour obtenir la licence de votre projet open source, s’il vous plait rempliez ce formulaire
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
I want to join the test
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
check circle
Votre message a été envoyé.

Nous vous répondrons à


Si l'e-mail n'apparaît pas dans votre boîte de réception, recherchez-le dans l'un des dossiers suivants:

  • Promotion
  • Notifications
  • Spam