LCOV - code coverage report
Current view: top level - basic - alloc-util.h (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 17 20 85.0 %
Date: 2019-08-23 13:36:53 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 6 12 50.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : #pragma once
       3                 :            : 
       4                 :            : #include <alloca.h>
       5                 :            : #include <stddef.h>
       6                 :            : #include <stdlib.h>
       7                 :            : #include <string.h>
       8                 :            : 
       9                 :            : #include "macro.h"
      10                 :            : 
      11                 :            : #if HAS_FEATURE_MEMORY_SANITIZER
      12                 :            : #  include <sanitizer/msan_interface.h>
      13                 :            : #endif
      14                 :            : 
      15                 :            : typedef void (*free_func_t)(void *p);
      16                 :            : 
      17                 :            : /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
      18                 :            :  * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
      19                 :            : #define ALLOCA_MAX (4U*1024U*1024U)
      20                 :            : 
      21                 :            : #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
      22                 :            : 
      23                 :            : #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
      24                 :            : 
      25                 :            : #define newa(t, n)                                                      \
      26                 :            :         ({                                                              \
      27                 :            :                 size_t _n_ = n;                                         \
      28                 :            :                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
      29                 :            :                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
      30                 :            :                 (t*) alloca(sizeof(t)*_n_);                             \
      31                 :            :         })
      32                 :            : 
      33                 :            : #define newa0(t, n)                                                     \
      34                 :            :         ({                                                              \
      35                 :            :                 size_t _n_ = n;                                         \
      36                 :            :                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
      37                 :            :                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
      38                 :            :                 (t*) alloca0(sizeof(t)*_n_);                            \
      39                 :            :         })
      40                 :            : 
      41                 :            : #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
      42                 :            : 
      43                 :            : #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
      44                 :            : 
      45                 :            : #define malloc0(n) (calloc(1, (n)))
      46                 :            : 
      47                 :     688853 : static inline void *mfree(void *memory) {
      48                 :     688853 :         free(memory);
      49                 :     688853 :         return NULL;
      50                 :            : }
      51                 :            : 
      52                 :            : #define free_and_replace(a, b)                  \
      53                 :            :         ({                                      \
      54                 :            :                 free(a);                        \
      55                 :            :                 (a) = (b);                      \
      56                 :            :                 (b) = NULL;                     \
      57                 :            :                 0;                              \
      58                 :            :         })
      59                 :            : 
      60                 :            : void* memdup(const void *p, size_t l) _alloc_(2);
      61                 :            : void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */
      62                 :            : 
      63                 :            : #define memdupa(p, l)                           \
      64                 :            :         ({                                      \
      65                 :            :                 void *_q_;                      \
      66                 :            :                 size_t _l_ = l;                 \
      67                 :            :                 assert(_l_ <= ALLOCA_MAX);      \
      68                 :            :                 _q_ = alloca(_l_);              \
      69                 :            :                 memcpy(_q_, p, _l_);            \
      70                 :            :         })
      71                 :            : 
      72                 :            : #define memdupa_suffix0(p, l)                   \
      73                 :            :         ({                                      \
      74                 :            :                 void *_q_;                      \
      75                 :            :                 size_t _l_ = l;                 \
      76                 :            :                 assert(_l_ <= ALLOCA_MAX);      \
      77                 :            :                 _q_ = alloca(_l_ + 1);          \
      78                 :            :                 ((uint8_t*) _q_)[_l_] = 0;      \
      79                 :            :                 memcpy(_q_, p, _l_);            \
      80                 :            :         })
      81                 :            : 
      82                 :   15556392 : static inline void freep(void *p) {
      83                 :   15556392 :         free(*(void**) p);
      84                 :   15556392 : }
      85                 :            : 
      86                 :            : #define _cleanup_free_ _cleanup_(freep)
      87                 :            : 
      88                 :    5365061 : static inline bool size_multiply_overflow(size_t size, size_t need) {
      89   [ +  -  -  + ]:    5365061 :         return _unlikely_(need != 0 && size > (SIZE_MAX / need));
      90                 :            : }
      91                 :            : 
      92                 :    3302473 : _malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
      93         [ -  + ]:    3302473 :         if (size_multiply_overflow(size, need))
      94                 :          0 :                 return NULL;
      95                 :            : 
      96         [ +  - ]:    3302473 :         return malloc(size * need ?: 1);
      97                 :            : }
      98                 :            : 
      99                 :            : #if !HAVE_REALLOCARRAY
     100                 :            : _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
     101                 :            :         if (size_multiply_overflow(size, need))
     102                 :            :                 return NULL;
     103                 :            : 
     104                 :            :         return realloc(p, size * need ?: 1);
     105                 :            : }
     106                 :            : #endif
     107                 :            : 
     108                 :        128 : _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
     109         [ -  + ]:        128 :         if (size_multiply_overflow(size, need))
     110                 :          0 :                 return NULL;
     111                 :            : 
     112                 :        128 :         return memdup(p, size * need);
     113                 :            : }
     114                 :            : 
     115                 :            : /* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger
     116                 :            :  * than the product of its parameters. */
     117                 :          4 : static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
     118         [ -  + ]:          4 :         if (size_multiply_overflow(size, need))
     119                 :          0 :                 return NULL;
     120                 :            : 
     121                 :          4 :         return memdup_suffix0(p, size * need);
     122                 :            : }
     123                 :            : 
     124                 :            : void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
     125                 :            : void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
     126                 :            : 
     127                 :            : #define GREEDY_REALLOC(array, allocated, need)                          \
     128                 :            :         greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
     129                 :            : 
     130                 :            : #define GREEDY_REALLOC0(array, allocated, need)                         \
     131                 :            :         greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
     132                 :            : 
     133                 :            : #define alloca0(n)                                      \
     134                 :            :         ({                                              \
     135                 :            :                 char *_new_;                            \
     136                 :            :                 size_t _len_ = n;                       \
     137                 :            :                 assert(_len_ <= ALLOCA_MAX);            \
     138                 :            :                 _new_ = alloca(_len_);                  \
     139                 :            :                 (void *) memset(_new_, 0, _len_);       \
     140                 :            :         })
     141                 :            : 
     142                 :            : /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
     143                 :            : #define alloca_align(size, align)                                       \
     144                 :            :         ({                                                              \
     145                 :            :                 void *_ptr_;                                            \
     146                 :            :                 size_t _mask_ = (align) - 1;                            \
     147                 :            :                 size_t _size_ = size;                                   \
     148                 :            :                 assert(_size_ <= ALLOCA_MAX);                           \
     149                 :            :                 _ptr_ = alloca(_size_ + _mask_);                        \
     150                 :            :                 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
     151                 :            :         })
     152                 :            : 
     153                 :            : #define alloca0_align(size, align)                                      \
     154                 :            :         ({                                                              \
     155                 :            :                 void *_new_;                                            \
     156                 :            :                 size_t _xsize_ = (size);                                \
     157                 :            :                 _new_ = alloca_align(_xsize_, (align));                 \
     158                 :            :                 (void*)memset(_new_, 0, _xsize_);                       \
     159                 :            :         })
     160                 :            : 
     161                 :            : /* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
     162                 :            :  * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
     163                 :            : #define TAKE_PTR(ptr)                           \
     164                 :            :         ({                                      \
     165                 :            :                 typeof(ptr) _ptr_ = (ptr);      \
     166                 :            :                 (ptr) = NULL;                   \
     167                 :            :                 _ptr_;                          \
     168                 :            :         })
     169                 :            : 
     170                 :            : #if HAS_FEATURE_MEMORY_SANITIZER
     171                 :            : #  define msan_unpoison(r, s) __msan_unpoison(r, s)
     172                 :            : #else
     173                 :            : #  define msan_unpoison(r, s)
     174                 :            : #endif

Generated by: LCOV version 1.14