#ifndef FLAC__SHARE__ALLOC_H
#define FLAC__SHARE__ALLOC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <limits.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdlib.h>
#include "share/compat.h"
#ifndef SIZE_MAX
# ifndef SIZE_T_MAX
# ifdef _MSC_VER
# ifdef _WIN64
# define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff)
# else
# define SIZE_T_MAX 0xffffffff
# endif
# else
# error
# endif
# endif
# define SIZE_MAX SIZE_T_MAX
#endif
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
extern int alloc_check_threshold, alloc_check_counter, alloc_check_keep_failing;
static inline int alloc_check(void) {
if(alloc_check_threshold == INT32_MAX)
return 0;
else if(alloc_check_counter++ == alloc_check_threshold)
return 1;
else if(alloc_check_keep_failing && (alloc_check_counter > alloc_check_threshold))
return 1;
else {
return 0;
}
}
#endif
static inline void *safe_malloc_(size_t size)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(alloc_check())
return NULL;
#endif
if(!size)
size++;
return malloc(size);
}
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static inline void *malloc_(size_t size)
{
if(alloc_check())
return NULL;
return malloc(size);
}
#else
#define malloc_ malloc
#endif
static inline void *safe_calloc_(size_t nmemb, size_t size)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(alloc_check())
return NULL;
#endif
if(!nmemb || !size)
return malloc(1);
return calloc(nmemb, size);
}
static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
{
size2 += size1;
if(size2 < size1)
return 0;
return safe_malloc_(size2);
}
static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
return safe_malloc_(size3);
}
static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
size4 += size3;
if(size4 < size3)
return 0;
return safe_malloc_(size4);
}
void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || !size2 || !size3)
return malloc(1);
if(size1 > SIZE_MAX / size2)
return 0;
size1 *= size2;
if(size1 > SIZE_MAX / size3)
return 0;
return malloc_(size1*size3);
}
static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || !size2)
return safe_malloc_(size3);
if(size1 > SIZE_MAX / size2)
return 0;
return safe_malloc_add_2op_(size1*size2, size3);
}
static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
{
if(!size1 || (!size2 && !size3))
return malloc(1);
size2 += size3;
if(size2 < size3)
return 0;
if(size1 > SIZE_MAX / size2)
return 0;
return malloc_(size1*size2);
}
static inline void *safe_realloc_(void *ptr, size_t size)
{
void *oldptr;
void *newptr;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if(alloc_check() && size > 0) {
free(ptr);
return NULL;
}
#endif
oldptr = ptr;
newptr = realloc(ptr, size);
if(size > 0 && newptr == 0)
free(oldptr);
return newptr;
}
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static inline void *realloc_(void *ptr, size_t size)
{
if(alloc_check())
return NULL;
return realloc(ptr, size);
}
#else
#define realloc_ realloc
#endif
static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2)
{
size2 += size1;
if(size2 < size1)
return 0;
return realloc_(ptr, size2);
}
static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
{
size2 += size1;
if(size2 < size1) {
free(ptr);
return 0;
}
size3 += size2;
if(size3 < size2) {
free(ptr);
return 0;
}
return safe_realloc_(ptr, size3);
}
static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
return realloc_(ptr, size3);
}
static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
{
size2 += size1;
if(size2 < size1)
return 0;
size3 += size2;
if(size3 < size2)
return 0;
size4 += size3;
if(size4 < size3)
return 0;
return realloc_(ptr, size4);
}
static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
{
if(!size1 || !size2)
return realloc(ptr, 0);
if(size1 > SIZE_MAX / size2) {
free(ptr);
return 0;
}
return safe_realloc_(ptr, size1*size2);
}
static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t size2)
{
if(!size1 || !size2)
return realloc(ptr, 0);
if(size1 > SIZE_MAX / size2)
return 0;
return realloc_(ptr, size1*size2);
}
static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
{
if(!size1 || (!size2 && !size3))
return realloc(ptr, 0);
size2 += size3;
if(size2 < size3) {
free(ptr);
return 0;
}
return safe_realloc_mul_2op_(ptr, size1, size2);
}
static inline void *safe_realloc_nofree_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
{
if(!size1 || (!size2 && !size3))
return realloc(ptr, 0);
size2 += size3;
if(size2 < size3)
return 0;
return safe_realloc_nofree_mul_2op_(ptr, size1, size2);
}
#endif