YACC - $ 1的strlen是0虽然字符串在那里

时间:2017-04-07 14:51:23

标签: bison yacc

我的程序中出现了一个奇怪的错误

我的YYSTYPE的结构是

%union
{
        char *text;
        node *n;
}
%token <text> NUMBER

,语法规则是

P:
        NUMBER
        {
                cout<<"$1 : "<<$1<<endl;
                int i = 0;
                while($1[i])
                {
                        cout<<"char : "<<$1[i++]<<endl;
                }
                $<n>$->left = $<n>$->right = NULL;
                char *test1 = new char[strlen($1)];
                strcpy(test1, $1);
                cout<<"len : "<<strlen($1)<<"test1 : "<<test1<<endl;
                char *lolz = strdup($1);
                cout<<"dup : "<<((uint64_t)lolz)<<' '<<((int)lolz[1])<<" : dup"<<endl;
                $<n>$->data = string($1);
                cout<<"nd : "<<$<n>$->data<<endl;
                print_tree($<n>$);
        }
        ;

我可以打印$ 1的内容,但是当我执行strlen($ 1)时,它返回0长度 这导致strdup和字符串初始化失败。

输出:

$1 : 65301
char : 6
char : 5
char : 3
char : 0
char : 1
len : 0test1 :
dup : 26935504 0 : dup
Segmentation fault (core dumped)

我错过了一些明显的东西吗?

1 个答案:

答案 0 :(得分:2)

执行时:

$<n>$->left = $<n>$->right = NULL;

你认为$<n>$的价值是多少?您是否已将其分配到node对象的地址?

为了节省你一些时间:你没有分配它,所以你可以把它想象成一个未初始化的指针;取消引用未初始化的指针是Undefined Behavior,它与您看到的内容相对应。

但这种分析并不十分准确。

在执行操作之前,生成bison的解析器会将$$初始化为$1。在这种情况下,$1是已分配text成员的联合,因此使用n成员是(不同的)UB。结果是相同的,但在常见的编译器中,它更容易预测:我认为left的{​​{1}}元素位于偏移0处,因此上面的赋值将覆盖字符串的前16个字节。零(如果您有32位架构,则为8)。这可能是缓冲区溢出,但如果它不是段错误,最终结果是node的第一个字节为0,因此$1的返回值。 (当你尝试使用strlen元素时,它显然是段错误,可能是因为它不是初始化的data。使用零长度的C字符串对于{{{{}}也不是问题。 1}}或std::string构造函数。)

道德:如果你不知道它指向什么,就不要通过指针分配。

顺便说一下,strdup到test1是一个字节的缓冲区溢出。这次你好像已经离开了它,但这是一个坏习惯。