查看文章
 
windows 驱动编程规范
2009-08-21 22:58

    最近又在看恶心的代码,于是在地铁上想了想windows驱动编程的规范问题。整理了一下,如下,欢迎指正和补充。

1 驱动编程中,代码的规范性比技巧更重要。除非有苛刻的要求,否则少用晦涩的技巧。

2 永远要努力将复杂的问题简单化,不要让代码的逻辑不清晰使问题变得更复杂。代码只有自己能看懂那是垃圾,代码可以让更多的人更轻易看懂才叫真正的高
水平。
3 所有涉及到的技术要点要在正式编码之前单独测试,包括效率,兼容性,稳定性等。所以技术方案使用前要充分讨论,充分论证。

4 项目中涉及到的核心数据结构要提前规划好。涉及到通信的结构要具有可扩展性。

5 算法要符合实际应用,请先拿到可信的测试数据再决定采用何种算法。比如数据量小的时候可以使用list,数据量大了可能有必要使用hash将list进行散列。
数据量更大可能需要使用树,如果数据变化大需要使用伸展树。一次性初始化,后面都是查询操作应该使用平衡树。

6 永远使用最新的ddk版本,使用和OS对应的编译环境编译代码

7 驱动程序需要通过driver verifier测试

8 代码需要在oacr 下无警告

9 所有可以用API搞定的事情请使用API

10 所有对api的使用,请确保通读msdn对该api的描述。

11 所有接受参数的函数,请在函数入口检查参数合法性。所有使用到不可控参数的地方应该用SEH保护起来。

12 如果局部变量作为指针传递出去,请确保调用关系在同一堆栈中。因为局部变量具有挥发性。

13 仅在单个函数内使用的非挥发性变量,请使用static修饰符,避免使用过多的全局变量

14 对于传入传出型参数,请保证仅在函数返回成功的时候修改参数。

15 内核中一个线程的堆栈空间有限,要避免定义过长的局部变量。不使用递归函数。

16 函数尽可能的单出口,不要随地都是return。

17 避免使用goto

18 对于确定类型的指针请不要使用pvoid,因为传入了错误的指针编译器不会报警。

19 所有对指针的指针的使用,请尽量使用引用,除非你非常谨慎。因为传入一级指针编译器还是不会报警。

20 定义结构的时候需要考虑字节对齐的粒度问题。尤其当代码需要在32位和64为下同时使用的时候。

21 对指针做运算时,请注意运算的单位是指针所指数据结构的大小。

22 如果代码想同时适用32,64位平台。需要注意对指针的定义,可以使用PVOID,PULONG_PTR等自动适应的指针类型。

23 所以对buffer的操作,请时刻注意其边界。

24 所有对字符串的操作,请至少使用安全字符串函数。

25 wcscpy之类的c运行时函数操作的字符串必须以0结尾。但是内核中普遍使用的UNICODE_STRING 不能保证这一点。所以不要使用wcsxxx去操作unicode_string。
比如每次我看到类似这样的代码我就想骂街
PUNICODE_STRING pName = ...
PWSTR p = wcschr(pName->Buffer, ...);

26 在驱动中访问用户态内存,需要先使用ProbeForRead和ProbeForWrite 验证其合法性。

27 在没有特殊要求的情况下,请使用分页内存。如果使用非分页内存,请尽快释放。

28 避免将代码执行时的IRQL提升到APC_LEVEL 之上,比如在DISPATCH_LEVEL上不能访问分页内存,很多API 不能使用。

29 对于频繁分配,释放的,且小的内存片,请使用LookasideList。

30 对同一资源的释放最好只在一个地方进行,避免重复释放。

31 如果需要在DISPATCH_LEVEL上访问分页内存,必须使用MDL将内存锁定

32 代码停留在DPC level 上的时间要很短。换句话说,dpc上执行的代码要很精练,否则会对系统性能有明显影响。

33 对共享资源的访问要加同步,互斥等机制。注意有些内核分发器对象可以递归获取,有的不能。递归获取的需要递归释放。

34 一条指令就可以对共享数据进行的修改,在单核机器上是安全的。但是请记住未来是多核世界,请使用Interlocked...机制,确保多核平台下操作的原子性。

35 API使用中,如果涉及到权限申请的问题,请保证使用可用的最小权限。

36 仅在内核中使用的句柄,请指定OBJ_KERNEL_HANDLE属性。

37 在内核中使用native api,请使用Zw...,不要直接调用Nt...

38 功能比较明确,且代码不多的时候,请使用宏或者inline函数

39 代码中要避免直接使用数字,请定义成宏
40 多处用到的固定数值,请使用宏。
41 在宏定义中请毫不吝啬的使用括号

42 每次发布2进制文件,请保存对应的pdb和source。可以用批处理来实现自动化

43 过滤型驱动的完成函数执行时,所在的进程上下文,所在的irql 都是未定义的。

44 避免使用硬编码,如果用到了,请检查平台的版本。对于不支持的平台版本需要bypass

45 如果驱动中设置了任何callback函数,请在驱动卸载前取消对callback的注册。

46 hook型驱动,驱动卸载前必须恢复hook。

47 推荐使用预编译头文件,将各模块共用的东西放这里。

48 强制类型转化时,请注意可能存在的数据被截短情况

49 测试性代码,请用 // for debug, // for test 之类的注释,并尽量整体的放到花括号里面,方便删除

50 过滤驱动,hook型驱动,总之做中间处理的,需要尽可能不修改系统原有的流程。比如异步的过程被改成同步的,并行的被改成串行可能会降低系统性能。

51 hook型驱动,调用任何函数之前,请确保被调用函数内部不会再call到hook函数。否则引发重入。

52 驱动中可以对一些功能模块做开关,方便用排除法解决bug。


类别:默认分类||添加到搜藏 |分享到i贴吧|浏览(3969)|评论 (0)
 
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu