用简单的代码以奇怪的顺序触发断点

huangapple go评论71阅读模式
英文:

Hitting breakpoints in strange order with simple code

问题

我在处理一些C++代码,发现断点的命中顺序很奇怪,我不明白为什么。我正在使用Visual Studio 2022,cl.exe版本为19.35.32215,link.exe版本为14.35.32215.0。作为一个简单的复现,我创建了一个新的C++控制台应用程序,代码如下:

#include <vector>

std::vector<int> DoSomething()
{
  std::vector<int> results;
  results.push_back(55);
  return results;
}

int main()
{
  std::vector<int> results = DoSomething();
  return 0;
}

我在以下两行上设置了断点:

  results.push_back(55);
  return results;

当第一个断点命中时,是"return results;",让我感到非常惊讶。如果我继续执行代码,我会回到"results.push_back(55);",然后继续到"return results;"。

我预期会按照它们在代码中的顺序命中两个断点(即先是"results.push_back(55)",然后是"return results;")。我尝试了x64和x86的Debug构建,两者都出现了相同的断点怪异情况。

我还尝试检查反汇编代码,弹出一个框让我“解决歧义”:
解决歧义弹出框

我还没有尝试在gcc或clang中使用相同的代码。

有人能帮我解释一下发生了什么吗?我觉得我可能漏掉了一些显而易见的东西,但我不知道是什么。

谢谢!

英文:

I was working on some C++ code and noticed my breakpoints were getting hit in a strange order and I don't understand why. I'm using Visual Studio 2022 with cl.exe version 19.35.32215 and link.exe version 14.35.32215.0. As a simple reproduction I created a new C++ console app with the following code:

#include &lt;vector&gt;

std::vector&lt;int&gt; DoSomething()
{
  std::vector&lt;int&gt; results;
  results.push_back(55);
  return results;
}

int main()
{
  std::vector&lt;int&gt; results = DoSomething();
  return 0;
}

I put breakpoints on the following two lines:

  results.push_back(55);
  return results;

I was very surprised when the first breakpoint hit was "return results;". If I continue code execution I bounce back to "results.push_back(55);" and then move on to "return results;" again.

I was expecting to hit my two breakpoints in their line ordering (i.e. "results.push_back(55)" first, then "return results;"). I've tried both x64 and x86 with a Debug build and both have the same breakpoint weirdness.

I also tried inspecting the disassembly and a box pops up asking me to "Resolve Ambiguity":
Resolve Ambiguity popup

I have not tried this same code with gcc or clang.

Can anyone help explain to me what's going on? I feel like I'm missing something obvious, but I don't know what.

Thanks!

答案1

得分: 3

如果在编译器中使用 /permissive-,则即使在调试配置中也会应用可选的 NVRO。它在调用者的堆栈帧上为返回的对象分配内存,并传递指向被调用函数的指针。这可能会让调试器感到困惑,因为它可能将 return results 视为在 push_back() 之前应执行的对象构造和初始化,但 return 实际上位于代码中 push_back() 之后,因此它的行为类似于:用户在第 N 行设置断点,但我已经跳过到第 N+1 行,我必须在这里停止。

您可以使用 /Zc:nrvo- 禁用 NVRO。

英文:

If you use /permissive- in the compiler, then it applies the optional NVRO even in the Debug configuration. It allocates memory for a returned object on the caller stack frame and passes a pointer to a called function. It can confuse the debugger, that can see return results as object construction and initialization that of course should be performed before push_back(), but return is located in the code after push_back(), so it behaves like: user set the breakpoint on the line N, but I have jumped over on the line N+1, I must stop here.

You can disable NVRO with using /Zc:nrvo-.

huangapple
  • 本文由 发表于 2023年2月27日 08:07:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575800.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定