CLEANUP: tree-wide: replace free(x);x=NULL with ha_free(&x)

This makes the code more readable and less prone to copy-paste errors.
In addition, it allows to place some __builtin_constant_p() predicates
to trigger a link-time error in case the compiler knows that the freed
area is constant. It will also produce compile-time error if trying to
free something that is not a regular pointer (e.g. a function).

The DEBUG_MEM_STATS macro now also defines an instance for ha_free()
so that all these calls can be checked.

178 occurrences were converted. The vast majority of them were handled
by the following Coccinelle script, some slightly refined to better deal
with "&*x" or with long lines:

  @ rule @
  expression E;
  @@
  - free(E);
  - E = NULL;
  + ha_free(&E);

It was verified that the resulting code is the same, more or less a
handful of cases where the compiler optimized slightly differently
the temporary variable that holds the copy of the pointer.

A non-negligible amount of {free(str);str=NULL;str_len=0;} are still
present in the config part (mostly header names in proxies). These
ones should also be cleaned for the same reasons, and probably be
turned into ist strings.
This commit is contained in:
Willy Tarreau
2021-02-20 10:46:51 +01:00
parent ee17b97eea
commit 61cfdf4fd8
45 changed files with 216 additions and 320 deletions

View File

@@ -73,6 +73,17 @@
#define BUG_ON(cond)
#endif
/* more reliable free() that clears the pointer */
#define ha_free(x) do { \
typeof(x) __x = (x); \
if (__builtin_constant_p((x)) || __builtin_constant_p(*(x))) { \
/* provoke a build-time error */ \
extern volatile int call_to_ha_free_attempts_to_free_a_constant; \
call_to_ha_free_attempts_to_free_a_constant = 1; \
} \
free(*__x); \
*__x = NULL; \
} while (0)
#if defined(DEBUG_MEM_STATS)
#include <stdlib.h>
@@ -129,6 +140,26 @@ struct mem_stats {
free(__x); \
})
#undef ha_free
#define ha_free(x) ({ \
typeof(x) __x = (x); \
static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \
.file = __FILE__, .line = __LINE__, \
.type = MEM_STATS_TYPE_FREE, \
}; \
__asm__(".globl __start_mem_stats"); \
__asm__(".globl __stop_mem_stats"); \
if (__builtin_constant_p((x)) || __builtin_constant_p(*(x))) { \
/* provoke a build-time error */ \
extern volatile int call_to_ha_free_attempts_to_free_a_constant; \
call_to_ha_free_attempts_to_free_a_constant = 1; \
} \
if (*__x) \
_HA_ATOMIC_ADD(&_.calls, 1); \
free(*__x); \
*__x = NULL; \
})
#undef malloc
#define malloc(x) ({ \
size_t __x = (x); \