简体   繁体   English

链式 strsep 给出分段错误 - C

[英]Chained strsep gives segmentation fault - C

I'm trying to create an array of array of strings to prepare them to be shown in a table.我正在尝试创建一个字符串数组,以准备将它们显示在表格中。

So I have a function that returns a buffer string with the list of some scanned wifi access points, and I'm using strsep to split it by "\n" and then again by "\t" .所以我有一个 function 返回一个缓冲区字符串,其中包含一些扫描的 wifi 接入点的列表,我使用strsep将其拆分为"\n" ,然后再拆分为"\t"

The loop runs fine until it reaches the end and when the while argument ((line = strsep(&buf, "\n"))) is evaluated it gives a SEGFAULT .循环运行良好,直到结束,当评估while参数((line = strsep(&buf, "\n")))时,它会给出SEGFAULT

Short Illustrative example asked per @Jabberwocky:每个@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;
}

The real function that gives me the problem:真正的 function 给我带来了问题:

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

Based on https://man7.org/linux/man-pages/man3/strsep.3.html the issue is that the loop will run one more time than you want it to, causing scan_result to overflow.基于https://man7.org/linux/man-pages/man3/strsep.3.html问题是循环运行的时间比您希望的多,导致scan_result溢出。

The relevant parts of the documentation are:文档的相关部分是:

   The strsep() function returns a pointer to the token, that is, it
   returns the original value of *stringp.

and

   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.

In wap_scan_count_lines you count the number of lines that are terminated with '\n'.wap_scan_count_lines 中,您计算以 '\n' 结尾的行数。

In the following 2 lines, you allocate the memory to hold the result based on the number of lines terminated with '\n'.在以下 2 行中,您根据以“\n”结尾的行数分配 memory 来保存结果。

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

However, the above quoted documentation for strsep() implies that in your simplified example the first wap_scan_size times strsep is called, at the end of the call the result will not be NULL and scan won't be set to NULL during the call.但是,上面引用的strsep()文档意味着在您的简化示例中,第一个wap_scan_size次 strsep 被调用,在调用结束时,结果不会是 NULL 并且在调用期间扫描不会设置为 NULL。 The next time through the call, scan will be set to NULL during the call but the result will not be NULL.下一次调用时,调用期间扫描将设置为 NULL,但结果不会是 NULL。 This means that the body of the loop will be executed wap_scan_size + 1 times, causing a write past the end of scan_result .这意味着循环体将被执行wap_scan_size + 1 次,导致写入超过scan_result的末尾。

There are at least two possible fixes, depending on whether you actually want to process any line at the end of the input that is not terminated by '\n'.至少有两种可能的修复方法,具体取决于您是否真的要处理输入末尾未由“\n”终止的任何行。

If you do need to process such lines, which seems more robust to me, particularly given that your simplified example ends with such a line, just allocate one extra entry in scan_result :如果您确实需要处理这样的行,这对我来说似乎更健壮,特别是考虑到您的简化示例以这样的行结尾,只需在scan_result中分配一个额外的条目:

scan_result = malloc((wap_scan_size + 1) * sizeof(**scan_result));

If you are quite sure that you do not need to process such lines, but this seems incorrect to me, change:如果您非常确定不需要处理这些行,但这对我来说似乎不正确,请更改:

while((line = strsep(&scan, "\n")) != NULL ) {

to

for(line = strsep(&scan, "\n"); scan != NULL; line = strsep(&scan, "\n") ) {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM