/*
  Copyright 2013 Google LLC All rights reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at:

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
   american fuzzy lop - error-checking, memory-zeroing alloc routines
   ------------------------------------------------------------------

   Written and maintained by Michal Zalewski <lcamtuf@google.com>

   This allocator is not designed to resist malicious attackers (the canaries
   are small and predictable), but provides a robust and portable way to detect
   use-after-free, off-by-one writes, stale pointers, and so on.
*/

#ifndef _HAVE_ALLOC_INL_H
#define _HAVE_ALLOC_INL_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "types.h"
#include "debug.h"

/* 提供给用户使用的宏，用于将sprintf()的输出到一个动态分配的缓冲区。 */
#define alloc_printf(_str...) ({ \
    u8* _tmp; \
    s32 _len = snprintf(NULL, 0, _str); \
    if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
    _tmp = ck_alloc(_len + 1); \
    snprintf((char*)_tmp, _len + 1, _str); \
    _tmp; \
  })

/* 宏，用于强制执行分配限制，作为防止整数溢出的最后一道防线。 */
#define ALLOC_CHECK_SIZE(_s) do { \
    if ((_s) > MAX_ALLOC) \
      ABORT("Bad alloc request: %u bytes", (_s)); \
  } while (0)

/* 宏，用于检查malloc()失败等情况。 */
#define ALLOC_CHECK_RESULT(_r, _s) do { \
    if (!(_r)) \
      ABORT("Out of memory: can't allocate %u bytes", (_s)); \
  } while (0)

/* 用于标记已使用/已释放块的魔术标记。 */
#define ALLOC_MAGIC_C1  0xFF00FF00 /* 已使用头部（双字） */
#define ALLOC_MAGIC_F   0xFE00FE00 /* 已释放头部（双字） */
#define ALLOC_MAGIC_C2  0xF0       /* 已使用尾部（字节） */

/* 与用户可见指针相关的保护标记的位置。 */
#define ALLOC_C1(_ptr)  (((u32*)(_ptr))[-2])
#define ALLOC_S(_ptr)   (((u32*)(_ptr))[-1])
#define ALLOC_C2(_ptr)  (((u8*)(_ptr))[ALLOC_S(_ptr)])

#define ALLOC_OFF_HEAD  8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)

/* ck_realloc_block()的分配器增量。 */
#define ALLOC_BLK_INC    256

/* 用于指针的合理性检查宏。 */
#define CHECK_PTR(_p) do { \
    if (_p) { \
      if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
        if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
          ABORT("Use after free."); \
        else ABORT("Corrupted head alloc canary."); \
      } \
      if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
        ABORT("Corrupted tail alloc canary."); \
    } \
  } while (0)

#define CHECK_PTR_EXPR(_p) ({ \
    typeof (_p) _tmp = (_p); \
    CHECK_PTR(_tmp); \
    _tmp; \
  })

/* 分配一个缓冲区，明确不将其清零。对于零大小的请求返回NULL。 */
static inline void* DFL_ck_alloc_nozero(u32 size) {

    void* ret;

    if (!size) return NULL;

    ALLOC_CHECK_SIZE(size);
    ret = malloc(size + ALLOC_OFF_TOTAL);
    ALLOC_CHECK_RESULT(ret, size);

    ret += ALLOC_OFF_HEAD;

    ALLOC_C1(ret) = ALLOC_MAGIC_C1;
    ALLOC_S(ret) = size;
    ALLOC_C2(ret) = ALLOC_MAGIC_C2;

    return ret;

}

/* 分配一个缓冲区，返回清零后的内存。 */
static inline void* DFL_ck_alloc(u32 size) {

    void* mem;

    if (!size) return NULL;
    mem = DFL_ck_alloc_nozero(size);

    return memset(mem, 0, size);

}


/* 释放内存，检查是否重复释放和堆损坏。当DEBUG_BUILD被设置时，
   旧内存也会被0xFF覆盖。 */
static inline void DFL_ck_free(void* mem) {
    if (!mem) return; /* 如果指针为空，不执行任何操作 */

    CHECK_PTR(mem); /* 检查是否重复释放和堆损坏 */

#ifdef DEBUG_BUILD /* 如果是调试构建，用0xFF覆盖内存 */
    /* 尽早捕捉指针问题。 */
    memset(mem, 0xFF, ALLOC_S(mem)); /* 用0xFF覆盖内存 */
#endif /* DEBUG_BUILD */

    ALLOC_C1(mem) = ALLOC_MAGIC_F; /* 标记内存为已释放 */

    free(mem - ALLOC_OFF_HEAD); /* 释放内存，调整头偏移 */
}

/* 重新分配缓冲区，检查问题并清零任何新添加的尾部。
   在DEBUG_BUILD下，缓冲区总是被重新分配到新地址，旧内存被0xFF覆盖。 */
static inline void* DFL_ck_realloc(void* orig, u32 size) {
    void* ret;
    u32 old_size = 0;

    if (!size) {
        DFL_ck_free(orig); /* 如果新大小为0，释放原始内存 */
        return NULL;
    }

    if (orig) {
        CHECK_PTR(orig); /* 检查是否重复释放和堆损坏 */

#ifndef DEBUG_BUILD /* 在非调试构建中，可以重用内存 */
        ALLOC_C1(orig) = ALLOC_MAGIC_F; /* 标记内存为已释放 */
#endif /* !DEBUG_BUILD */

        old_size = ALLOC_S(orig); /* 获取原始大小 */
        orig -= ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */

        ALLOC_CHECK_SIZE(old_size); /* 检查原始大小是否有效 */
    }

    ALLOC_CHECK_SIZE(size); /* 检查新大小是否有效 */

#ifndef DEBUG_BUILD /* 在非调试构建中，尝试原地调整内存大小 */
    ret = realloc(orig, size + ALLOC_OFF_TOTAL); /* 重新分配内存 */
    ALLOC_CHECK_RESULT(ret, size); /* 检查重新分配是否成功 */
#else /* 在调试构建中，总是分配新内存并清除旧内存 */
    /* 尽早捕捉指针问题：强制重新定位，并确保旧缓冲区被清除。 */

    ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配新内存 */
    ALLOC_CHECK_RESULT(ret, size); /* 检查分配是否成功 */

    if (orig) {
        memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size)); /* 将数据复制到新内存 */
        memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size); /* 用0xFF覆盖旧内存 */
        ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; /* 标记旧内存为已释放 */
        free(orig); /* 释放旧内存 */
    }
#endif /* ^!DEBUG_BUILD */

    ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */

    ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 标记内存为已使用 */
    ALLOC_S(ret) = size; /* 存储内存块的大小 */
    ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 标记内存块的结尾 */

    if (size > old_size) /* 如果新大小更大，清零新的尾部 */
        memset(ret + old_size, 0, size - old_size);

    return ret; /* 返回（可能新的）内存块 */
}


/* 以ALLOC_BLK_INC的增量重新分配缓冲区（用于加速重复的小realloc操作，而不需要复杂化用户代码）。 */
static inline void* DFL_ck_realloc_block(void* orig, u32 size) {

#ifndef DEBUG_BUILD

    if (orig) {

        CHECK_PTR(orig); /* 检查原始指针是否有效 */

        if (ALLOC_S(orig) >= size) return orig; /* 如果当前大小已满足需求，则不进行realloc */

        size += ALLOC_BLK_INC; /* 增加ALLOC_BLK_INC，以减少频繁的小realloc操作 */

    }

#endif /* !DEBUG_BUILD */

    return DFL_ck_realloc(orig, size); /* 调用DFL_ck_realloc进行实际的realloc操作 */

}

/* 创建一个包含字符串副本的缓冲区。对于NULL输入返回NULL。 */
static inline u8* DFL_ck_strdup(u8* str) {

    void* ret;
    u32 size;

    if (!str) return NULL; /* 如果输入字符串为空，则返回NULL */

    size = strlen((char*)str) + 1; /* 计算字符串长度加1（为'\0'留空间） */

    ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
    ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配内存 */
    ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */

    ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */

    ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
    ALLOC_S(ret) = size; /* 存储分配的大小 */
    ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */

    return memcpy(ret, str, size); /* 复制字符串并返回新指针 */

}

/* 创建一个包含内存块副本的缓冲区。对于零大小或NULL输入返回NULL。 */
static inline void* DFL_ck_memdup(void* mem, u32 size) {

    void* ret;

    if (!mem || !size) return NULL; /* 如果内存块为空或大小为零，则返回NULL */

    ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
    ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配内存 */
    ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */

    ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */

    ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
    ALLOC_S(ret) = size; /* 存储分配的大小 */
    ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */

    return memcpy(ret, mem, size); /* 复制内存块并返回新指针 */

}

/* 创建一个包含文本块的缓冲区，并在末尾追加NUL终止符。对于零大小或NULL输入返回NULL。 */
static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {

    u8* ret;

    if (!mem || !size) return NULL; /* 如果内存块为空或大小为零，则返回NULL */

    ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
    ret = malloc(size + ALLOC_OFF_TOTAL + 1); /* 分配内存，额外+1用于NUL终止符 */
    ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */

    ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */

    ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
    ALLOC_S(ret) = size; /* 存储分配的大小 */
    ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */

    memcpy(ret, mem, size); /* 复制内存块 */
    ret[size] = 0; /* 设置NUL终止符 */

    return ret; /* 返回新指针 */

}

#ifndef DEBUG_BUILD

/* 在非调试模式下，我们直接将上述函数别名为用户可见的名称，如ck_alloc()。 */

#define ck_alloc          DFL_ck_alloc
#define ck_alloc_nozero   DFL_ck_alloc_nozero
#define ck_realloc        DFL_ck_realloc
#define ck_realloc_block  DFL_ck_realloc_block
#define ck_strdup         DFL_ck_strdup
#define ck_memdup         DFL_ck_memdup
#define ck_memdup_str     DFL_ck_memdup_str
#define ck_free           DFL_ck_free

#define alloc_report()

#else

/* 在调试模式下，我们还跟踪内存分配以检测内存泄漏，这个过程会经历更多的间接层。 */

/* 分配跟踪数据结构： */

#define ALLOC_BUCKETS     4096 /* 定义分配桶的数量 */

struct TRK_obj {
    void* ptr; /* 指向分配的内存块 */
    char* file, * func; /* 分配时的文件名和函数名 */
    u32  line; /* 分配时的代码行号 */
};

#ifdef AFL_MAIN

struct TRK_obj* TRK[ALLOC_BUCKETS]; /* 跟踪分配的内存对象数组 */
u32 TRK_cnt[ALLOC_BUCKETS]; /* 每个桶中跟踪对象的数量 */

#  define alloc_report() TRK_report() /* 定义alloc_report宏为TRK_report函数 */

#else

extern struct TRK_obj* TRK[ALLOC_BUCKETS]; /* 外部声明跟踪分配的内存对象数组 */
extern u32 TRK_cnt[ALLOC_BUCKETS]; /* 外部声明每个桶中跟踪对象的数量 */

#  define alloc_report() /* 在非AFL_MAIN环境下，alloc_report宏为空 */

#endif /* ^AFL_MAIN */

/* 为给定指针分配桶的函数： */

#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS) /* 定义桶分配宏 */

/* 将新分配的内存对象添加到跟踪列表中。 */

static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
    u32 line) {
    u32 i, bucket;

    if (!ptr) return; /* 如果指针为空，则返回 */

    bucket = TRKH(ptr); /* 获取桶编号 */

    /* 在该桶的条目列表中找到一个空闲位置。 */

    for (i = 0; i < TRK_cnt[bucket]; i++)
        if (!TRK[bucket][i].ptr) { /* 如果找到空闲位置 */
            TRK[bucket][i].ptr = ptr;
            TRK[bucket][i].file = (char*)file;
            TRK[bucket][i].func = (char*)func;
            TRK[bucket][i].line = line;
            return;
        }

    /* 没有可用空间 - 分配更多空间。 */

    TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
        (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); /* 重新分配桶的大小 */

    TRK[bucket][i].ptr = ptr;
    TRK[bucket][i].file = (char*)file;
    TRK[bucket][i].func = (char*)func;
    TRK[bucket][i].line = line;

    TRK_cnt[bucket]++; /* 更新桶中条目的数量 */
}

/* 从分配的内存对象列表中移除条目。 */

static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
    u32 line) {
    u32 i, bucket;

    if (!ptr) return; /* 如果指针为空，则返回 */

    bucket = TRKH(ptr); /* 获取桶编号 */

    /* 在列表中找到该元素... */

    for (i = 0; i < TRK_cnt[bucket]; i++)
        if (TRK[bucket][i].ptr == ptr) { /* 如果找到匹配的指针 */
            TRK[bucket][i].ptr = 0; /* 将指针设置为NULL */
            return;
        }

    WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
        func, file, line); /* 警告：尝试释放未分配的内存 */
}

/* 对所有未释放的对象进行最终报告。 */

static inline void TRK_report(void) {
    u32 i, bucket;

    fflush(0); /* 清空输出缓冲区 */

    for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
        for (i = 0; i < TRK_cnt[bucket]; i++)
            if (TRK[bucket][i].ptr) /* 如果指针不为空 */
                WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
                    TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line); /* 警告：内存从未释放 */
}

/* 非调试函数的简单包装器： */

static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
    u32 line) {
    void* ret = DFL_ck_alloc(size); /* 分配内存 */
    TRK_alloc_buf(ret, file, func, line); /* 添加到跟踪列表 */
    return ret;
}

static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
    const char* func, u32 line) {
    void* ret = DFL_ck_realloc(orig, size); /* 重新分配内存 */
    TRK_free_buf(orig, file, func, line); /* 从跟踪列表中移除 */
    TRK_alloc_buf(ret, file, func, line); /* 添加到跟踪列表 */
    return ret;
}


/* 重新分配内存块，同时更新跟踪信息。 */
static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
    const char* func, u32 line) {
    void* ret = DFL_ck_realloc_block(orig, size); /* 调用DFL_ck_realloc_block重新分配内存 */
    TRK_free_buf(orig, file, func, line); /* 从跟踪列表中移除原始内存块 */
    TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
    return ret; /* 返回新内存块 */
}

/* 复制字符串并分配内存，同时更新跟踪信息。 */
static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
    u32 line) {
    void* ret = DFL_ck_strdup(str); /* 调用DFL_ck_strdup复制字符串 */
    TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
    return ret; /* 返回新内存块 */
}

/* 复制内存块并分配内存，同时更新跟踪信息。 */
static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
    const char* func, u32 line) {
    void* ret = DFL_ck_memdup(mem, size); /* 调用DFL_ck_memdup复制内存块 */
    TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
    return ret; /* 返回新内存块 */
}

/* 复制内存块并添加字符串终止符，同时更新跟踪信息。 */
static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
    const char* func, u32 line) {
    void* ret = DFL_ck_memdup_str(mem, size); /* 调用DFL_ck_memdup_str复制内存块并添加终止符 */
    TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
    return ret; /* 返回新内存块 */
}

/* 释放内存并更新跟踪信息。 */
static inline void TRK_ck_free(void* ptr, const char* file,
    const char* func, u32 line) {
    TRK_free_buf(ptr, file, func, line); /* 从跟踪列表中移除内存块 */
    DFL_ck_free(ptr); /* 释放内存块 */
}

/* 将用户可见的名称别名为跟踪函数： */

#define ck_alloc(_p1) \
  TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_alloc宏为TRK_ck_alloc */

#define ck_alloc_nozero(_p1) \
  TRK_ck_alloc_nozero(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_alloc_nozero宏为TRK_ck_alloc_nozero */

#define ck_realloc(_p1, _p2) \
  TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_realloc宏为TRK_ck_realloc */

#define ck_realloc_block(_p1, _p2) \
  TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_realloc_block宏为TRK_ck_realloc_block */

#define ck_strdup(_p1) \
  TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_strdup宏为TRK_ck_strdup */

#define ck_memdup(_p1, _p2) \
  TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_memdup宏为TRK_ck_memdup */

#define ck_memdup_str(_p1, _p2) \
  TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_memdup_str宏为TRK_ck_memdup_str */

#define ck_free(_p1) \
  TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_free宏为TRK_ck_free */

#endif /* ^!DEBUG_BUILD */
#endif /* ! _HAVE_ALLOC_INL_H */
