IoCopyCurrentIrpStackLocationToNext与IoSetCompletionRoutine的深入理解
1、
IoCopyCurrentIrpStackLocationToNext是拷贝本层的IO_STACK_LOCATION 到下一层。在楚狂人的驱动教程中说:
如果对irp完成之后的事情有兴趣,并打算在完成函数中处理,应该首先拷贝当前 IO_STACK_LOCATION(IoCopyCurrentIrpStackLocationToNext),然后指定完成函数,并返回 IoCallDriver()所返回的status.完成函数中,不需要调用IoCompleteRequest!直接返回Irp的当前状态即可.但是IoCopyCurrentIrpStackLocationToNext是这样的:
将本层的IO_STACK_LOCATION拷贝到下一层的方法一:
#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \
PIO_STACK_LOCATION __irpSp; \
PIO_STACK_LOCATION __nextIrpSp; \
__irpSp = IoGetCurrentIrpStackLocation( (Irp) ); \
__nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); \
RtlCopyMemory(__nextIrpSp, __irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \
__nextIrpSp->Control = ; }
也就是说他并没有拷贝当前的完成例程给下层,而是通过IoSetCompletionRoutine来设置的 这样一来的话,拷不拷贝本层的IO_STACK_LOCATION 到下层不都是没有关系的了?因为下层的IO_STACK_LOCATION 有他自己的结构内容,何必要用本层的拷贝过去呢?
2、IoSetCompletionRoutine
#define IoSetCompletionRoutine(irp,routine,completioncontext,success,error,cancel)\
#{ PIO_STACK_LOCATION irpsp;\
#ASSERT((success)|(error)|(cancel)?(routine)!=NULL:TRUE);\
#irpsp=IoGetNextIrpStackLocation((irp));\
#irpsp->completionroutine=(routine);\
#irpsp->context=(completioncontext);\
#irpsp->control=;\
#if((success)){irpsp->control=SL_INVOKE_ON_SUCCESS;}\
#if((error)){irpsp->control |= SL_INVOKE_ON_ERROR;}\
#if((cancel)){irpsp->control |= SL_INVOKE_ON_CANCEL;} }\
这样一来IoSetCompletionRoutine不是设置的下层的完成例程么?为什么是设置下层的完成例程?为什么不是本层的?
3、
将本层的IO_STACK_LOCATION拷贝到下一层的方法二:
PIO_STACK_LOCATION IrpSp;
PIO_STACK_LOCATION NextIrpSp; IrpSp = IoGetCurrentIrpStackLocation(Irp);
NextIrpSp = IoGetNextIrpStackLocation(Irp); *NextIrpSp = *IrpSp; return IoCallDriver(NextDeviceObject, Irp);
这种方法OSR中说IO_STACK_LOCATION中有两个成员CompletionRoutine、Context,即完成例程和完成例程的上下文参数。也就是说方法二会让Lb层拥有这两个原本不一定会属于它的成员。如果这两个成员都是NULL,那还好。一旦这两个成员有有效的内容,那么就会导致"an eventual blue screen"。但是在filemon源码的FilemonHookRoutine例程靠后中有
*nextIrpStack = *currentIrpStack;
但是随后
#if defined(_IA64_)
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR) seqNum, TRUE, TRUE, TRUE );
#else
IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE, TRUE, TRUE );
#endif
而并没有出现什么蓝屏。而且我不明白为什么会出现蓝屏原本不属于他的成员CompletionRoutine、Context在IoSetCompletionRoutine不就是设置NextIrpSp 自己的成员么?(IoSetCompletionRoutine的定义 )
答疑:
1,完成例程本来就是设置在当前堆栈的下一层堆栈里,这相当于是一个规范,也可以用实际的IRP的返回来理解。在完成例程里,根据返回不同的状态值,IRP的控制流可能会发生相应的变化,比如:...STATUS_MORE_PROCESSING,这样,下层堆栈执行完成例程后,会将IRP的控制权交付给本层堆栈。从这个意义上讲,完成例程,只能放在下层堆栈,实际上,设计也是这样的。
2,拷贝当前堆栈的内容到下层堆栈,只是为了保证执行环境一样。
在一个设备栈中,高层设备只能访问自己的设备栈或者下层设备栈,这就要求这个驱动必须要为下层设置IO堆栈,但不是必须的。每个堆栈中,context字段的值是唯一的,会标识一些pending等状态位,表示不同的完成状态,所以这个字段不可以随意复制。
两种方法都挺常用。但是今天再看DDK中一篇OSR的分析文章里提到一个采用方法二可能会导致的一个很隐蔽的BUG:
方法二把本层(La)的整个IO_STACK_LOCATION都拷贝到了下一层(Lb),而IO_STACK_LOCATION中有两个成员CompletionRoutine、Context,即完成例程和完成例程的上下文参数。也就是说方法二会让Lb层拥有这两个原本不一定会属于它的成员。如果这两个成员都是NULL,那还好。一旦这两个成员有有效的内容,那么就会导致"an eventual blue screen"。
原来这是个宏,重点看RtlCopyMemory调用的最后一个参数:这个宏只拷贝了CompletionRoutine成员之前的部分。方法一、方法二的区别就在这里。而实际上后者相对于前者,并没有什么优点,所以还是尽量使用方法一比较好。
IoCopyCurrentIrpStackLocationToNext与IoSetCompletionRoutine的深入理解的更多相关文章
- 《Windows驱动开发技术详解》之分层驱动程序
分层驱动程序概念 分层的目的是将功能复杂的驱动程序分解成多个简单的驱动程序.一般来说,他们是指两个或两个 以上的驱动程序,它们分别创建设备对象,并且形成一个由高到低的设备对象栈.IRP请求一般会被传送 ...
- [转&精]IO_STACK_LOCATION与IRP的一点笔记
IO_STACK_LOCATION和IRP算是驱动中两个很基础的东西,为了理解这两个东西,找了一点资料. 1. IRP可以看成是Win32窗口程序中的消息(Message),DEVICE_OBJECT ...
- [转]C/C++ 实现文件透明加解密
今日遇见一个开超市的朋友,真没想到在高校开超市一个月可以达到月净利润50K,相比起我们程序员的工资,真是不可同日而语,这个世道啊,真是做程序员不如经商开超市, 我们高科技的从业者,真是造原子弹不如卖茶 ...
- 键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试
键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试 完整源代码 /// /// @file ctrl2cap.c /// @author wowocock /// @date 2009-1 ...
- 一个文件系统过滤驱动的demo
因为没写过FSD过滤驱动,所以拿来练练手,没有什么技术含量.参考自Win内核安全与驱动开发. 先梳理一下大概的流程,就是怎么去绑定设备栈.怎么去过滤各种请求的. 首先肯定是要绑定设备栈的,来看下怎么绑 ...
- 《windows内核安全与驱动开发》ctrl2cap中的ObReferenceObjectByName疑问
国内有关于windows内核驱动这块的书籍实在是甚少,不过好在<windows内核安全与驱动开发>这本书还算不错(内容方面),但是不得不说这本书在许多地方存在着一些细节上的问题.比如我今天 ...
- [内核编程] 键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试
键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试 完整源代码 /// /// @file ctrl2cap.c /// @author wowocock /// @date 2009-1 ...
- 理解CSS视觉格式化
前面的话 CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...
- 彻底理解AC多模式匹配算法
(本文尤其适合遍览网上的讲解而仍百思不得姐的同学) 一.原理 AC自动机首先将模式组记录为Trie字典树的形式,以节点表示不同状态,边上标以字母表中的字符,表示状态的转移.根节点状态记为0状态,表示起 ...
随机推荐
- STM8串口初始化寄存器配置
//库函数配置 UART1_DeInit(); UART1_Init((u32)1000000, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, \ UART1_PARI ...
- Android 上传文件,图片。以及服务器端接收相关。
前面一篇文章写了实现照相功能的一个例子,其实那个实现效果是个略缩图.要查看全图就要先指定照片的存放路径.以后我会修改那个文章.今天先说下图片,文件等上传的实现.接着拿照片说事,光照完了不行还得往服务器 ...
- 学习Git---20分钟git快速上手
学习Git-----20分钟git快速上手 在Git如日中天的今天,不懂git都不好意思跟人说自己是程序猿.你是不是早就跃跃欲试了,只是苦于没有借口(契机). 好吧,机会就在今天. 给我20分钟,是 ...
- 谈一谈python的垃圾回收机制
[python的垃圾回收机制是怎么实现的] 在C语言时代程序员要负责内存的申请和释放,虽然这样的程序可以对资源进行精细的控制.但是它也有它的问题.这就要求程序员 要写许多与业务逻辑无关的内容在代码里面 ...
- unfolding maps支持中文
由于项目需要,选择了processing+unfolding的方式进行数据可是话的开发,unfolding maps是一个非常强大的地图工具,processing可以灵活自如的表达各种图形/效果.使用 ...
- Atitti cto的日常流程与职责attilax总结
Atitti cto的日常流程与职责attilax总结 1. (最重要)技术战略制定 规划,预测趋势1 1.1. 关键词 Throught技术雷达 趋势 没落 已死 辉煌 未来1 1.2. (比较 ...
- django搭建一个小型的服务器运维网站-拿来即用的bootstrap模板
目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...
- # tail -f /var/log/zabbix/zabbix_agentd.log sudo: sorry, you must have a tty to run sudo
/etc/sudoers 1)Defaults requiretty,修改为 #Defaults requiretty,表示不需要控制终端. 2)Defaults requiretty,修改为 Def ...
- 用express-generator创建express项目骨架
npm install express-generator -g express -e --view=ejs myproject && cd myproject npm install ...
- lua -- 字体闪烁
-- 这里是实现控件的闪烁,不能将一个局部的动作变量,赋给两个控件来动作,只能一个控件对应一个动作 function UIBagController:ShowEffect( ) local tGood ...