gcc Function Attributes alloc_size
ddatsh
基于 11965 里面的 示例代码
gcc 12 +
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct a {
char c;
char buf[];
};
int main() {
const int BUFSIZE = 5;
struct a *a = malloc(sizeof(*a) + BUFSIZE);
printf("sizeof(struct a)=%zu \n", sizeof(struct a));
printf("sizeof(*a)=%zu \n", sizeof(*a));
size_t n = malloc_usable_size(a);
printf("a usable size=%zu \n", n);
// Dummy condition to prevent compiler throw warning on compile time
// n will always be n >= BUFSIZE
size_t copy = n >= BUFSIZE ? BUFSIZE + 3 : BUFSIZE;
memcpy(a->buf, "12345678", copy);
printf("%.*s \n", (int) copy, (char*) a->buf);
return 0;
}
gcc main.c
./a.out
“正常” 运行了
sizeof(struct a)=1
sizeof(*a)=1
a usable size=24
12345678
ida反编译
上点强度就报错了
gcc -O2 -Wall -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 main.c
或者直接 gcc -O2也一样
sizeof(struct a)=1
sizeof(*a)=1
a usable size=24
*** buffer overflow detected ***: terminated
Aborted (core dumped)
仿 redis 之 attribute alloc_size
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct a {
char c;
char buf[];
};
#define UNUSED(x) ((void)(x))
__attribute__((alloc_size(2), noinline)) void *extend_to_usable(void *ptr, size_t size) {
UNUSED(size);
return ptr;
}
int main() {
const int BUFSIZE = 5;
struct a *a = malloc(sizeof(*a) + BUFSIZE);
printf("sizeof(struct a):%zu \n", sizeof(struct a));
printf("sizeof(*a):%zu \n", sizeof(*a));
size_t n = malloc_usable_size(a);
printf("a usable size: %zu \n", n);
// Dummy condition to prevent compiler throw warning on compile time
// n will always be n >= BUFSIZE
size_t copy = n >= BUFSIZE ? BUFSIZE + 3 : BUFSIZE;
a=extend_to_usable(a, n);
memcpy(a->buf, "12345678", copy);
printf("%.*s \n", (int) copy, (char*) a->buf);
return 0;
}
#define UNUSED(x) ((void)(x))
此宏可以强制的产生一个对该变量的使用操作, 从而消除编译器产生的”unused variable”警告
malloc_size
malloc内存分配时的内存对齐,实际分配的内存空间大小与申请的空间大小可能并不一致, 可能比申请的空间大。得知具体的空间大小后, 在 Redis 中, SDS 库借助于此机制调整 alloc 变量的取值, 从而减少不必要的内存分配
extend_to_usable
是一个纯声明性质的函数, 通过alloc_size(2)
属性标记, 向编译器表明这个函数的第二个参数是 ptr 执行的内存空间的实际大小
此函数通常与malloc_size
函数配合使用, 通过malloc_size
函数获取实际分配的内存空间大小后, 使用extend_to_usable
函数向编译器声明后续代码会按照实际分配的空间大小使用
FORTIFY_SOURCE
-
3 在 2 的基础上,可以对 malloc 出来的内存进行检测 (gcc> 12)
-
2 在 1 的基础上,可以对栈变量进行检测
-
1 在编译时进行检测
-
优化等级必须要大于 O2 这个选项才会生效