我尝试为 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"
我将返回更改为 { const char* r = DEFAULT_FONTNAME;返回 r;
在调试时查看值:r 在返回指令中是正确的。
但是当调试器返回调用函数时,def
指向无效内存。
我在汇编模式下运行调试器,看到了:
const char* def = getDefaultFont();
000007FEDA1244FE call getDefaultFont (07FEDA1291A0h)
000007FEDA124503 cdqe
000007FEDA124505 mov qword ptr [def],rax
在 call
指令之后,RAX 包含正确的值,一个指向 .data 的指针:RAX = 000007FEDA0C9A20
但下一条指令 cqde
“将双字 (eax) 转换为四字 (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
- 在 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
最佳答案
您的链接需要一些我没有的帐户。
您可能没有包含声明该函数的 header ,或者弄乱了 header 顺序。 Here’s more info为什么 C 编译器插入 cdqe
.
附言为什么您应该阅读并修复编译器警告的一个很好的例子。
更新:如果您有循环依赖问题并且不能只包含 utils.h,一个快速的解决方法是在 emit 中声明 const char * getDefaultFont();
。 c 在调用该函数之前。
关于c - visual studio 2013 截断 x64 中返回的指针值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49455189/