【问题标题】:How to get the name/description of an exception?如何获取异常的名称/描述?
【发布时间】:2023-03-24 21:42:01
【问题描述】:

您如何获得SEH 异常的名称和/或描述,而无需将字符串硬编码到您的应用程序中?

我尝试使用FormatMessage(),但有时它会截断消息,即使您指定忽略插入:

__asm { // raise access violation
    xor    eax, eax
    mov    eax, [eax]
}

使用代码0xC0000005 (EXCEPTION_ACCESS_VIOLATION) 引发异常。

char msg[256];
FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
    GetModuleHandleA("ntdll.dll"), 0xC0000005,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    msg, sizeof(msg), NULL);

用截断的字符串填充msg:“The instruction at 0x”。

【问题讨论】:

  • 哇,这确实看起来很糟糕。它适用于各种消息,但我无法让它在我的一生中为 STATUS_ACCESS_VIOLATION 工作。
  • 我现在对此有点生疏了,但是您尝试过 FORMAT_MESSAGE_FROM_SYSTEM 吗?
  • morechilli:是的,我已经尝试过了,但它不会改变结果。

标签: windows winapi exception


【解决方案1】:

结构化异常代码通过 NTSTATUS 编号定义。尽管来自 MS suggests 的某人使用 FormatMessage() 将 NTSTATUS 数字转换为字符串,但我不会这样做。标志FORMAT_MESSAGE_FROM_SYSTEM 用于将GetLastError() 的结果转换为字符串,所以这里没有意义。将标志 FORMAT_MESSAGE_FROM_HMODULEntdll.dll 一起使用会导致某些代码的结果不正确。例如,对于EXCEPTION_ACCESS_VIOLATION,你会得到The instruction at 0x,这不是很丰富:)。

当您查看存储在ntdll.dll 中的字符串时,很明显它们中的许多应该与printf() 函数一起使用,而不是与FormatMessage() 一起使用。例如,EXCEPTION_ACCESS_VIOLATION 的字符串为:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0FormatMessage() 视为转义序列,意思是消息终止符,而不是插入。插入是 %1 到 %99。这就是为什么标志 FORMAT_MESSAGE_IGNORE_INSERTS 没有任何区别。

您可能希望从ntdll.dll 加载字符串并将其传递给vprintf(),但您需要完全按照字符串指定的方式准备参数(例如,对于EXCEPTION_ACCESS_VIOLATION,它是unsigned longunsigned long、@987654342 @)。这种方法有一个主要缺点:ntdll.dll 中参数的数量、顺序或大小的任何更改都可能会破坏您的代码。

因此,将字符串硬编码到您自己的代码中会更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是很危险的:) 以及其他功能。这只是故障的另一种可能性。

【讨论】:

  • 这太糟糕了,但已经来不及改变了。
  • @davidbak 出了什么问题?
  • 他们最初(在创建 NT 时)有充分的机会制作这些正确的事件日志字符串(%1 样式格式),而是将它们制作为 printf 格式字符串。然后他们从未提供过替代品。必须有数百个程序(如果不是数千个)具有特殊代码来格式化 AV 以进行日志记录。
【解决方案2】:
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 2011-02-24
  • 1970-01-01
  • 2021-08-19
  • 2013-09-09
  • 1970-01-01
  • 2011-04-08
  • 2018-06-18
相关资源
最近更新 更多