STATUS_REPARSE不是“失败”
曾经在过滤驱动中想针对REPARSE的情况做特殊处理,实现代码如下:
if (NT_SUCCESS(status)) {
/* file created */
} else if (STATUS_REPARSE == status) {
/* to be repared */
} else {
...
}
结果代码运行没达有预期效果,手工调试时才发现代码进入了NT_SUCCESS(status)分支。STATUS_REPARSE竟然表示是“成功”的!
这件事后才真正注意到status的问题,虽然在学习内核及驱动编程的时候书上都有相关介绍,但这些基础章节并没有引起重视就直接跳过了。但是像STATS_REPARSE这样的特例并不是少数,如STATUS_PENDING、STATUS_TIMEOUT等。
NTSTATUS的定义
再回顾一下NTSTATUS的定义: NTSTATUS是一个32位长的有符号整型数,即LONG型。其格式如下:
3 2 1 0
1 0|9|8|7 6 5 4 3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
---+-+-+-----------------------+-------------------------------
S |C|N| Facility | Code
---------------------------------------------------------------
各部分的解释如下:
位数 | 注解 | |
---|---|---|
S | 2 | Severity: 分4个等级(Success, Informational, Warning, Error) |
C | 1 | 1:用户自定义的值 0:默认为系统定义(Microsoft) |
N | 1 | 保留位,始终为0值 |
Facility | 12 | 错误类别或子系统的划分 |
Code | 16 | 具体错误代码 |
Severity的4个等级的定义如下:
00 - Success
01 - Informational
10 - Warning
11 - Error
NT_XXXX宏分析
引用WDK代码(ntdef.h):
//
// Generic test for success on any status value (non-negative numbers
// indicate success).
//
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
//
// Generic test for information on any status value.
//
#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)
//
// Generic test for warning on any status value.
//
#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)
//
// Generic test for error on any status value.
//
#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)
由定义可以看出至少两点:
-
NT_SUCCESS的定义和其它三者是有区别的,并不是根据Severity的值来判断的。NT_SUCCESS(status)其实包含了Severity == 0及Severity == 1的情形。
- NT_SUCCESS与NT_ERROR不是单纯的非黑即白的关系。新手常犯的错误就是主观上认为NT_SUCCESS()与!NT_ERROR(),或者NT_ERROR()与!NT_SUCCESS()是等价。
如果想确保一个irp确实是“成功”完成了,就要严格用STATUS_SUCCESS来判断,而不是NT_SUCCESS()。类似地,用NT_ERROR()可以保证代码的执行确实出现了错误,但是NT_WARNING()的情况即被漏掉了。
总之,必要的基本功始终是不可少的,像熟悉开发场景相关的返回值并弄懂这些返回值的确切含义等此类的苦活累活是必须要做且要做好的。
参考链接
<本文用时2小时,字体及表格调整花时较多。>