结构分配:段错误 11
struct assignment: segment fault 11
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union value {
long long i;
unsigned long long u;
double d;
long double ld;
void *p;
void (*g) ();
};
struct foo {
struct {
union value max;
union value min;
}limits;
};
struct bucket_info {
void *p; // free position
void *limit; // end position
struct bucket_info *next; // next bucket
};
#define NODES 8192
void * my_malloc(size_t size)
{
void *p = malloc(size);
if (!p)
exit(1);
memset(p, 0, size);
return p;
}
void * alloc_bucket(size_t size)
{
struct bucket_info *pb;
pb = my_malloc(sizeof(struct bucket_info) + size);
pb->p = pb + 1;
pb->limit = (char *)pb->p + size;
return pb;
}
void * alloc_for_size(struct bucket_info *s, size_t size)
{
void *ret;
while (s->next)
s = s->next;
if ((char *)s->p + size > (char *)s->limit) {
struct bucket_info *pb = alloc_bucket(size * NODES);
s->next = pb;
s = pb;
}
ret = s->p;
s->p = (char *)s->p + size;
return ret;
}
static void * alloc_node(struct bucket_info **s, size_t size)
{
if (!*s)
*s = alloc_bucket(size * NODES);
return alloc_for_size(*s, size);
}
static struct bucket_info *foo_info;
void * alloc_foo_node()
{
void *ret = alloc_node(&foo_info, sizeof(struct foo));
return ret;
}
struct foo * new_foo()
{
return alloc_foo_node();
}
void test(int t, struct foo *foo1)
{
struct foo *foo2 = new_foo();
// Crash at this line
*foo2 = *foo1;
// comment this switch statement, it works. why?
switch (t) {
case 1:
break;
default:
break;
}
}
int main(int argc, const char * argv[]) {
struct foo *foo1 = new_foo();
test(10, foo1);
return 0;
}
以上是完整的代码。我用 clang 编译了它,在行中得到了一个 'Segment Fault 11':
*foo2 = *foo1;
然后,将此行更改为:
memcpy(foo2, foo1, sizeof(struct Foo));
有效。
那我试过用gcc编译这两个case,没有问题。
alloc_foo_node
返回的值可能没有与 struct foo
正确对齐。
在我的系统上,打印 _Alignof(struct foo)
得到 16
,但指针 foo1
和 foo2
不是 16
的倍数。
所以它导致未定义的行为将 alloc_foo_node
的未对齐结果转换为具有类型 struct foo *
.
要解决此问题,您必须对分配代码进行更多处理,以确保它只会分发 space,它位于 struct foo
的正确边界上。您可以使用 max_align_t
来帮助解决这个问题(它被定义为 _Alignof(max_align_t)
是所需的最大可能对齐)。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union value {
long long i;
unsigned long long u;
double d;
long double ld;
void *p;
void (*g) ();
};
struct foo {
struct {
union value max;
union value min;
}limits;
};
struct bucket_info {
void *p; // free position
void *limit; // end position
struct bucket_info *next; // next bucket
};
#define NODES 8192
void * my_malloc(size_t size)
{
void *p = malloc(size);
if (!p)
exit(1);
memset(p, 0, size);
return p;
}
void * alloc_bucket(size_t size)
{
struct bucket_info *pb;
pb = my_malloc(sizeof(struct bucket_info) + size);
pb->p = pb + 1;
pb->limit = (char *)pb->p + size;
return pb;
}
void * alloc_for_size(struct bucket_info *s, size_t size)
{
void *ret;
while (s->next)
s = s->next;
if ((char *)s->p + size > (char *)s->limit) {
struct bucket_info *pb = alloc_bucket(size * NODES);
s->next = pb;
s = pb;
}
ret = s->p;
s->p = (char *)s->p + size;
return ret;
}
static void * alloc_node(struct bucket_info **s, size_t size)
{
if (!*s)
*s = alloc_bucket(size * NODES);
return alloc_for_size(*s, size);
}
static struct bucket_info *foo_info;
void * alloc_foo_node()
{
void *ret = alloc_node(&foo_info, sizeof(struct foo));
return ret;
}
struct foo * new_foo()
{
return alloc_foo_node();
}
void test(int t, struct foo *foo1)
{
struct foo *foo2 = new_foo();
// Crash at this line
*foo2 = *foo1;
// comment this switch statement, it works. why?
switch (t) {
case 1:
break;
default:
break;
}
}
int main(int argc, const char * argv[]) {
struct foo *foo1 = new_foo();
test(10, foo1);
return 0;
}
以上是完整的代码。我用 clang 编译了它,在行中得到了一个 'Segment Fault 11':
*foo2 = *foo1;
然后,将此行更改为:
memcpy(foo2, foo1, sizeof(struct Foo));
有效。
那我试过用gcc编译这两个case,没有问题。
alloc_foo_node
返回的值可能没有与 struct foo
正确对齐。
在我的系统上,打印 _Alignof(struct foo)
得到 16
,但指针 foo1
和 foo2
不是 16
的倍数。
所以它导致未定义的行为将 alloc_foo_node
的未对齐结果转换为具有类型 struct foo *
.
要解决此问题,您必须对分配代码进行更多处理,以确保它只会分发 space,它位于 struct foo
的正确边界上。您可以使用 max_align_t
来帮助解决这个问题(它被定义为 _Alignof(max_align_t)
是所需的最大可能对齐)。