⁉️
__debugbreak() は無視されることがある
はじめに
この記事の結論は __debugbreak
関数は__nop
関数を呼び出してからの使用がベター ということです。
事例
ことの発端は、以下のようなアサーションマクロで発生しました。
// 記事のために改行しているが、本来は一行で記述している
#define DEBUG_ASSERT(expr, error)\
{\
if(!(expr))\
{\
LOG_FATAL("{}: {}, {}, {}", error, __FUNCTION__, __FILE__, __LINE__);\
__debugbreak();\
}\
}
正常な挙動であれば、expr
式がfalse
の場合、コンソール出力と共にデバッガーが一時停止するはずです。しかし、実際にはLOG_FATAL
が出力を行うだけで、__dubugbreak
はブレイクポイントをトリガーさせない場合が存在しました。
// false なのに 停止しない
DEBUG_ASSERT(false, "assertion failed");
解決策
コンパイラのバグでいつか直るだろうと思って諦めつつ、UnrealEngine
のコードを眺めていたところ、解説付きの模範解答ページを発見しました☺️
Source/Runtime/Core/Public/Windows/WindowsPlatform.h
// Q: Why is there a __nop() before __debugbreak()?
// A: VS' debug engine has a bug where it will silently swallow explicit
// breakpoint interrupts when single-step debugging either line-by-line or
// over call instructions. This can hide legitimate reasons to trap. Asserts
// for example, which can appear as if the did not fire, leaving a programmer
// unknowingly debugging an undefined process.
#define PLATFORM_BREAK() (__nop(), __debugbreak())
どうやらデバッガーのバグらしいですが、__nop
の副作用がどのような影響を与えているのかは分かりませんでした。組み込み系? アセンブラ? の知識が必要になってきそうなのでこの辺でやめておきますが、いずれ触れてみたい分野です。
Discussion