我正在尝试在每个已分配的块的最后添加一个保护字符,以便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
,{{1} }和malloc
。
calloc
答案 0 :(得分:0)
您正在使用位于分配区域之前的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
}
你最终会被保护字符覆盖 next 区域的长度。解决方案是以字节为单位减去长度字段的长度,即改为使用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);
}
}
希望这有帮助。