我的程序中出现了一个奇怪的错误
我的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)
我错过了一些明显的东西吗?
答案 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是一个字节的缓冲区溢出。这次你好像已经离开了它,但这是一个坏习惯。