【发布时间】:2018-09-02 10:57:52
【问题描述】:
我尝试为 x64 编译 wingraphviz(这是一个旧的、无人维护的项目),但遇到了一个非常奇怪的问题:
对getDefaultFont() 的调用如下所示:
const char* def = getDefaultFont();
Deffontname = late_nnstring(g->proto->n,N_fontname,def);
(原代码在函数调用中做了调用,但我把它提取出来以便理解)
getDefaultFont 函数非常简单,根据当前字符集返回一个字符串:
const char * getDefaultFont() {
switch(DOT_CODEPAGE) {
case CP_KOREAN:
return CP_949_DEFAULTFONT;
break;
[...]
default:
return DEFAULT_FONTNAME;
break;
}
}
在头文件中定义DEFAULT_FONTNAME 和其他人:
#define DEFAULT_FONTNAME "Times New Roman"
我把return改成{ const char* r = DEFAULT_FONTNAME; return r; }调试的时候看值:r在return指令是正确的。
但是当调试器返回调用函数时,def 指向无效内存。
我在汇编模式下运行调试器,看到了:
const char* def = getDefaultFont();
000007FEDA1244FE call getDefaultFont (07FEDA1291A0h)
000007FEDA124503 cdqe
000007FEDA124505 mov qword ptr [def],rax
在call 指令之后,RAX 包含正确的值,一个指向 .data 的指针:RAX = 000007FEDA0C9A20
但下一条指令,cqde“将 dword (eax) 转换为 qword (rax)。”销毁高 4 个字节,现在 RAX = FFFFFFFFDA0C9A20。然后第三个将截断的值存储在堆栈中。
之后,late_nnstring() 尝试取消引用损坏的指针并崩溃...
你知道为什么 VS 会插入这个cqde 指令吗?
所有这些函数都在同一个项目下的.c文件中。
我已经实现了一个解决方法,使用 strdup() 返回低内存地址,但这并不安全(也许堆可以在 4G 之后使用内存?)(还有一些我在测试时没有发现的其他情况使用库时会崩溃)
我在这里发布了文件:https://gitlab.com/data-public/wingraphviz
尤其是:
- 来电者https://gitlab.com/data-public/wingraphviz/blob/97085eeb6e9356c7784965c5a43757d8db3fec41/dependencies/graphviz-1.8.10/dotneato/common/emit.c#L842
- getDefaultFont 在https://gitlab.com/data-public/wingraphviz/blob/97085eeb6e9356c7784965c5a43757d8db3fec41/dependencies/graphviz-1.8.10/dotneato/common/utils.c#L111
- 常量定义在https://gitlab.com/data-public/wingraphviz/blob/97085eeb6e9356c7784965c5a43757d8db3fec41/dependencies/graphviz-1.8.10/dotneato/common/const.h#L49
【问题讨论】:
-
gitlab项目配置错误,现已公开
标签: c visual-studio assembly compilation 64-bit