strcat的分段错误

时间:2010-07-15 22:51:39

标签: c string segmentation-fault 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-&gt; 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");

我做错了什么,但我真的迷失了什么。提前谢谢,

本。

5 个答案:

答案 0 :(得分:9)

我看到了几个问题:

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

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

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

它可能已经被删除了,但我没有看到你在结构中初始化了number_of_hash_salts成员。

答案 1 :(得分:4)

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

该行:

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

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

您需要为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,因为它是一个指针,sizeof用于hash_function_salt,这是一个固定大小的char数组。我们不需要添加任何内容,因为hash_function_salt已包含NUL的空间。我们首先使用strcpystrcat适用于已有NUL终止字符串的情况(我们不在此处)。请注意,我们放弃*。从错误的typedef开始,这是一个错误。

答案 2 :(得分:2)

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

答案 3 :(得分: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(),然后释放指针数组。

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

答案 4 :(得分: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)