github.com/prysmaticlabs/prysm@v1.4.4/third_party/afl/alloc-inl.h (about)

     1  /*
     2     american fuzzy lop - error-checking, memory-zeroing alloc routines
     3     ------------------------------------------------------------------
     4  
     5     Written and maintained by Michal Zalewski <lcamtuf@google.com>
     6  
     7     Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
     8  
     9     Licensed under the Apache License, Version 2.0 (the "License");
    10     you may not use this file except in compliance with the License.
    11     You may obtain a copy of the License at:
    12  
    13       http://www.apache.org/licenses/LICENSE-2.0
    14  
    15     This allocator is not designed to resist malicious attackers (the canaries
    16     are small and predictable), but provides a robust and portable way to detect
    17     use-after-free, off-by-one writes, stale pointers, and so on.
    18  
    19   */
    20  
    21  #ifndef _HAVE_ALLOC_INL_H
    22  #define _HAVE_ALLOC_INL_H
    23  
    24  #include <stdio.h>
    25  #include <stdlib.h>
    26  #include <string.h>
    27  
    28  #include "config.h"
    29  #include "types.h"
    30  #include "debug.h"
    31  
    32  /* User-facing macro to sprintf() to a dynamically allocated buffer. */
    33  
    34  #define alloc_printf(_str...) ({ \
    35      u8* _tmp; \
    36      s32 _len = snprintf(NULL, 0, _str); \
    37      if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
    38      _tmp = ck_alloc(_len + 1); \
    39      snprintf((char*)_tmp, _len + 1, _str); \
    40      _tmp; \
    41    })
    42  
    43  /* Macro to enforce allocation limits as a last-resort defense against
    44     integer overflows. */
    45  
    46  #define ALLOC_CHECK_SIZE(_s) do { \
    47      if ((_s) > MAX_ALLOC) \
    48        ABORT("Bad alloc request: %u bytes", (_s)); \
    49    } while (0)
    50  
    51  /* Macro to check malloc() failures and the like. */
    52  
    53  #define ALLOC_CHECK_RESULT(_r, _s) do { \
    54      if (!(_r)) \
    55        ABORT("Out of memory: can't allocate %u bytes", (_s)); \
    56    } while (0)
    57  
    58  /* Magic tokens used to mark used / freed chunks. */
    59  
    60  #define ALLOC_MAGIC_C1  0xFF00FF00 /* Used head (dword)  */
    61  #define ALLOC_MAGIC_F   0xFE00FE00 /* Freed head (dword) */
    62  #define ALLOC_MAGIC_C2  0xF0       /* Used tail (byte)   */
    63  
    64  /* Positions of guard tokens in relation to the user-visible pointer. */
    65  
    66  #define ALLOC_C1(_ptr)  (((u32*)(_ptr))[-2])
    67  #define ALLOC_S(_ptr)   (((u32*)(_ptr))[-1])
    68  #define ALLOC_C2(_ptr)  (((u8*)(_ptr))[ALLOC_S(_ptr)])
    69  
    70  #define ALLOC_OFF_HEAD  8
    71  #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
    72  
    73  /* Allocator increments for ck_realloc_block(). */
    74  
    75  #define ALLOC_BLK_INC    256
    76  
    77  /* Sanity-checking macros for pointers. */
    78  
    79  #define CHECK_PTR(_p) do { \
    80      if (_p) { \
    81        if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
    82          if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
    83            ABORT("Use after free."); \
    84          else ABORT("Corrupted head alloc canary."); \
    85        } \
    86        if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
    87          ABORT("Corrupted tail alloc canary."); \
    88      } \
    89    } while (0)
    90  
    91  #define CHECK_PTR_EXPR(_p) ({ \
    92      typeof (_p) _tmp = (_p); \
    93      CHECK_PTR(_tmp); \
    94      _tmp; \
    95    })
    96  
    97  
    98  /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
    99     requests. */
   100  
   101  static inline void* DFL_ck_alloc_nozero(u32 size) {
   102  
   103    void* ret;
   104  
   105    if (!size) return NULL;
   106  
   107    ALLOC_CHECK_SIZE(size);
   108    ret = malloc(size + ALLOC_OFF_TOTAL);
   109    ALLOC_CHECK_RESULT(ret, size);
   110  
   111    ret += ALLOC_OFF_HEAD;
   112  
   113    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
   114    ALLOC_S(ret)  = size;
   115    ALLOC_C2(ret) = ALLOC_MAGIC_C2;
   116  
   117    return ret;
   118  
   119  }
   120  
   121  
   122  /* Allocate a buffer, returning zeroed memory. */
   123  
   124  static inline void* DFL_ck_alloc(u32 size) {
   125  
   126    void* mem;
   127  
   128    if (!size) return NULL;
   129    mem = DFL_ck_alloc_nozero(size);
   130  
   131    return memset(mem, 0, size);
   132  
   133  }
   134  
   135  
   136  /* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
   137     is set, the old memory will be also clobbered with 0xFF. */
   138  
   139  static inline void DFL_ck_free(void* mem) {
   140  
   141    if (!mem) return;
   142  
   143    CHECK_PTR(mem);
   144  
   145  #ifdef DEBUG_BUILD
   146  
   147    /* Catch pointer issues sooner. */
   148    memset(mem, 0xFF, ALLOC_S(mem));
   149  
   150  #endif /* DEBUG_BUILD */
   151  
   152    ALLOC_C1(mem) = ALLOC_MAGIC_F;
   153  
   154    free(mem - ALLOC_OFF_HEAD);
   155  
   156  }
   157  
   158  
   159  /* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
   160     With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
   161     old memory is clobbered with 0xFF. */
   162  
   163  static inline void* DFL_ck_realloc(void* orig, u32 size) {
   164  
   165    void* ret;
   166    u32   old_size = 0;
   167  
   168    if (!size) {
   169  
   170      DFL_ck_free(orig);
   171      return NULL;
   172  
   173    }
   174  
   175    if (orig) {
   176  
   177      CHECK_PTR(orig);
   178  
   179  #ifndef DEBUG_BUILD
   180      ALLOC_C1(orig) = ALLOC_MAGIC_F;
   181  #endif /* !DEBUG_BUILD */
   182  
   183      old_size  = ALLOC_S(orig);
   184      orig     -= ALLOC_OFF_HEAD;
   185  
   186      ALLOC_CHECK_SIZE(old_size);
   187  
   188    }
   189  
   190    ALLOC_CHECK_SIZE(size);
   191  
   192  #ifndef DEBUG_BUILD
   193  
   194    ret = realloc(orig, size + ALLOC_OFF_TOTAL);
   195    ALLOC_CHECK_RESULT(ret, size);
   196  
   197  #else
   198  
   199    /* Catch pointer issues sooner: force relocation and make sure that the
   200       original buffer is wiped. */
   201  
   202    ret = malloc(size + ALLOC_OFF_TOTAL);
   203    ALLOC_CHECK_RESULT(ret, size);
   204  
   205    if (orig) {
   206  
   207      memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
   208      memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
   209  
   210      ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
   211  
   212      free(orig);
   213  
   214    }
   215  
   216  #endif /* ^!DEBUG_BUILD */
   217  
   218    ret += ALLOC_OFF_HEAD;
   219  
   220    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
   221    ALLOC_S(ret)  = size;
   222    ALLOC_C2(ret) = ALLOC_MAGIC_C2;
   223  
   224    if (size > old_size)
   225      memset(ret + old_size, 0, size - old_size);
   226  
   227    return ret;
   228  
   229  }
   230  
   231  
   232  /* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
   233     repeated small reallocs without complicating the user code). */
   234  
   235  static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
   236  
   237  #ifndef DEBUG_BUILD
   238  
   239    if (orig) {
   240  
   241      CHECK_PTR(orig);
   242  
   243      if (ALLOC_S(orig) >= size) return orig;
   244  
   245      size += ALLOC_BLK_INC;
   246  
   247    }
   248  
   249  #endif /* !DEBUG_BUILD */
   250  
   251    return DFL_ck_realloc(orig, size);
   252  
   253  }
   254  
   255  
   256  /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
   257  
   258  static inline u8* DFL_ck_strdup(u8* str) {
   259  
   260    void* ret;
   261    u32   size;
   262  
   263    if (!str) return NULL;
   264  
   265    size = strlen((char*)str) + 1;
   266  
   267    ALLOC_CHECK_SIZE(size);
   268    ret = malloc(size + ALLOC_OFF_TOTAL);
   269    ALLOC_CHECK_RESULT(ret, size);
   270  
   271    ret += ALLOC_OFF_HEAD;
   272  
   273    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
   274    ALLOC_S(ret)  = size;
   275    ALLOC_C2(ret) = ALLOC_MAGIC_C2;
   276  
   277    return memcpy(ret, str, size);
   278  
   279  }
   280  
   281  
   282  /* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
   283     or NULL inputs. */
   284  
   285  static inline void* DFL_ck_memdup(void* mem, u32 size) {
   286  
   287    void* ret;
   288  
   289    if (!mem || !size) return NULL;
   290  
   291    ALLOC_CHECK_SIZE(size);
   292    ret = malloc(size + ALLOC_OFF_TOTAL);
   293    ALLOC_CHECK_RESULT(ret, size);
   294    
   295    ret += ALLOC_OFF_HEAD;
   296  
   297    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
   298    ALLOC_S(ret)  = size;
   299    ALLOC_C2(ret) = ALLOC_MAGIC_C2;
   300  
   301    return memcpy(ret, mem, size);
   302  
   303  }
   304  
   305  
   306  /* Create a buffer with a block of text, appending a NUL terminator at the end.
   307     Returns NULL for zero-sized or NULL inputs. */
   308  
   309  static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
   310  
   311    u8* ret;
   312  
   313    if (!mem || !size) return NULL;
   314  
   315    ALLOC_CHECK_SIZE(size);
   316    ret = malloc(size + ALLOC_OFF_TOTAL + 1);
   317    ALLOC_CHECK_RESULT(ret, size);
   318    
   319    ret += ALLOC_OFF_HEAD;
   320  
   321    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
   322    ALLOC_S(ret)  = size;
   323    ALLOC_C2(ret) = ALLOC_MAGIC_C2;
   324  
   325    memcpy(ret, mem, size);
   326    ret[size] = 0;
   327  
   328    return ret;
   329  
   330  }
   331  
   332  
   333  #ifndef DEBUG_BUILD
   334  
   335  /* In non-debug mode, we just do straightforward aliasing of the above functions
   336     to user-visible names such as ck_alloc(). */
   337  
   338  #define ck_alloc          DFL_ck_alloc
   339  #define ck_alloc_nozero   DFL_ck_alloc_nozero
   340  #define ck_realloc        DFL_ck_realloc
   341  #define ck_realloc_block  DFL_ck_realloc_block
   342  #define ck_strdup         DFL_ck_strdup
   343  #define ck_memdup         DFL_ck_memdup
   344  #define ck_memdup_str     DFL_ck_memdup_str
   345  #define ck_free           DFL_ck_free
   346  
   347  #define alloc_report()
   348  
   349  #else
   350  
   351  /* In debugging mode, we also track allocations to detect memory leaks, and the
   352     flow goes through one more layer of indirection. */
   353  
   354  /* Alloc tracking data structures: */
   355  
   356  #define ALLOC_BUCKETS     4096
   357  
   358  struct TRK_obj {
   359    void *ptr;
   360    char *file, *func;
   361    u32  line;
   362  };
   363  
   364  #ifdef AFL_MAIN
   365  
   366  struct TRK_obj* TRK[ALLOC_BUCKETS];
   367  u32 TRK_cnt[ALLOC_BUCKETS];
   368  
   369  #  define alloc_report() TRK_report()
   370  
   371  #else
   372  
   373  extern struct TRK_obj* TRK[ALLOC_BUCKETS];
   374  extern u32 TRK_cnt[ALLOC_BUCKETS];
   375  
   376  #  define alloc_report()
   377  
   378  #endif /* ^AFL_MAIN */
   379  
   380  /* Bucket-assigning function for a given pointer: */
   381  
   382  #define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
   383  
   384  
   385  /* Add a new entry to the list of allocated objects. */
   386  
   387  static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
   388                                   u32 line) {
   389  
   390    u32 i, bucket;
   391  
   392    if (!ptr) return;
   393  
   394    bucket = TRKH(ptr);
   395  
   396    /* Find a free slot in the list of entries for that bucket. */
   397  
   398    for (i = 0; i < TRK_cnt[bucket]; i++)
   399  
   400      if (!TRK[bucket][i].ptr) {
   401  
   402        TRK[bucket][i].ptr  = ptr;
   403        TRK[bucket][i].file = (char*)file;
   404        TRK[bucket][i].func = (char*)func;
   405        TRK[bucket][i].line = line;
   406        return;
   407  
   408      }
   409  
   410    /* No space available - allocate more. */
   411  
   412    TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
   413      (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
   414  
   415    TRK[bucket][i].ptr  = ptr;
   416    TRK[bucket][i].file = (char*)file;
   417    TRK[bucket][i].func = (char*)func;
   418    TRK[bucket][i].line = line;
   419  
   420    TRK_cnt[bucket]++;
   421  
   422  }
   423  
   424  
   425  /* Remove entry from the list of allocated objects. */
   426  
   427  static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
   428                                  u32 line) {
   429  
   430    u32 i, bucket;
   431  
   432    if (!ptr) return;
   433  
   434    bucket = TRKH(ptr);
   435  
   436    /* Find the element on the list... */
   437  
   438    for (i = 0; i < TRK_cnt[bucket]; i++)
   439  
   440      if (TRK[bucket][i].ptr == ptr) {
   441  
   442        TRK[bucket][i].ptr = 0;
   443        return;
   444  
   445      }
   446  
   447    WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
   448          func, file, line);
   449  
   450  }
   451  
   452  
   453  /* Do a final report on all non-deallocated objects. */
   454  
   455  static inline void TRK_report(void) {
   456  
   457    u32 i, bucket;
   458  
   459    fflush(0);
   460  
   461    for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
   462      for (i = 0; i < TRK_cnt[bucket]; i++)
   463        if (TRK[bucket][i].ptr)
   464          WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
   465                TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
   466  
   467  }
   468  
   469  
   470  /* Simple wrappers for non-debugging functions: */
   471  
   472  static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
   473                                   u32 line) {
   474  
   475    void* ret = DFL_ck_alloc(size);
   476    TRK_alloc_buf(ret, file, func, line);
   477    return ret;
   478  
   479  }
   480  
   481  
   482  static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
   483                                     const char* func, u32 line) {
   484  
   485    void* ret = DFL_ck_realloc(orig, size);
   486    TRK_free_buf(orig, file, func, line);
   487    TRK_alloc_buf(ret, file, func, line);
   488    return ret;
   489  
   490  }
   491  
   492  
   493  static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
   494                                           const char* func, u32 line) {
   495  
   496    void* ret = DFL_ck_realloc_block(orig, size);
   497    TRK_free_buf(orig, file, func, line);
   498    TRK_alloc_buf(ret, file, func, line);
   499    return ret;
   500  
   501  }
   502  
   503  
   504  static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
   505                                    u32 line) {
   506  
   507    void* ret = DFL_ck_strdup(str);
   508    TRK_alloc_buf(ret, file, func, line);
   509    return ret;
   510  
   511  }
   512  
   513  
   514  static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
   515                                    const char* func, u32 line) {
   516  
   517    void* ret = DFL_ck_memdup(mem, size);
   518    TRK_alloc_buf(ret, file, func, line);
   519    return ret;
   520  
   521  }
   522  
   523  
   524  static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
   525                                        const char* func, u32 line) {
   526  
   527    void* ret = DFL_ck_memdup_str(mem, size);
   528    TRK_alloc_buf(ret, file, func, line);
   529    return ret;
   530  
   531  }
   532  
   533  
   534  static inline void TRK_ck_free(void* ptr, const char* file,
   535                                  const char* func, u32 line) {
   536  
   537    TRK_free_buf(ptr, file, func, line);
   538    DFL_ck_free(ptr);
   539  
   540  }
   541  
   542  /* Aliasing user-facing names to tracking functions: */
   543  
   544  #define ck_alloc(_p1) \
   545    TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
   546  
   547  #define ck_alloc_nozero(_p1) \
   548    TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
   549  
   550  #define ck_realloc(_p1, _p2) \
   551    TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
   552  
   553  #define ck_realloc_block(_p1, _p2) \
   554    TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
   555  
   556  #define ck_strdup(_p1) \
   557    TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
   558  
   559  #define ck_memdup(_p1, _p2) \
   560    TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
   561  
   562  #define ck_memdup_str(_p1, _p2) \
   563    TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
   564  
   565  #define ck_free(_p1) \
   566    TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
   567  
   568  #endif /* ^!DEBUG_BUILD */
   569  
   570  #endif /* ! _HAVE_ALLOC_INL_H */