LCOV - code coverage report
Current view: top level - basic - alloc-util.h (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 17 20 85.0 %
Date: 2019-08-22 15:41:25 Functions: 6 6 100.0 %

          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      172259 : static inline void *mfree(void *memory) {
      48      172259 :         free(memory);
      49      172259 :         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     3900199 : static inline void freep(void *p) {
      83     3900199 :         free(*(void**) p);
      84     3900199 : }
      85             : 
      86             : #define _cleanup_free_ _cleanup_(freep)
      87             : 
      88     1340540 : static inline bool size_multiply_overflow(size_t size, size_t need) {
      89     1340540 :         return _unlikely_(need != 0 && size > (SIZE_MAX / need));
      90             : }
      91             : 
      92      825703 : _malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
      93      825703 :         if (size_multiply_overflow(size, need))
      94           0 :                 return NULL;
      95             : 
      96      825703 :         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          32 : _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
     109          32 :         if (size_multiply_overflow(size, need))
     110           0 :                 return NULL;
     111             : 
     112          32 :         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           1 : static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
     118           1 :         if (size_multiply_overflow(size, need))
     119           0 :                 return NULL;
     120             : 
     121           1 :         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