2

我在 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");

我做错了什么,但我真的不知道是什么。提前致谢,

本。

4

5 回答 5

9

我看到几个问题:

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了结构中的成员。

于 2010-07-15T22:59:14.600 回答
4

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

该行:

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

将使 temp 成为指针长度的 34 倍 + 2。 item 的大小是指针的大小,sizeof(bloom->hash_salts[i])当前是指针大小的 33 倍。

您需要使用 strlen item,因此您知道实际的字符数。

其次,bloom->hash_salts[i]是 a hash_function_salt,它是一个由 33 个指向 char 的指针组成的数组。似乎hash_function_salt应该定义为:

因为您希望它包含 33 个字符,而不是 33 个指针。您还应该记住,当您将字符串文字传递给bloom_filter_create 时,您传递的是一个指针。hash_function_salt这意味着我们使用 memcpy 或 strcpy来初始化数组。当我们知道确切的长度时,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]);

我们使用strlenfor item 因为它是一个指针,但sizeof对于hash_function_saltchar 是一个固定大小的数组。我们不需要添加任何东西,因为 hash_function_salt 已经包含了NUL. 我们strcpy先用。 strcat适用于您已经有一个以 NUL 结尾的字符串(我们在这里没有)的情况。请注意,我们删除了 *. 这是您不正确的typedef造成的错误。

于 2010-07-15T22:58:09.203 回答
2

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

于 2010-07-15T23:00:11.383 回答
2

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

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

您已经bloom->hash_salts[]va_arg(). 这些指针的生命周期有限。他们甚至可能不会比电话更持久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()

另一种需要更多初始化开销但释放工作量更少的方法是在一次分配中分配指针数组以及为所有字符串提供足够空间。然后复制字符串并填写指针。它有很多代码来获得一个非常小的优势。

于 2010-07-15T23:10:18.990 回答
1

您确定 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) 
于 2010-07-15T23:07:36.267 回答