1

It's more of a curiosity than anything else. I've been reviewing the HRESULT error codes that many Win32 APIs and Windows components return to signify errors.

If I understand its structure correctly, the most significant bit 31 is the error bit. If it's set, then HRESULT contains an error.

For instance, 0x80004002 is E_NOINTERFACE:

No such interface supported.

But what happens when two of its most significant bits are set as in 0xC0262588? What makes it different?

That value above also seems to translate to an error, which is ERROR_GRAPHICS_MCA_INTERNAL_ERROR:

An internal Monitor Configuration API error occurred.

EDIT: The documentation declares such values to be invalid but then goes on to list multiple supposedly invalid values.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • Since `HRESULT` is typedef'd as `long`, the first bit for errors a way to check the result with a generic `if (value < 0)`. – Giovanni Cerretani Jan 04 '19 at 08:11
  • If you read the document that you linked to which explains the structure, this is an invalid `HRESULT` value. – David Heffernan Jan 04 '19 at 08:31
  • 1
    @DavidHeffernan: Yes, I could see that. But then there's a quarter of [this page](https://msdn.microsoft.com/en-us/library/cc704587.aspx?f=255&MSPPError=-2147217396) full of `HRESULT` codes that start with `0xC`. That's what I'm trying to understand. MS clearly violated that rule. – c00000fd Jan 04 '19 at 08:35
  • Yes, I can see that. The question would, in my view, be better if you pointed out this contradiction and asked specifically about it. – David Heffernan Jan 04 '19 at 08:38
  • 1
    @DavidHeffernan: I thought I linked to that page in my original post. – c00000fd Jan 04 '19 at 08:39
  • 1
    The question should explicitly state that the documentation declares such values to be invalid but then goes on to list multiple supposedly invalid values. As it stands, it is not at all obvious that you were aware that the documentation declared such values to be invalid. You made no mention of what it said about bit 30 and for all we know you had not read that part of the documentation. When asking a question, make it clear to the readers the extent of your knowledge and research. – David Heffernan Jan 04 '19 at 08:47
  • @DavidHeffernan: OK, if that makes you look it in a different light... just added that line. – c00000fd Jan 04 '19 at 08:49
  • with `NTSTATUS` exist serious different between `8xxxxxxx` and `cxxxxxxx` status returned from I/O request - are information will be copied (only with 8) are will be iocp or apc completion (if status 8xxxxxxx returned by device) but with `HRESULT` think no such different. with it at all not clear in general case how we need check returned `hr` - `(0 <= hr)` or `(hr == 0)` ? say `hr == S_FALSE(1)` this is error or ok code ? – RbMm Jan 04 '19 at 11:02
  • @RbMm I think there's a language problem with that comment. I'm afraid I cannot make sense of it. Would you be able to rephrase it please? – David Heffernan Jan 04 '19 at 12:27
  • @DavidHeffernan sorry. i try say that in case [ntstatus](https://msdn.microsoft.com/en-us/library/cc231200.aspx) value exist strict rules related to Sev (2 bits) code. based on which we can detect are will be io completion notification after io, etc. but in case `hreasult` - no such strict rules. frequently even not clear how correct detect result of interface call - compare it as `0 <= hr` or `0 == hr`. are say `1 (S_FALSE)` this is ok or error code. so i think in case `hresult we can simply ignore 8 vs c in high bits. in ntstatus - not – RbMm Jan 04 '19 at 12:35
  • 2
    in case [Using NTSTATUS](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values) exist significant different between `NT_WARNING(Status)` and `NT_ERROR(Status)` (8 vs c) which we take into account in the code (for example [copy data](https://github.com/Zer0Mem0ry/ntoskrnl/blob/master/Io/iomgr/internal.c#L1224) and [completion](https://github.com/Zer0Mem0ry/ntoskrnl/blob/master/Io/iomgr/internal.c#L1292). but in case `HRESULT` we can simply ignore different between 8xxxxxxx and cxxxxxxx – RbMm Jan 04 '19 at 13:22
  • It may be a kernel `NTSTATUS` code that's mapped exactly as a Windows `HRESULT` code, i.e. the same severity and facility code. Most likely the NT status code is defined in shared/ntstatus.h, and the Windows error code is defined in shared/winerror.h. In this case the associated message has to be available in both ntdll.dll and kernelbase.dll (or kernel32.dll), respectively for `NTSTATUS` and `HRESULT` functions. The facility code that's assigned to the kernel componenet has to be available in both domains. – Eryk Sun Jan 07 '19 at 08:37
  • Examples include `FACILITY_HYPERVISOR` (0x035), `FACILITY_VIRTUALIZATION` (0x037), `FACILITY_VOLMGR` (0x038; volmgr.sy, volmgrx.sys), `FACILITY_BCD` (0x039), `FACILITY_VHD` (0x03A; vhdmp.sys), `FACILITY_SHARED_VHDX` (0x05C; svhdxflt.sys), `FACILITY_SMB` (0x05D), `FACILITY_SECURITY_CORE` (0x0E8), and `FACILITY_LICENSING` (0x0EA). – Eryk Sun Jan 07 '19 at 08:37
  • Or a system API may use a two-bit severity code because it's coupled with kernel components such as device drivers, but without a direct mapping between `NTSTATUS` and `HRESULT` codes. The status message is only in kernelbase.dll (or kernel32.dll), but there's no confusion. We don't route message-lookup based on the severity code. If an `HRESULT` function needs to return an `NTSTATUS` code, it uses the `HRESULT_FROM_NT` macro to set the NT bit. Callers that do the right thing will clear the bit and either retrieve the message from ntdll.dll or map the status code via `RtlNtStatusToDosError`. – Eryk Sun Jan 07 '19 at 08:39
  • Examples include `FACILITY_SECURITY` (0x009); `FACILITY_USERMODE_HNS` (0x03B); `FACILITY_GRAPHICS` (0x026; monitor.sys, dxgkrnl.sys), as mentioned in the question; `FACILITY_NDIS` (0x034; ndis.sys); and `FACILITY_[MEDIASERVER|NS|MF]` (0x00D; see um/nserror.h, um/mferror.h, um/asferr.h, and winrt/dlnaerror.h; they even define the `STATUS_SEVERITY` macro). – Eryk Sun Jan 07 '19 at 08:41
  • @eryksun: so what you're saying is that decades of development created this mess? – c00000fd Jan 07 '19 at 09:04
  • Not necessarily. Many of these are relatively new system facilities. For example, NT `FACILITY_VOLMGR` has `STATUS_VOLMGR_INCOMPLETE_REGENERATION` (0x80380001) and `STATUS_VOLMGR_DATABASE_FULL` (0xC0380001), and WinAPI `FACILITY_USERMODE_VOLMGR` (0x038) has `ERROR_VOLMGR_INCOMPLETE_REGENERATION` (0x80380001) and `ERROR_VOLMGR_DATABASE_FULL` (0xC0380001). It's the same set of codes made available simultaneously to two separate APIs. – Eryk Sun Jan 07 '19 at 09:34

1 Answers1

2

From the Structures of HRESULT definition, 0x8 and 0xC is different at "R" bit and if the N bit is set, this bit is defined by the NTSTATUS numbering space. In NTSTATUS definition, 0x8 indicate STATUS_SEVERITY_WARNING and 0xC indicate STATUS_SEVERITY_ERROR.

enter image description here

enter image description here

Ref: "[MS-ERREF]: Windows Error Codes"

Rita Han
  • 9,574
  • 1
  • 11
  • 24
  • The question is about why there are many `HRESULT` values defined with a two-bit severity code in shared/winerror.h, um/nserror.h, um/mferror.h, and winrt/dlnaerror.h. In many cases, it's simply that the same set of codes are made available as `NTSTATUS` and (improper) `HRESULT` values by defining the same facility code in both domains and storing the same messages for the status codes in both ntdll.dll.mui and kernelbase.dll.mui. But other HRESULT-only facilities also have these strictly improper severity codes. See my comments on the question itself for examples. – Eryk Sun Jan 07 '19 at 10:12
  • This documentation looks weird, because it excludes the value 0xC0 in the MSB: if `N` is zero, `R` must be zero. But such values exist as already the question and some comments show. Further the bit number line is in wrong order. MSB is *left*. – harper Jan 07 '19 at 12:49
  • @harper yes, I agree with you about this document and I am researching and confirming internal. As for bit order, there is such sentence "Values are 32 bit and are laid out as follows. The following diagram is independent of endianness; that is, the diagram is shown in host byte order and merely shows the layout of the numbering space." Does it clear your confusion? – Rita Han Jan 08 '19 at 07:16
  • @eryksun In the document I refered to it says that it is possible to map an NTSTATUS value to an equivalent HRESULT value. And I search the oxC codes in HRESULT, for example, AUDITING_DISABLED(The specified event is currently not being audited.) you will see the similar one listed in NTSTATUS. But I don't know what's the map rules. Can this explain what you have found in header files? – Rita Han Jan 08 '19 at 07:27
  • `STATUS_AUDITING_DISABLED` and `ERROR_AUDITING_DISABLED` are related in practice, but the codes have nothing to do with each other (i.e. 0xC0000356 vs 0xC0090001). The former is in the `NTSTATUS` System facility (0x000), and the latter is in the `HRESULT` Security facility (0x009). We can flag the former with the NT facility bit (i.e. `0xC0000356 | 0x10000000 == 0xD0000356`) if returned as an `HRESULT`. Users should clear the NT bit and look up the message for 0xC0000356 in ntdll.dll. OTOH, 0xC0090001 is an `HRESULT`, not an `NTSTATUS` code, and its message is in kernelbase.dll, not ntdll.dll. – Eryk Sun Jan 08 '19 at 09:59
  • By being related in practice, I mean that `RtlNtStatusToDosError(STATUS_AUDITING_DISABLED) == ERROR_AUDITING_DISABLED`. We have an API on the boundary between NT and Windows, but they're not copying `NTSTATUS` codes directly as `HRESULT` codes. They can't do that in this case. And for whatever reason (I guess convenient error lookup), they're also not returning them wrapped as an `HRESULT` with the NT bit set. So they cherry pick and change codes, e.g. informational (not an error) `STATUS_BIZRULES_NOT_ENABLED` (0x40000034) maps to `ERROR_BIZRULES_NOT_ENABLED` (0xC0090003). – Eryk Sun Jan 08 '19 at 10:25
  • @RitaHan-MSFT The bit number bar shows the bit 31 at the right side, but the bit 32 is the `S` bit. This bit is notated left. That's just wrong. The endianess isn't relevant here since placement of bytes in memory is not included in the documentaion. Just lookup the `C` bit in the graphic. Move some pixels up and ... check if you get the correct bit number. I am convinced you don't find a match. – harper Jan 09 '19 at 12:12
  • @harper Yes, I know what you mean. The bit order looks misleading. Thanks for pointing it out. – Rita Han Jan 10 '19 at 01:20
  • @RitaHan-MSFT Per [Microsoft Open Specifications 2.1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/3caa4769-b02f-4cee-a857-8496f4395ec1) (MS-ERRREF is a Microsoft Open Specification) "the bit numbering convention followed is the same as that used in RFCs, namely: the high (most significant) bit of the first byte to hit the wire is in packet bit 0, and the low bit of the last byte to hit the wire is in packet bit 31 (so that the bits are shown from left-to-right in the order they naturally appear over the network)". IME such a convention is common at the hardware level. – alx9r Dec 15 '20 at 16:36
  • @ErykSun `ERROR_AUDITING_DISABLED` is a Win32 error code and not an HRESULT error code So that's why it differs more than by 1 bit from `STATUS_AUDITING_DISABLED`. Windows has HRESULT, NTSTATUS and Win32 error codes. – Sergey Podobry Apr 05 '22 at 14:21