使用strtok转储分段故障核心

时间:2018-03-22 10:17:07

标签: c pointers segmentation-fault strtok coredump

我正在尝试编写自己的scanf,它以格式字符串获取数字以限制输入的大小。而不是“%d”,它使用“@ 5%d”表示输入不能超过5位。

我正在使用以下代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>



/*
 * 
 */
char** str_split(char* a_str, const char a_delim);
void myscanf(char *input_format, ... );

int main(int argc, char** argv) {
    int x;
    myscanf("@2%d", &x);

    printf("%d", x);

    return 0;
}

void myscanf(char *input_format, ... ){
   va_list args;
   va_start(args, input_format);
   char** tokens;
   tokens = str_split(input_format, '@');
   tokens=tokens++;
   while(*tokens){

       int number;
       char format;
       char** parts;

       parts=str_split(*tokens,'%');
       number=atoi(*(parts));
       format= **(parts+1);

       char s[number+1];
       fgets(s,number+1,stdin);

       if(strlen(s)>number)
           perror("buffer overflow");

       switch(format){
           case 'd':{

                int* integer = va_arg(args,int*);
                *integer = atoi(s);
                break;
           }
           case 'f': {

               float* floatingpoint = va_arg(args,float*);
               *floatingpoint = atof(s);
               break;
           }
           case 'c': {
               if(strlen(s)>1)
                    perror("buffer overflow");
               char* character = va_arg(args,char*);
               *character = s[0];
               break;
           }
           case 's': {
               char *string = va_arg(args,char*);
               strcpy(string, s);
               break;
           }
       }
       tokens++;
   }
}

char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = (char **) malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}

当我执行此操作时,控制台显示

  

转储分段故障核心。

我使用gdb来调试它,它表明问题出在strtok上。 gdb输出:

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...(no debugging symbols found)...done.
/home/core: No such file or directory.
(gdb) r
Starting program: /home/a.out 

Program received signal SIGSEGV, Segmentation fault.
strtok () at ../sysdeps/x86_64/strtok.S:186
186 ../sysdeps/x86_64/strtok.S: No such file or directory.

我真的很感激如果有人能解决这个问题。

1 个答案:

答案 0 :(得分:1)

您正在使用字符串文字(myscanf),"@2%d"调用myscanf来调用str_splitstr_split将调用strtok并且strtok试图写入它,这是不允许的。

一个简单的解决方案是创建一个缓冲区

char buffer[] = "@2%d";
myscanf(buffer, &x);

我注意到的另一个小错误:
tokens=tokens++;是未定义的行为,您应该只使用tokens++;来增加tokens。 您已经注意到我对strcpy的评论,并在示例代码中对其进行了更改。