c - 使用 strtok 转储的分段故障核心



我正在尝试编写自己的scanf,它以格式字符串获取数字以限制输入的大小。 就像它使用"@5%d"代替"%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.

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

你用字符串文字 ("@2%d") 调用myscanfmyscanf用它调用str_splitstr_split会调用strtokstrtok尝试写入它,这是不允许的。

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

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

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

相关内容

  • 没有找到相关文章