strcat 的分段错误

发布于 2024-09-09 08:04:17 字数 2475 浏览 4 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

巴黎夜雨 2024-09-16 08:04:17

我发现了几个问题:

char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];

sizeof(item) 将仅返回 4(或 64 位平台上的 8)。您可能需要使用 strlen() 来获取实际长度。虽然我不认为你可以像使用 strlen 那样在堆栈上声明它(尽管我想也许我看到有人表明使用较新版本的 gcc 是可能的 - 我可能会出去吃午饭)。

另一个问题是临时数组未初始化。因此第一个 strcat 可能不会写入数组的开头。在调用 strcat 之前,需要在第一个元素中放入 NULL (0)。

它可能已经在被剪掉的代码中,但我没有看到您初始化了结构中的 number_of_hash_salts 成员。

I see a couple of problems:

char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];

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.

以歌曲疗慰 2024-09-16 08:04:17

您需要使用 strlen,而不是 sizeof。 item 作为指针而不是数组传入。

该行:

char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];

将使 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 会更快(就像这里一样):

所以我们得到:

typedef unsigned char hash_function_salt[33];

bloom_filter_create 中:

memcpy(bloom->hash_salts[i], va_arg(args, char*), sizeof(bloom->hash_salts[i]));

回到bloom_operation,我们得到:

char temp[strlen(item) + sizeof(bloom->hash_salts[i])];
strcpy(temp, item);
strcat(temp, bloom->hash_salts[i]);

我们使用 strlen 作为 item 因为它是一个指针,但是 hash_function_saltsizeof,它是一个固定大小的 char 数组。我们不需要添加任何内容,因为 hash_function_salt 已经包含了 NUL 的空间。我们首先使用strcpystrcat 适用于已经有一个以 NUL 结尾的字符串(我们这里没有)的情况。请注意,我们删除了*。这是由于您的 typedef 不正确而导致的错误。

You need to use strlen, not sizeof. item is passed in as a pointer, not an array.

The line:

char temp[sizeof(item) + sizeof(bloom->hash_salts[i]) + 2];

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 a hash_function_salt, which is an array of 33 pointers to char. It seems like hash_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:

typedef unsigned char hash_function_salt[33];

and in bloom_filter_create:

memcpy(bloom->hash_salts[i], va_arg(args, char*), sizeof(bloom->hash_salts[i]));

Going back to bloom_operation, we get:

char temp[strlen(item) + sizeof(bloom->hash_salts[i])];
strcpy(temp, item);
strcat(temp, bloom->hash_salts[i]);

We use strlen for item since it's a pointer, but sizeof for the hash_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 a NUL. We use strcpy 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.

盗琴音 2024-09-16 08:04:17

temp 的数组大小计算使用 sizeof(bloom->hash_salts[i]) (即
只是指针的大小),但随后您取消引用指针并尝试
将整个字符串复制到 temp 中。

Your array size calculation for temp uses sizeof(bloom->hash_salts[i]) (which is
just the size of the pointer), but then you dereference the pointer and try
to copy the entire string into temp.

网白 2024-09-16 08:04:17

首先,正如大家所说,您根据两个指针的大小而不是字符串的长度来调整 temp 的大小。您现在已经修复了该问题,并报告症状已转移到对 strlen() 的调用。

这显示了一个更微妙的错误。

您已根据 va_arg() 返回的指针初始化了数组 bloom->hash_salts[]。这些指针的生命周期是有限的。它们甚至可能不会比对 va_end() 的调用更持久,但它们几乎肯定不会比对 bloom_filter_create() 的调用更持久。
后来,在bloom_filter_operation()中,它们指向任意位置,你注定会遇到某种有趣的失败。

编辑:解决这个问题需要存储在hash_salts数组中的指针有足够的生命周期。解决这个问题的一种方法是为它们分配存储空间,将它们从 varargs 数组中复制出来,例如:

// fragment from bloom_filter_create()
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] = strdup(va_arg(args, hash_function_salt));
va_end(args);

稍后,您需要循环 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 to strlen().

This is showing a more subtle bug.

You've initialized the array bloom->hash_salts[] from pointers returned by va_arg(). Those pointers will have a limited lifetime. They may not even outlast the call to va_end(), but they almost certainly do not outlive the call to bloom_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:

// fragment from bloom_filter_create()
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] = strdup(va_arg(args, hash_function_salt));
va_end(args);

Later, you would need to loop over hash_salts and call free() 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.

咿呀咿呀哟 2024-09-16 08:04:17

您确定 hash_function_salt 类型定义正确吗?您可能有太多 *:

(gdb) ptype bloom
type = struct {
    size_t buckets;
    size_t number_of_hash_salts;
    int bytes_per_bucket;
    unsigned char *data;
    hash_function_salt *hash_salts;
} *
(gdb) ptype bloom->hash_salts
type = const unsigned char **)[33]
(gdb) ptype bloom->hash_salts[0]
type = const unsigned char *[33]
(gdb) ptype *bloom->hash_salts[0]
type = const unsigned char *
(gdb) 

Are you sure that the hash_function_salt type is defined correctly? You may have too many *'s:

(gdb) ptype bloom
type = struct {
    size_t buckets;
    size_t number_of_hash_salts;
    int bytes_per_bucket;
    unsigned char *data;
    hash_function_salt *hash_salts;
} *
(gdb) ptype bloom->hash_salts
type = const unsigned char **)[33]
(gdb) ptype bloom->hash_salts[0]
type = const unsigned char *[33]
(gdb) ptype *bloom->hash_salts[0]
type = const unsigned char *
(gdb) 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文