为什么使用 /Og 和 /GL 标志以及引用传递时会发生这种访问冲突?
当(且仅当)我使用 Windows Server 2003 DDK C++ 编译器使用 /Og
和 /GL
标志编译我的程序时(在 WDK 7.1 和 Visual Studio 2010 上很好!),当我运行此命令时,我遇到了访问冲突:
#include <algorithm>
#include <vector>
template<typename T> bool less(T a, T b) { return a < b; }
int main()
{
std::vector<int> s;
for (int i = 0; i < 13; i++)
s.push_back(i);
std::stable_sort(s.begin(), s.end(), &less<const int&>);
}
当我运行此命令时,访问冲突消失了改变最后一个换句话说
std::stable_sort(s.begin(), s.end(), &less<int>);
,当我让我的项目被复制而不是仅仅被引用时,它就会消失。
(我没有进行任何类型的多线程。)
为什么会发生这样的事情?我是否通过传递 const & 来调用一些未定义的行为?
编译器标志:
<前><代码> /Og /GL /MD /EHsc链接器标志:(无)
包含环境变量:
<前><代码> C:\WinDDK\3790.1830\inc\crtLIB 环境变量:
<预><代码> C:\WinDDK\3790.1830\lib\crt\I386;C:\WinDDK\3790.1830\lib\wxp\I386操作系统:Windows 7 x64
平台:32位编译出错(64位运行正确)
编辑:
我刚刚使用 Windows XP DDK(即 C:\WinDDK\2600
)尝试过,我得到:
error LNK2001: unresolved external symbol
"bool __cdecl less(int const &,int const &)" (?less@@YA_NABH0@Z)
但是 当我将它从模板更改为常规函数时,它神奇地与两个编译器一起工作!
我怀疑这意味着我发现了使用 DDK 编译器获取模板化函数的地址时发生的错误。如果可能是这种情况,或者这是我不知道的不同的极端情况,有什么想法吗?
When (and only when) I compile my program with the /Og
and /GL
flag using the Windows Server 2003 DDK C++ compiler (it's fine on WDK 7.1 as well as Visual Studio 2010!), I get an access violation when I run this:
#include <algorithm>
#include <vector>
template<typename T> bool less(T a, T b) { return a < b; }
int main()
{
std::vector<int> s;
for (int i = 0; i < 13; i++)
s.push_back(i);
std::stable_sort(s.begin(), s.end(), &less<const int&>);
}
The access violation goes away when I change the last line to
std::stable_sort(s.begin(), s.end(), &less<int>);
-- in other words, it goes away when I let my item get copied instead of merely referenced.
(I have no multithreading of any sort going on whatsoever.)
Why would something like this happen? Am I invoking some undefined behavior through passing by const &
?
Compiler flags:
/Og /GL /MD /EHsc
Linker flags: (none)
INCLUDE environmental variable:
C:\WinDDK\3790.1830\inc\crt
LIB environmental variable:
C:\WinDDK\3790.1830\lib\crt\I386;C:\WinDDK\3790.1830\lib\wxp\I386
Operating system: Windows 7 x64
Platform: 32-bit compilation gives error (64-bit runs correctly)
Edit:
I just tried it with the Windows XP DDK (that's C:\WinDDK\2600
) and I got:
error LNK2001: unresolved external symbol
"bool __cdecl less(int const &,int const &)" (?less@@YA_NABH0@Z)
but when I changed it from a template to a regular function, it magically worked with both compilers!
I'm suspecting this means that I've found a bug that happens while taking the address of a templated function, using the DDK compilers. Any ideas if this might be the case, or if it's a different corner case I don't know about?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在 Windows Server 2003 DDK SP1 安装中尝试了这一点(非 SP1 DDK 目前还不易获得)。这使用 80x86 的 cl.exe 版本 13.10.4035。它似乎与您发现的问题相同。
如果您在调试器中单步调试代码(通过使用() 的函数(名为
/FAsc
选项生成的 .cod 文件会变得更容易),您会发现less()
函数期望使用指向eax
和edx
中传递的int
值的指针来调用。但是,调用 less_Insertion_sort_1<>()
)调用它来传递堆栈上的指针。如果将模板化的
less
函数变成非模板化函数,它期望参数在堆栈上传递,所以每个人都很高兴。更有趣的是,当您将
less
更改为less
时会发生什么。没有崩溃,但也没有任何内容被排序(当然,您需要更改程序以从未排序的向量开始才能真正看到这种效果)。这是因为当您更改为less
时,less
函数不再取消引用任何指针 - 它期望在寄存器中传递实际的 int 值 (ecx<在本例中为 /code> 和
edx
)。但没有指针取消引用就意味着不会崩溃。但是,调用方_Insertion_sort_1
仍然在堆栈上传递参数,因此less
执行的比较与向量中的值无关。这就是正在发生的事情,但我真的不知道根本原因是什么 - 正如其他人提到的,它看起来像是与优化相关的编译器错误。
由于该错误显然已被修复,因此报告它显然没有意义(该版本的 DDK 中的编译器对应于接近 VS 2003/VC 7.1 的编译器)。
顺便说一句 - 我无法让你的示例完全干净地编译 - 为了让它完全构建,我必须包含 bufferoverflowu.lib 来获取要链接的堆栈检查内容,甚至然后链接器抱怨“发现多个具有不同属性的‘.rdata’部分”。我似乎记得这是一个可以安全忽略的警告,但我真的不记得了。但我认为这两者都与该错误无关。
I tried this with a Windows Server 2003 DDK SP1 installation (the non-SP1 DDK isn't readily available at the moment). This uses cl.exe version 13.10.4035 for 80x86. It appears to have the same problem you've found.
If you step through the code in a debugger (which is made a bit easier by following along with the .cod file generated using the
/FAsc
option) you'll find that theless<int const &>()
function expects to be called with the pointers to theint
values passed ineax
andedx
. However, the function that callsless<int const&>()
(named_Insertion_sort_1<>()
) calls it passing the pointers on the stack.If you turn the templated
less
function into a non-templated function, it expects the parameters to be passed on the stack, so everyone is happy.Of a bit more interest is what happens when you change
less<const int&>
to beless<int>
instead. There's no crash, but nothing gets sorted either (of course, you'd need to change your program to start out with a non-sorted vector to actually see this effect). That's because when you change toless<int>
theless
function no longer dereferences any pointers - it expects the actual int values to be passed in registers (ecx
andedx
in this case). But no pointer dereference means no crash. However, the caller,_Insertion_sort_1
, still passes the arguments on the stack, so the comparison being performed byless<int>
has nothing to do with the values in the vector.So that's what's happening, but I don't really know what the root cause is - as others have mentioned, it looks like a compiler bug related to the optimizations.
Since the bug has apparently been fixed, there's obviously no point in reporting it (the compiler in that version of the DDK corresponds to something close to VS 2003/VC 7.1).
By the way - I was unable to get your example to compile completely cleanly - to get it to build at all, I had to include the
bufferoverflowu.lib
to get the stack checking stuff to link, and even then the linker complained about "multiple '.rdata' sections found with different attributes". I seem to remember that being a warning that was safe to ignore, but I really don't remember. I don't think either of these has anything to do with the bug though.如果您在较新的编译器上没有得到它,则很可能是一个错误。
你有一个小型的独立复制品吗?
If you don't get it on newer compilers, it's most likely a bug.
Do you have a small self-contained repro?