1

我正在尝试创建一个字符串数组,以准备将它们显示在表格中。

所以我有一个函数,它返回一个带有一些扫描的wifi接入点列表的缓冲区字符串,我用strsep它来分割它"\n",然后再分割它"\t"

循环运行良好,直到它到达结尾,并且在评估while参数时((line = strsep(&buf, "\n")))它给出一个SEGFAULT.

每个@Jabberwocky 询问的简短说明性示例:

#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;
}

给我带来问题的真正功能:

char *** wifi_client_get_wap_list(int *len)
{
    char ***scan_result;
    char *buf, *buf_free, *cmd, *line, *item;
    int ret, items_len;
    cmd = strdup("SCAN");
    ret = wpa_ctrl_command(cmd, NULL);
    if (ret < 0) goto error;

    cmd = strdup("SCAN_RESULTS");
    ret = wpa_ctrl_command(cmd, &buf); //RETURNS A STRING ON BUF ALLOCATED BY STRDUP
    if (ret < 0){
        free(buf);
        goto error;
    }

    *len = wap_scan_count_lines(buf); //NUMBER OF LINES IN THE SCAN RESULT
    scan_result = calloc(*len, sizeof(**scan_result));
    int i = 0, j;
    buf_free = buf;
    items_len = sizeof (*scan_result);

    while ((line = strsep(&buf, "\n"))){ //THIS GIVES THE SEGFAULT AT THE END
        // SKIP FIRST LINE WITH HEADERS
        if (i==0){
            i++;
            continue;
        }

        //if (strcmp(line, "") == 0) {
        //  break;   
        //}

       //EACH LINE HAS 5 VALUES (bssid, freq, level,flags,ssid)
        char **scan_line = calloc(5, items_len); 
        j = 0;
        printf("INNER STEPS:\n");
        while((item = strsep(&line, "\t"))){
            *(scan_line + j) = strdup(item);
            printf("%d ", j);
            j++;
        }
        *(scan_result + i) = scan_line;
        printf("\nSTEP: %d\n", i);
        i++;
    }

    free(buf_free);
    free(cmd);
    return scan_result;

    error:
    // @TODO: Handle error
    if (ret == -2) {
        printf("'%s' command timed out.\n", cmd);
    } else if (ret < 0) {
        printf("'%s' command failed.\n", cmd);
    }

    free(cmd);
    return NULL;
}
4

1 回答 1

1

基于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' 结尾的行数。

在接下来的 2 行中,您根据以 '\n' 结尾的行数分配内存来保存结果。

int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));

但是,上面引用的strsep()文档意味着在您的简化示例中,第一个wap_scan_size次 strsep 被调用,在调用结束时结果不会为 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") ) {
于 2021-03-11T00:37:28.877 回答