我试图在每个分配 block 的末尾添加一个保护字符,以便如果找不到它,free()
可以abort()
。为什么这些函数预加载不起作用?我意识到这不是一个可移植的方法,但我很好奇为什么它不起作用。
gcc -shared -fPIC -std=gnu99 -O2 -o wrapper.so wrapper.c
LD_PRELOAD=/path/to/wrapper.so programname
我对每个函数都有一个函数:valloc
、realloc
、pvalloc
、posix_memalign
、aligned_alloc
、memalign
、malloc
和 calloc
。
#define PREV_INUSE 0x1
#define IS_MMAPPED 0x2
#define NON_MAIN_ARENA 0x4
#define SIZE_BITS (PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA)
extern void *__libc_malloc(size_t size);
void *malloc(size_t size){
size = size + 1; // add char for guard byte '@'
void *p = __libc_malloc(size);
if(p != NULL){
size_t *q = p;
q--;
size_t s = *q & ~(SIZE_BITS); // get allocated bytes subtracting info bits
char *z = p;
memset(z, 0, s); // zero memory
z[s - 1] = '@'; // place guard char
}
return p;
}
extern void *__libc_free(void *ptr);
void free(void *ptr){
if(ptr != NULL){
size_t *p = ptr;
p--;
size_t s = *p & ~(SIZE_BITS);
char *z = ptr;
if(z[s - 1] != '@') // if guard char not found, abort()
{
abort();
}
memset(z, 0, s); // zero memory
}
__libc_free(ptr);
}
最佳答案
您正在使用size_t
位于分配区域之前,作为可用长度。但是,它包括size_t
本身。因此,这里:
if (p != NULL) {
size_t *q = p;
q--;
size_t s = *q & ~(SIZE_BITS); // get allocated bytes subtracting info bits
char *z = p;
memset(z, 0, s); // zero memory
z[s - 1] = '@'; // place guard char
}
您最终会通过保护字符部分覆盖下一个区域的长度。解决方案是减去长度字段的长度(以字节为单位),即使用 const s = (((size_t *)p)[-1] & (~(size_t)SIZE_BITS)) - sizeof (size_t);
相反。
(我在 x86-64 上的嵌入式 GNU C 库 2.15-0ubuntu10.15 上验证了此方法适用于 64 位和 32 位代码(具有不同的 size_t
大小)。)
我建议您至少添加最少的抽象,这样将来将代码移植到不同的 C 库或更新版本的 GNU C 库就不会徒劳。 (版本检查会很好,但我懒得去找出哪些版本的 GNU C 库实际上使用了这个布局。)
#include <string.h>
#include <limits.h>
#ifdef __GLIBC__
/* GLIBC stuffs the length just prior to the returned pointer,
* with flags in the least significant three bits. It includes
* the length field itself. */
#define USER_LEN(ptr) ( ( ((size_t *)(ptr))[-1] & (~((size_t)7)) ) - sizeof (size_t))
#else
#error This C library is not supported (yet).
#endif
extern void abort(void);
extern void *__libc_malloc(size_t);
extern void *__libc_realloc(void *, size_t);
extern void __libc_free(void *);
#define CANARY_LEN 1
static void canary_set(void *const ptr, const size_t len)
{
((unsigned char *)ptr)[len - CANARY_LEN] = '@';
}
static int canary_ok(const void *const ptr, const size_t len)
{
return ((const unsigned char *)ptr)[len - CANARY_LEN] == '@';
}
void *malloc(size_t size)
{
void *ptr;
ptr = __libc_malloc(size + CANARY_LEN);
if (ptr) {
const size_t len = USER_LEN(ptr);
memset(ptr, 0, len);
canary_set(ptr, len);
}
return ptr;
}
void *realloc(void *ptr, size_t size)
{
void *newptr;
if (!ptr)
return malloc(size);
if (!canary_ok(ptr, USER_LEN(ptr)))
abort();
newptr = __libc_realloc(ptr, size + CANARY_LEN);
if (!newptr)
return newptr;
canary_set(newptr, USER_LEN(ptr));
return newptr;
}
void free(void *ptr)
{
if (ptr) {
const size_t len = USER_LEN(ptr);
if (!canary_ok(ptr, len))
abort();
memset(ptr, 0, len);
__libc_free(ptr);
}
}
希望这有帮助。
关于c - glibc malloc 保护字节包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23108020/