[英]Segmentation fault with yacc/bison
我正在尝试为学校作业编写一个简单的 HTTP 请求解析器,但是我遇到了无法摆脱的分段错误。 我认为我的生产规则还可以。 我已经在启用跟踪的情况下执行了野牛,它总是在解析我的 header 的部分产生段错误:
Reducing stack by rule 9 (line 59):
$1 = token ID ()
$2 = token COLON ()
$3 = token STRING ()
[4] 36661 segmentation fault (core dumped) ./problem1 < input.txt
这是我的 request.l 文件的内容:
%option noyywrap
%{
#include<stdio.h>
#include "request.tab.h"
char *strclone(char *str);
%}
num [0-9]+(\.[0-9]{1,2})?
letter [a-zA-Z]
letternum [a-zA-Z0-9\-]
id {letter}{letternum}*
string \"[^"]*\"
fieldvalue {string}|{num}
%%
(GET|HEAD|POST|PUT|DELETE|OPTIONS) { yylval = strclone(yytext); return METHOD; }
HTTP\/{num} { yylval = strclone(yytext); return VERSION; }
{id} { yylval = strclone(yytext); return ID; }
"/" { return SLASH; }
"\n" { return NEWLINE; }
{string} { yylval = strclone(yytext); return STRING; }
":" { return COLON; }
[ \t\n]+ ;
. {
printf("Unexpected: %c\nExiting...\n", *yytext);
exit(0);
}
%%
char *strclone(char *str) {
int len = strlen(str);
char *clone = (char *)malloc(sizeof(char)*(len+1));
strcpy(clone,str);
return clone;
}
和我的 request.y 文件:
%{
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define YYSTYPE char*
extern int yylex();
extern int yyparse();
extern FILE* yyin;
void yyerror(const char* s);
%}
%token METHOD
%token SLASH
%token VERSION
%token STRING
%token ID
%token COLON
%token NEWLINE
%%
REQUEST: METHOD URI VERSION NEWLINE HEADERS {
printf("%s %s", $1, $2);
}
;
URI: SLASH DIR {
$$ = (char *)malloc(sizeof(char)*(1+strlen($2)+1));
sprintf($$, "//%s", $2);
}
;
DIR: ID SLASH {
$$ = (char *)malloc(sizeof(char)*(strlen($1)+2));
sprintf($$, "%s//", $1);
}
|ID {
$$ = $1;
}
| {
$$ = "";
}
;
HEADERS: HEADER {
$$ = $1;
}
|HEADER NEWLINE HEADERS {
$$ = (char *)malloc(sizeof(char)*(strlen($1)+1+strlen($3)+1));
sprintf($$, "%s\n%s", $1, $3);
}
|{
$$ = "";
}
;
HEADER: ID COLON STRING {
$$ = (char *)malloc(sizeof(char)*(strlen($1)+1+strlen($2)+1));
sprintf($$, "%s:%s", $1, $3);
}
;
%%
void yyerror (char const *s) {
fprintf(stderr, "Poruka nije tacna\n");
}
int main() {
yydebug = 1;
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
这也是我作为输入传递的 input.txt 的内容:
GET / HTTP/1.1
Host: "developer.mozzila.org"
Accept-language: "fr"
HEADER: ID COLON STRING {
$$ = (char *)malloc(sizeof(char)*(strlen($1)+1+strlen($2)+1));
sprintf($$, "%s:%s", $1, $3);
};
您不应该在表达式中使用strlen($3)
来计算组合字符串的长度吗? 您使用的strlen($2)
只会返回应该为 1 的冒号字符串的长度。如果您随后sprintf
到太短的缓冲区,则访问其长度后面的缓冲区。
在request.y
中,您包含指令
#define YYSTYPE char*
所以在 Bison 生成的解析器代码中, yylval
的类型是char*
。 但是该行没有插入request.l
。 所以在 Flex 生成的扫描器代码中, yylval
有它的默认类型, int
。
C, unfortunately, allows a pointer to be converted to an integer type even if the integer type is too narrow to hold the entire address, which is the case with a typical 64-bit platform with 8-byte pointers and 4-byte int
. 因此,在您的扫描仪中,将编译器认为是四字节int
的值设置为八字节指针意味着该值将被截断。 因此,当解析器尝试将其用作地址时,您将收到段错误。 如果你幸运的话。
大多数 C 编译器都会警告您这种截断 - 但前提是您告诉编译器您希望看到警告( -Wall
用于 clang 和 gcc)。 使用-Wall
进行编译始终很重要,即使在编译代码生成器的 output 时也是如此。
您还需要修正@JakobStark指出的错字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.