YACC - $1 的 strlen 是 0 尽管有字符串

YACC - strlen of $1 is 0 although string is there

我的程序出现奇怪的错误

我的YYSTYPE的结构是

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

语法规则是

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

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

输出:

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

我是不是漏掉了什么明显的东西?

当你执行:

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

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

为了节省你一些时间:你还没有分配它所以你可以把它当作一个未初始化的指针;取消引用未初始化的指针是未定义的行为,对应于您所看到的。

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

bison 生成的解析器在执行操作之前将 $$ 初始化为 </code>。在这种情况下,<code> 是一个联合,其 text 成员已分配给,因此使用 n 成员是(不同的)UB。结果是一样的,但在普通编译器中它更可预测:我假设 nodeleft 元素位于偏移量 0,因此上面的赋值会覆盖字符串的前 16 个字节零(如果您有 32 位体系结构,则为 8)。这可能是缓冲区溢出,但如果它没有出现段错误,最终结果是 </code> 的第一个字节为 0,因此 <code>strlen 的 return 值。 (当您尝试使用 data 元素时,它显然会出现段错误,大概是因为它不是初始化的 std::string。使用零长度的 C 字符串对于 strdupstd::string 构造函数。)

道德:如果您不知道指针指向什么,请不要通过指针进行赋值。


顺便说一句,test1 的strcpy 是一个字节的缓冲区溢出。这次你好像逃过了一劫,但这是个坏习惯。