strcat 的分段错误
我在 strcat 和分段错误方面遇到了一些问题。错误如下:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x00007fff82049f1f in __strcat_chk ()
(gdb) where
#0 0x00007fff82049f1f in __strcat_chk ()
#1 0x0000000100000adf in bloom_operation (bloom=0x100100080, item=0x100000e11 "hello world", operation=1) at bloom_filter.c:81
#2 0x0000000100000c0e in bloom_insert (bloom=0x100100080, to_insert=0x100000e11 "hello world") at bloom_filter.c:99
#3 0x0000000100000ce5 in main () at test.c:6
bloom_operation如下:
int bloom_operation(bloom_filter_t *bloom, const char *item, int operation)
{
int i;
for(i = 0; i < bloom->number_of_hash_salts; i++)
{
char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];
strcat(temp, item);
strcat(temp, *bloom->hash_salts[i]);
switch(operation)
{
case BLOOM_INSERT:
bloom->data[hash(temp) % bloom->buckets] = 1;
break;
case BLOOM_EXISTS:
if(!bloom->data[hash(temp) % bloom->buckets]) return 0;
break;
}
}
return 1;
}
有问题的行是第二 strcat。 bloom->hash_salts 是定义如下的结构的一部分:
typedef unsigned const char *hash_function_salt[33];
typedef struct {
size_t buckets;
size_t number_of_hash_salts;
int bytes_per_bucket;
unsigned char *data;
hash_function_salt *hash_salts;
} bloom_filter_t;
它们在这里初始化:
bloom_filter_t* bloom_filter_create(size_t buckets, size_t number_of_hash_salts, ...)
{
bloom_filter_t *bloom;
va_list args;
int i;
bloom = malloc(sizeof(bloom_filter_t));
if(bloom == NULL) return NULL;
// left out stuff here for brevity...
bloom->hash_salts = calloc(bloom->number_of_hash_salts, sizeof(hash_function_salt));
va_start(args, number_of_hash_salts);
for(i = 0; i < number_of_hash_salts; ++i)
bloom->hash_salts[i] = va_arg(args, hash_function_salt);
va_end(args);
// and here...
}
并且bloom_filter_create 的调用如下:
bloom_filter_create(100, 4, "3301cd0e145c34280951594b05a7f899", "0e7b1b108b3290906660cbcd0a3b3880", "8ad8664f1bb5d88711fd53471839d041", "7af95d27363c1b3bc8c4ccc5fcd20f32");
我做错了什么,但我真的不知道是什么。预先感谢,
本。
I'm having a bit of a problem with strcat and segmentation faults. The error is as follows:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x00007fff82049f1f in __strcat_chk ()
(gdb) where
#0 0x00007fff82049f1f in __strcat_chk ()
#1 0x0000000100000adf in bloom_operation (bloom=0x100100080, item=0x100000e11 "hello world", operation=1) at bloom_filter.c:81
#2 0x0000000100000c0e in bloom_insert (bloom=0x100100080, to_insert=0x100000e11 "hello world") at bloom_filter.c:99
#3 0x0000000100000ce5 in main () at test.c:6
bloom_operation is as follows:
int bloom_operation(bloom_filter_t *bloom, const char *item, int operation)
{
int i;
for(i = 0; i < bloom->number_of_hash_salts; i++)
{
char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];
strcat(temp, item);
strcat(temp, *bloom->hash_salts[i]);
switch(operation)
{
case BLOOM_INSERT:
bloom->data[hash(temp) % bloom->buckets] = 1;
break;
case BLOOM_EXISTS:
if(!bloom->data[hash(temp) % bloom->buckets]) return 0;
break;
}
}
return 1;
}
The line with trouble is the second strcat. The bloom->hash_salts are part of a struct defined as follows:
typedef unsigned const char *hash_function_salt[33];
typedef struct {
size_t buckets;
size_t number_of_hash_salts;
int bytes_per_bucket;
unsigned char *data;
hash_function_salt *hash_salts;
} bloom_filter_t;
And they are initialized here:
bloom_filter_t* bloom_filter_create(size_t buckets, size_t number_of_hash_salts, ...)
{
bloom_filter_t *bloom;
va_list args;
int i;
bloom = malloc(sizeof(bloom_filter_t));
if(bloom == NULL) return NULL;
// left out stuff here for brevity...
bloom->hash_salts = calloc(bloom->number_of_hash_salts, sizeof(hash_function_salt));
va_start(args, number_of_hash_salts);
for(i = 0; i < number_of_hash_salts; ++i)
bloom->hash_salts[i] = va_arg(args, hash_function_salt);
va_end(args);
// and here...
}
And bloom_filter_create is called as follows:
bloom_filter_create(100, 4, "3301cd0e145c34280951594b05a7f899", "0e7b1b108b3290906660cbcd0a3b3880", "8ad8664f1bb5d88711fd53471839d041", "7af95d27363c1b3bc8c4ccc5fcd20f32");
I'm doing something wrong but I'm really lost as to what. Thanks in advance,
Ben.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我发现了几个问题:
sizeof(item)
将仅返回 4(或 64 位平台上的 8)。您可能需要使用 strlen() 来获取实际长度。虽然我不认为你可以像使用 strlen 那样在堆栈上声明它(尽管我想也许我看到有人表明使用较新版本的 gcc 是可能的 - 我可能会出去吃午饭)。另一个问题是临时数组未初始化。因此第一个 strcat 可能不会写入数组的开头。在调用 strcat 之前,需要在第一个元素中放入 NULL (0)。
它可能已经在被剪掉的代码中,但我没有看到您初始化了结构中的
number_of_hash_salts
成员。I see a couple of problems:
The
sizeof(item)
will only return 4 (or 8 on a 64-bit platform). You probably need to use strlen() for the actual length. Although I don't think you can declare it on the stack like that with strlen (although I think maybe I saw someone indicate that it was possible with newer versions of gcc - I may be out to lunch on that).The other problem is that the temp array is not initialized. So the first strcat may not write to the beginning of the array. It needs to have a NULL (0) put in the first element before calling strcat.
It may already be in the code that was snipped out, but I didn't see that you initialized the
number_of_hash_salts
member in the structure.您需要使用 strlen,而不是 sizeof。
item
作为指针而不是数组传入。该行:
将使 temp 成为指针长度的 34 倍 + 2。 item 的大小是指针的大小,并且
sizeof(bloom->hash_salts[i])
当前为 33x指针的大小。您需要对
item
使用 strlen,以便知道实际的字符数。其次,
bloom->hash_salts[i]
是一个hash_function_salt
,它是一个包含33个char指针的数组。看起来hash_function_salt
应该定义为:因为你希望它保存 33 个字符,而不是 33 个指针。您还应该记住,当您将字符串文字传递给bloom_filter_create时,您正在传递一个指针。这意味着我们使用 memcpy 或 strcpy 来初始化 hash_function_salt 数组。当我们知道确切的长度时,memcpy 会更快(就像这里一样):
所以我们得到:
在
bloom_filter_create
中:回到bloom_operation,我们得到:
我们使用
strlen
作为 item 因为它是一个指针,但是hash_function_salt
的sizeof
,它是一个固定大小的 char 数组。我们不需要添加任何内容,因为 hash_function_salt 已经包含了NUL
的空间。我们首先使用strcpy
。strcat
适用于已经有一个以 NUL 结尾的字符串(我们这里没有)的情况。请注意,我们删除了*。这是由于您的 typedef 不正确而导致的错误。You need to use strlen, not sizeof.
item
is passed in as a pointer, not an array.The line:
will make temp the 34x the length of a pointer + 2. The size of item is the size of a pointer, and the
sizeof(bloom->hash_salts[i])
is currently 33x the size of a pointer.You need to use strlen for
item
, so you know the actual number of characters.Second,
bloom->hash_salts[i]
is ahash_function_salt
, which is an array of 33 pointers to char. It seems likehash_function_salt
should be defined as:since you want it to hold 33 characters, not 33 pointers. You should also remember that when you're passing a string literal to bloom_filter_create, you're passing a pointer. That means to initialize the
hash_function_salt
array we use memcpy or strcpy. memcpy is faster when we know the exact length (like here):So we get:
and in
bloom_filter_create
:Going back to bloom_operation, we get:
We use
strlen
for item since it's a pointer, butsizeof
for thehash_function_salt
, which is a fixed size array of char. We don't need to add anything, because hash_function_salt already includes room for aNUL
. We usestrcpy
first.strcat
is for when you already have a NUL-terminated string (which we don't here). Note that we drop the *. That was a mistake following from your incorrect typedef.temp
的数组大小计算使用sizeof(bloom->hash_salts[i])
(即只是指针的大小),但随后您取消引用指针并尝试
将整个字符串复制到
temp
中。Your array size calculation for
temp
usessizeof(bloom->hash_salts[i])
(which isjust the size of the pointer), but then you dereference the pointer and try
to copy the entire string into
temp
.首先,正如大家所说,您根据两个指针的大小而不是字符串的长度来调整 temp 的大小。您现在已经修复了该问题,并报告症状已转移到对
strlen()
的调用。这显示了一个更微妙的错误。
您已根据
va_arg()
返回的指针初始化了数组bloom->hash_salts[]
。这些指针的生命周期是有限的。它们甚至可能不会比对va_end()
的调用更持久,但它们几乎肯定不会比对bloom_filter_create()
的调用更持久。后来,在bloom_filter_operation()中,它们指向任意位置,你注定会遇到某种有趣的失败。
编辑:解决这个问题需要存储在
hash_salts
数组中的指针有足够的生命周期。解决这个问题的一种方法是为它们分配存储空间,将它们从 varargs 数组中复制出来,例如:稍后,您需要循环
hash_salts
并调用free() 在释放指针数组本身之前在每个元素上。
另一种需要更多开销来初始化但释放精力更少的方法是在一次分配中为所有字符串分配指针数组以及足够的空间。然后复制字符串并填写指针。为了获得一个很小的优势而编写了很多代码。
First, as everyone has said, you've sized
temp
based on the sizes of two pointers, not the lengths of the strings. You've now fixed that, and report that the symptom has moved to the call tostrlen()
.This is showing a more subtle bug.
You've initialized the array
bloom->hash_salts[]
from pointers returned byva_arg()
. Those pointers will have a limited lifetime. They may not even outlast the call tova_end()
, but they almost certainly do not outlive the call tobloom_filter_create()
.Later, in
bloom_filter_operation()
, they point to arbitrary places and you are doomed to some kind of interesting failure.Edit: Resolving this this requires that the pointers stored in the
hash_salts
array have sufficient lifetime. One way to deal with that is to allocate storage for them, copying them out of the varargs array, for example:Later, you would need to loop over
hash_salts
and callfree()
on each element before freeing the array of pointers itself.Another approach that would require more overhead to initialize, but less effort to free would be to allocate the array of pointers along with enough space for all of the strings in a single allocation. Then copy the strings and fill in the pointers. Its a lot of code to get right for a very small advantage.
您确定 hash_function_salt 类型定义正确吗?您可能有太多 *:
Are you sure that the hash_function_salt type is defined correctly? You may have too many *'s: