问题描述
所以我有一个函数返回一个缓冲区字符串,其中包含一些扫描的 wifi 接入点的列表,我使用 strsep
将其除以 "\n"
,然后再次由 {{1} }.
循环运行良好,直到到达末尾,当 "\t"
参数 while
被求值时,它给出一个 ((line = strsep(&buf,"\n")))
。
按@Jabberwocky 询问的简短说明性示例:
SEGFAULT
真正给我带来问题的函数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
wap_scan_count_lines(char* wap_scan)
{
int line_amount = 0;
char *scan = wap_scan;
while(*scan)
{
if ('\n' == *scan){
line_amount++;
}
scan++;
}
return line_amount;
}
int main() {
char ***scan_result,*line=NULL,*item=NULL,*scan=NULL;
scan = strdup("bssid / frequency / signal level / flags / ssid\n"
"a8:6a:bb:e2:d6:ef 5785 -47 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS] Fibertel WiFi114 5.8GHz");
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
int i = 0;
int item_len = sizeof (*scan_result);
while((line = strsep(&scan,"\n")) != NULL ) {
if(i==0){
i++;
continue;
}
char **scan_line = calloc(5,item_len);
int j = 0;
while ((item = strsep(&line,"\t")) != NULL) {
printf("%s\n",item);
scan_line[j++] = strdup(item);
}
scan_result[i++] = scan_line;
}
return 0;
}
解决方法
基于 https://man7.org/linux/man-pages/man3/strsep.3.html,问题是循环会比您希望的多运行一次,从而导致 scan_result 溢出。
文档的相关部分是:
The strsep() function returns a pointer to the token,that is,it
returns the original value of *stringp.
和
If *stringp is NULL,the strsep() function returns NULL and does
nothing else. Otherwise,this function finds the first token in
the string *stringp,that is delimited by one of the bytes in the
string delim. This token is terminated by overwriting the
delimiter with a null byte ('\0'),and *stringp is updated to
point past the token. In case no delimiter was found,the token
is taken to be the entire string *stringp,and *stringp is made
NULL.
在 wap_scan_count_lines 中,您计算以“\n”结尾的行数。
在接下来的两行中,您根据以“\n”结尾的行数分配内存来保存结果。
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
但是,上面引用的 strsep() 文档暗示在您的简化示例中,第一次 wap_scan_size 次 strsep 被调用,在调用结束时,结果将not be NULL 并且 scan 在调用过程中不会被设置为 NULL。下一次调用时,scan 会在调用过程中设置为 NULL,但结果不会是 NULL。这意味着循环体将被执行 wap_scan_size + 1 次,导致写入超过 scan_result。
至少有两种可能的修复方法,具体取决于您是否真的要处理输入末尾未以 '\n' 终止的任何行。
如果您确实需要处理这样的行,这对我来说似乎更可靠,特别是考虑到您的简化示例以这样的行结束,只需在 scan_result 中分配一个额外的条目:
scan_result = malloc((wap_scan_size + 1) * sizeof(**scan_result));
如果您非常确定不需要处理这些行,但在我看来这不正确,请更改:
while((line = strsep(&scan,"\n")) != NULL ) {
到
for(line = strsep(&scan,"\n"); scan != NULL; line = strsep(&scan,"\n") ) {