String buffers and IRQL

from https://blogs.msdn.microsoft.com/doronh/2006/03/03/string-buffers-and-irql/

If you look at the docs for many Rtl string functions, you will see that they are callable only at IRQL == PASSIVE_LEVEL.  This applies to not only Rtl functions but also to CRT functions Why is that?  Well, there are a few resaons

如果你查看Rtl系统字符串函数的文档说明,你会看到它们仅当IRQL处于Passive级别是才可以被调用。这个规则不仅仅用于Rtl系列函数,并且也应用于CRT函数,这是为什么呢?有以下原因。

  • The Rtl functions are marked PAGEable so you can’t even execute the function itself
  • The Buffer in a UNICODE_STRING is typically from PagedPool if it is not stack based
  • The string conversion (e.g. NLS) tables are PAGEable
  • Rtl函数被标记为分页函数,所以你有的时候甚至不能执行它(在IRQL大于等于Dispatch级别时)
  • UNICODE_STRING成员Buffer一般来自分页内存
  • 字符串转换表存在于分页内存中

You can overcome the 2nd bullet by making sure your buffer allocations come from NonPagedPool, but that doesn’t help you very much because the surrounding infrastructure.  But wait a minute…there are samples out there which use strlen or sprintf at DISPATCH_LEVEL or higher.  The most common use of string functions in a driver is to wrap DbgPrintf with more logic (like levels or component bits), something similar to

你可以规避第二种陷阱,比如确保你的缓冲区分配自非分页内存,但是由于周边的基础设施这也帮不了你太多。等等....这有一些在IRQL大于等于DISPATCH_LEVEL时使用strlen及sprinf的例子啊!最普通的应用是使用更多的逻辑(例如级别、组件)包装DbgPrint。


#define PRINT(level, x) if ((level) <= Globals.DebugLevel) { MyPrint x ; }


VOID MyPrint(PSTR Format, …) 
{
    CHAR ach[128];
    va_list va;
    NTSTATUS status;


    va_start(va, Format);
    status = RtlStringCbVPrintfA(ach, sizeof(ach), Format, va);
    if (NT_SUCCESS(status)) { DbgPrint(ach); }
    va_end(va);
}


which is invoked like this PRINT(2, (“Number of instances %d\n”, DevExt->NumInstances”)); and this actually works.  Why?  Because the format string does not contain any %s format specifiers.  If you use %s, you will hit the aforementioned tables and potentially hit paged out pool (and bugcheck). 

你可以调用这个宏PRINT(2, (“Number of instances %d\n”, DevExt->NumInstances”));并且工作正常,为什么?因为这个格式化字符串不包含%s。如果你使用%s,你就会碰到之前所说的STRING CONVERTION TABLE,可能会被交换出内存并且引起BSOD。

What to do?  Well, don’t put strings in your debug print statements if it is callable at IRQL > PASSIVE.  Also, you have to consider why you are even dealing with a string at a higher IRQL, hopefully you are not comparing strings or other similar string operations.  Also, consider using WPP where you can use strings (because the string contents are copied directly and processed in user mode later).

怎么处理这些状况呢,当IRQL大于Passive级别时,别在调试打印中输出字符串。另外你还得考虑为什么在高IRQL级别处理字符串,希望你不要比较字符串或者其它什么字符串操作。当然,你可以考虑使用WPP。



PS:根据文档及其此博文的评论,有如下更正:

DbgPrint的格式化参数有以下注解 

The Format string supports all the printf-style formatting codes. However, the Unicode format codes (%C, %S, %lc, %ls, %wc, %ws, and %wZ) can only be used with IRQL = PASSIVE_LEVEL. 

所以以上作者所写的有个小问题,就是%s不会引起BSOD,而是%S。至于为什么是宽字符只能在Passive级别使用,原因可能是DbgPrint最终会输出Ansi字符串,宽字符向Ansi字符转换会使用到之前提到的String Convertion Table(处于分页内存)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值