X64调试模式下返回STL容器的函数调试异常咨询
调试X64 Debug模式下返回复杂类型函数的异常调试行为
在X64架构Debug模式调试应用程序时,返回std::string、std::stack、std::vector这类非平凡类型的函数(如fooNoOk、barNook、bar2NoOk)会出现异常调试行为:调试器进入函数后会先跳转到return语句,再执行函数内代码,最后再次跳转至return语句。反汇编显示这类函数的return语句对应代码被生成两次;而返回int类型的foOk函数调试行为完全正常。
测试代码
#include <stack> #include <vector> #include <string> std::stack<std::string> fooNoOk() { std::stack<std::string> s; int r = 0; return s; } std::vector<int> barNook() { std::vector<int> s; int r = 0; return s; } std::string bar2NoOk() { std::string s; int r = 0; return s; } int foOk() { int s{}; int r = 0; return s; } int main() { fooNoOk(); barNook(); bar2NoOk(); foOk(); }
异常函数反汇编示例(fooNoOk)
std::stack<std::string> fooNoOk() { 00007FF63B544D30 mov qword ptr [rsp+8],rcx 00007FF63B544D35 push rbp 00007FF63B544D36 push rdi 00007FF63B544D37 sub rsp,188h 00007FF63B544D3E lea rbp,[rsp+20h] 00007FF63B544D43 lea rdi,[rsp+20h] 00007FF63B544D48 mov ecx,2Ah 00007FF63B544D4D mov eax,0CCCCCCCCh 00007FF63B544D52 rep stos dword ptr [rdi] 00007FF63B544D54 mov rcx,qword ptr [rsp+1A8h] 00007FF63B544D5C mov dword ptr [rbp+144h],0 00007FF63B544D66 lea rcx,[__F9076511_TestReturn@cpp (07FF63B55906Ah)] 00007FF63B544D6D call __CheckForDebuggerJustMyCode (07FF63B54161Dh) std::stack<std::string> s; 00007FF63B544D72 mov edx,28h 00007FF63B544D77 mov rcx,qword ptr [rbp+180h] 00007FF63B544D7E call std::stack<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::deque<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::__autoclassinit2 (07FF63B541280h) 00007FF63B544D83 mov rcx,qword ptr [rbp+180h] 00007FF63B544D8A call std::stack<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::deque<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::stack<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::deque<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > > (07FF63B541532h) 00007FF63B544D8F mov qword ptr [rbp+158h],rax return s; 00007FF63B544D96 mov eax,dword ptr [rbp+144h] 00007FF63B544D9C or eax,1 00007FF63B544D9F mov dword ptr [rbp+144h],eax int r = 0; 00007FF63B544DA5 mov dword ptr [r],0 return s; 00007FF63B544DAC mov rax,qword ptr [rbp+180h] }
正常函数反汇编示例(foOk)
int foOk() { 00007FF63B545500 push rbp 00007FF63B545502 push rdi 00007FF63B545503 sub rsp,128h 00007FF63B54550A lea rbp,[rsp+20h] 00007FF63B54550F lea rcx,[__F9076511_TestReturn@cpp (07FF63B55906Ah)] 00007FF63B545516 call __CheckForDebuggerJustMyCode (07FF63B54161Dh) int s{}; 00007FF63B54551B mov dword ptr [s],0 int r = 0; 00007FF63B545522 mov dword ptr [r],0 return s; 00007FF63B545529 mov eax,dword ptr [s] }
问题原因
这是MSVC Debug模式下的返回值优化与调试信息错位导致的:
- Debug模式为了支持编辑并继续(Edit and Continue)功能,对返回非平凡类型(需要调用构造/析构函数)的函数,会生成额外的代码路径。第一次
return对应的是编译器插入的临时对象初始化标记代码,用于处理返回值的构造逻辑; - 第二次
return才是执行完用户代码后的真正返回操作。调试器的源代码映射因为额外生成的代码出现错位,导致视觉上出现先跳转到return再执行函数体的异常现象; - 返回
int这类平凡类型的函数不需要复杂的返回值构造逻辑,编译器不会生成额外代码路径,因此调试行为完全正常。
内容的提问来源于stack exchange,提问作者amplifier
相关产品推荐
相关产品推荐

