我读了很多关于这方面的文章,但找不到错误。
我有一个过程来说明是否在另一个较长的CSV字符串中找到了字符串值(在IP中下面的代码中是IPv4地址,allow_hosts应该是IPv4地址的CSV列表,但它应该适用于任何字符串和字符串的CSV列表)。
代码如下:
bool stringFound(char* inIP,char* allow_hosts){
bool found=false;
int i =0;
int j =0;
char* ip;
printf("strlen(allow_hosts)=%dn",strlen(allow_hosts));
while(i<strlen(allow_hosts) && !found){
j=i;
while(allow_hosts[i]!=',' && i<strlen(allow_hosts)){
i++;
}
printf("jota = %dn",j);
printf("i = %dn",i);
printf("i-j+1 = %dn",i-j+1);
ip = malloc(i-j+1);//1 more for ' '
strncpy(ip,allow_hosts+j,i);//line 25, illegal access, problem one
printf("it copies=%sn",ip);
ip[i-j]=' ';
found = strcmp(ip,inIP)==0;
//free(ip);//Problem two
if(found)
return found;
i++;
}
return found;
};
当我测试它一次时,没有问题,结果是正确的,然而,当我在一行上运行它多次时,第三次或第四次会给我错误:
malloc.c:2372: sysmalloc: Assertion
`(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2]))
- __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0)
|| ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof
(struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1))
& ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) &&
((unsigned long) old_end & pagemask) == 0)' failed.
Aborted (core dumped)
据我所知,这是malloc的一个问题,但当我用调用它时,我分配的内存数量是足够的
stringFound("8.8.7.8","127.0.0.1,8.8.8.8");
stringFound("8.8.54.8","127.0.0.1,8.8.8.8,192.168.92.3");
正在打印
jota = 10
i = 17
i-j+1 = 8
it copies=8.8.8.8
strlen(allow_hosts)=30
jota = 0
i = 9
i-j+1 = 10
//the error I showed above appears here
我还用Valgrind测试了它,只是称之为Valgrind/myProgram,它说:
==3406== Invalid write of size 1
==3406== at 0x402D763: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3406== by 0x80485EB: stringFound (esta.c:25)
==3406== by 0x80486CC: test (esta.c:49)
==3406== by 0x8048803: main (esta.c:75)
==3406== Address 0x41fe0f0 is 0 bytes after a block of size 8 alloc'd
"test"是一个多次调用我的过程的函数,代码中第25行标记为"problem here"。
正如你所看到的,我在free()行有一条评论。如果我使用这条线,错误将变为
Error in `./esta': free(): invalid next size (fast): 0x09d11008
Aborted (core dumped)
我认为两个错误都是由相同的原因引起的,但我没有发现错误
strncpy(ip,allow_hosts+j,i);//line 25, illegal access, problem one
是的,这应该是问题的根源。我认为第三个论点应该是i-j
,而不是i
。
您应该写:
strncpy(ip,allow_hosts+j,i-j);
在循环的任何下一次迭代中,i
都会变大,但您只为从j开始的ip字符串分配空间,因此您也必须只复制该部分。
strncpy(ip,allow_hosts+j,i);
这里的问题是,您需要一个片段的长度作为第三个参数,但您传递了结束位置。你应该通过i-j
。
2个问题:
ip = malloc(i-j+1);
// Wrong limit on strncpy
// strncpy(ip,allow_hosts+j,i);
strncpy(ip,allow_hosts+j,i-j);
// ip may not be null character terminated, re-arrange code
ip[i-j]=' ';
printf("it copies=%sn",ip);
// ip[i-j]=' ';
free()
问题很可能是由于上述问题的损坏。
更微妙的问题是:strlen
返回的长度类型是size_t
。如果size_t
和int
的大小相似,则此问题可能不会轻易显现出来最好不要指望这一点,使用CCD_ 10。
size_t i =0;
size_t j =0;
// Change format specifier too.
printf("strlen(allow_hosts)=%zun",strlen(allow_hosts));
printf("jota = %zu",j); // Review all printf formats
- strstr()是一个可用的库函数
- 你不需要malloc;只要检查一下字符串
- 如果找到该字符串,则该字符串可以是较大的有效带点四元字符串的部分
- (注意:strncpy()是一个糟糕的函数,非常需要)
#include <stdio.h>
#include <string.h>
int stringFound(char *inIP, char *allow_hosts){
char *cp;
cp = strstr(allow_hosts, inIP);
/* IF substring is found:
** check if it is PART of a LARGER dotted quad string
*/
if (!cp) return 0;
if (cp > allow_hosts && cp[-1] >= '0' && cp[-1] <= '9' ) return 0;
cp += strlen(inIP); if (*cp >= '0' && *cp <= '9' ) return 0;
return 1;
}
int main(int argc, char **argv)
{
int found;
char *the_ip = "1.2.3.4";
char *should_fail = "5.2.3.4 ,1.2.3.45, 11.2.3.4, 1.2.3.4.";
char *should_match = "5.2.3.4 ,6.2.3.4, 1.2.3.4, 9.2.3.4";
found = stringFound(the_ip, should_fail);
printf("(should fail) Found=%dn" , found);
found = stringFound(the_ip, should_match);
printf("(should match) Found=%dn" , found);
return 0;
}