一次问题追查----短字符串签名算法引发的bug

近期开发代码, 出现了一些诡异现象。追查原因是公司使用的签名函数出现的问题。

问题: 代码使用的签名库函数, 对于<=4字节的字符串, 签名就是本身。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 
 5 int main(){
 6     char str[128] = "ni";   //长度是2
 7     unsigned num[1];    //长度是4
 8     memset(num, 0, sizeof(unsigned));
 9     memcpy(num, str, strlen(str));  //num[0] = 26990
10     
11     //可以看出, str, num 在前3个字节的内存是相等的
12     printf("tag = %d\n", memcmp(num, str, strlen(str) + 1));    //把\0也算进去
13 
14     //对于使用的优化后的签名函数, <= 4个字节则签名为本身(12的签名还是12)
15     //出现的bug是:
16     //str:ni, len:3 ---> sign:26990
17     //num:26990, len:4 ---> sign:26990
18     return 0;   
19 }

hash函数只是计算签名, 有时会有hash冲突导致实际不相等的字符串, 有相同的hash值。

如果要严格比较, 可以直接比较内存字节。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 
 5 int is_eq(
 6         const void* addr1, int len1,
 7         const void* addr2, int len2){
 8     if (len1 != len2){
 9         return 1;
10     }   
11     return memcmp(addr1, addr2, len1) == 0? 0:1;
12 }
13 
14 int main(){
15     char str[128] = "ni";   //长度是2
16     unsigned num[1];    //长度是4
17     num[0] = 26990;
18     
19     //把字符串的结尾也计算进去
20     printf("tag = %d\n", is_eq(str, strlen(str) + 1, num, sizeof(num)));
21     return 0;   
22 }

 

在严格场景下, 可以先用hash做签名, 之后再具体到每个hash值(桶, 拉链)上进行内存字节的比较就可以解决。

点赞