visual studio 2013 截断 x64 中返回的指针值
visual studio 2013 truncates returned pointer value in x64
我尝试为 x64 编译 wingraphviz(这是一个旧的、无人维护的项目),并且 运行 变成了一个非常 st运行ge 的问题:
有一个对 getDefaultFont()
的调用,如下所示:
const char* def = getDefaultFont();
Deffontname = late_nnstring(g->proto->n,N_fontname,def);
(原代码是在函数调用里面调用的,为了理解我提取出来了)
getDefaultFont
函数非常简单,return是一个基于当前字符集的字符串乱码:
const char * getDefaultFont() {
switch(DOT_CODEPAGE) {
case CP_KOREAN:
return CP_949_DEFAULTFONT;
break;
[...]
default:
return DEFAULT_FONTNAME;
break;
}
}
with DEFAULT_FONTNAME
& others defined in a header file:
#define DEFAULT_FONTNAME "Times New Roman"
我将 return 更改为 { const char* r = DEFAULT_FONTNAME; return r; }
以在调试时查看值:r 在 return 指令处是正确的。
但是当调试器return调用函数时,def
指向无效内存。
我 运行 汇编模式下的调试器,看到了:
const char* def = getDefaultFont();
000007FEDA1244FE call getDefaultFont (07FEDA1291A0h)
000007FEDA124503 cdqe
000007FEDA124505 mov qword ptr [def],rax
在 call
指令之后,RAX 包含正确的值,一个指向 .data 的指针:RAX = 000007FEDA0C9A20
但是下一条指令 cqde
"Convert dword (eax) to qword (rax)." 破坏了 4 个高位字节,现在 RAX = FFFFFFFFDA0C9A20。然后第三个将截断的值存储在堆栈上。
之后,late_nnstring() 尝试取消引用损坏的指针并崩溃...
你知道VS为什么要插入这个cqde
指令吗?
所有这些功能都在同一个项目下的.c文件中。
我已经实现了一个解决方法,使用 strdup() 到 return 低内存地址,但它不安全(也许堆可以在 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
您的链接需要一些我没有的帐户。
您可能没有包含 header 声明该函数,或者弄乱了 header 的顺序。 Here’s more info 为什么 C 编译器插入 cdqe
.
P.S。为什么您应该阅读并修复编译器警告的一个很好的例子。
更新: 如果你有循环依赖问题并且不能只包含 utils.h,一个快速的解决方法是在 [=25= 中声明 const char * getDefaultFont();
] 在调用该函数之前。
我尝试为 x64 编译 wingraphviz(这是一个旧的、无人维护的项目),并且 运行 变成了一个非常 st运行ge 的问题:
有一个对 getDefaultFont()
的调用,如下所示:
const char* def = getDefaultFont();
Deffontname = late_nnstring(g->proto->n,N_fontname,def);
(原代码是在函数调用里面调用的,为了理解我提取出来了)
getDefaultFont
函数非常简单,return是一个基于当前字符集的字符串乱码:
const char * getDefaultFont() {
switch(DOT_CODEPAGE) {
case CP_KOREAN:
return CP_949_DEFAULTFONT;
break;
[...]
default:
return DEFAULT_FONTNAME;
break;
}
}
with DEFAULT_FONTNAME
& others defined in a header file:
#define DEFAULT_FONTNAME "Times New Roman"
我将 return 更改为 { const char* r = DEFAULT_FONTNAME; return r; }
以在调试时查看值:r 在 return 指令处是正确的。
但是当调试器return调用函数时,def
指向无效内存。
我 运行 汇编模式下的调试器,看到了:
const char* def = getDefaultFont();
000007FEDA1244FE call getDefaultFont (07FEDA1291A0h)
000007FEDA124503 cdqe
000007FEDA124505 mov qword ptr [def],rax
在 call
指令之后,RAX 包含正确的值,一个指向 .data 的指针:RAX = 000007FEDA0C9A20
但是下一条指令 cqde
"Convert dword (eax) to qword (rax)." 破坏了 4 个高位字节,现在 RAX = FFFFFFFFDA0C9A20。然后第三个将截断的值存储在堆栈上。
之后,late_nnstring() 尝试取消引用损坏的指针并崩溃...
你知道VS为什么要插入这个cqde
指令吗?
所有这些功能都在同一个项目下的.c文件中。
我已经实现了一个解决方法,使用 strdup() 到 return 低内存地址,但它不安全(也许堆可以在 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
您的链接需要一些我没有的帐户。
您可能没有包含 header 声明该函数,或者弄乱了 header 的顺序。 Here’s more info 为什么 C 编译器插入 cdqe
.
P.S。为什么您应该阅读并修复编译器警告的一个很好的例子。
更新: 如果你有循环依赖问题并且不能只包含 utils.h,一个快速的解决方法是在 [=25= 中声明 const char * getDefaultFont();
] 在调用该函数之前。