| |
@@ -43,6 +43,20 @@
|
| |
pointer will always return false, so it is impossible to detect
|
| |
movement this way.
|
| |
|
| |
+ On a related note, `realloc` frees the memory area if the new size is
|
| |
+ zero. If the size unintentionally becomes zero, as a result of
|
| |
+ unsigned integer wrap-around for instance, the following idiom causes
|
| |
+ a double-free.
|
| |
+
|
| |
+ [source,c]
|
| |
+ ----
|
| |
+ new_size = size + x; /* 'x' is a very large value and the result wraps around to zero */
|
| |
+ new_ptr = realloc(ptr, new_size);
|
| |
+ if (!new_ptr) {
|
| |
+ free(ptr);
|
| |
+ }
|
| |
+ ----
|
| |
+
|
| |
==== Handling Memory Allocation Errors
|
| |
|
| |
Recovering from out-of-memory errors is often difficult or even
|
| |
@@ -105,6 +119,30 @@
|
| |
function, check if `malloc` had been called,
|
| |
and free the buffer as needed.
|
| |
|
| |
+ If portability is not important in your program, an alternative way of
|
| |
+ automatic memory management is to leverage the `cleanup` attribute
|
| |
+ supported by the recent versions of GCC and Clang. If a local variable
|
| |
+ is declared with the attribute, the specified cleanup function will be
|
| |
+ called when the variable goes out of scope.
|
| |
+
|
| |
+ [source,c]
|
| |
+ ----
|
| |
+ static inline void freep(void *p) {
|
| |
+ free(*(void**) p);
|
| |
+ }
|
| |
+
|
| |
+ void somefunction(const char *param) {
|
| |
+ if (strcmp(param, "do_something_complex") == 0) {
|
| |
+ __attribute__((cleanup(freep))) char *ptr = NULL;
|
| |
+
|
| |
+ /* Allocate a temporary buffer */
|
| |
+ ptr = malloc(size);
|
| |
+
|
| |
+ /* Do something on it, but do not need to manually call free() */
|
| |
+ }
|
| |
+ }
|
| |
+ ----
|
| |
+
|
| |
[[sect-Defensive_Coding-C-Allocators-Arrays]]
|
| |
=== Array Allocation
|
| |
|
| |
@@ -118,6 +156,12 @@
|
| |
greater than `((size_t) -1) / sizeof(T)`. See
|
| |
<<sect-Defensive_Coding-C-Arithmetic>>.
|
| |
|
| |
+ GNU libc provides a dedicated function `reallocarray` that allocates
|
| |
+ an array with those checks performed internally. However, care must
|
| |
+ be taken if portability is important: while the interface originated
|
| |
+ in OpenBSD and has been adopted in many other platforms, NetBSD
|
| |
+ exposes an incompatible behavior with the same interface.
|
| |
+
|
| |
[[sect-Defensive_Coding-C-Allocators-Custom]]
|
| |
=== Custom Memory Allocators
|
| |
|
| |
This adds a couple of tips that can be used with the recent compilers and glibc, namely
cleanup
attribute andreallocarray
.