繁体   English   中英

yacc/bison 的分段错误

[英]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.

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