• 【原创】驱动开发中Memory read error导致的蓝屏问题


        最近在看着《windows驱动开发技术详解》这本书,模仿着敲了第七章中的模拟文件读写部分。在Debug过程中,蓝屏了好多次并出现了各种奇葩的问题。在调了快两天之后,问题终于解决了!现在在这里一一再现遇到的问题和解决方法。

     
     【在别人博客的评论中看到这么一句,"能让大家节约时间,就是写博客的目的之一",让我很有很深的感触,希望自己能以这个目的持续将博客进行到底,帮助更多的初学者。
     
    一 蓝屏问题
     
     1. deviceName,symbolicName显示Memory read error问题
     
        在Debug过程中,发现在调用派遣函数的时候,设备扩展结构体变量中的deviceName,symbolicName以及buffer,显示Memory read error。找了好久,终于发现问题所在。
     
    1 //设备拓展结构体
    2 typedef struct {
    3     PDEVICE_OBJECT pDeviceObject; //指向自己
    4     UNICODE_STRING deviceName;    //设备名
    5     UNICODE_STRING symbolicName;    //符号链接
    6     PDEVICE_OBJECT  attachDevice;   //下层设备对象
    7     PWCHAR buffer;            //缓冲区指针
    8     LONG            file_length;        //文件长度
    9 }DeviceExtension, *PDeviceExtension;
       
     初始化deviceName,symbolicName子域的函数原型是
    NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject, UNICODE_STRING &linkName, UNICODE_STRING &devName);
     
      CreateDevice的形参linkName和devName都是引用形参,并且该函数在DriverEntry中被调用用于创建新设备。
    1 pDevExt->deviceName = devName;
    2 pDevExt->symbolicName = linkName;
      
     在之前书中看到过,直接进行初始化,不需要额外的空间也不需要销毁内存,它只是简单地拷贝Buffer指针到另一结构体而已。好了,问题便出现在这里了,当外部的linkName和devName变量被销毁,那么设备扩展中的deviceName和symbolicName引用的Buffer空间也就非法的。
       
     恰好DriverEntry函数被我定义为#pragma INITCODE了,一次调用完空间便被系统自动回收了,定义在函数内部的设备名和符号名变量也自然就没了,自然在派遣函数中使用便会出现蓝屏。
       
     解决的办法就是将DriverEntry函数定义为#pragma PAGECODE就好了。
     
        和我遇到同样问题的还有这位网友:http://www.programlife.net/page_fault_in_nonpaged_area.html,在这篇文章的评论中有这么一句,"能让大家节约时间,就是写博客的目的之一",让我很有很深的感触,希望自己能以这个目的持续将博客进行到底,帮助更多的初学者。
     
    二 字符串显示错误问题
     
    1. 指针字节问题
        
        这个问题出现在应用程序和驱动上面,也是调了好久才解决的。原来问题是如此简单!
       
     我们知道WriteFile和ReadFile函数都是以字节为单位,写入和读取内容的,SetFilePointer函数也是以字节来偏移文件指针的。在驱动程序上,我的IRP_MJ_WRITE派遣函数中的写入缓冲区语句是这样写的
    //将数据写入缓冲区
    RtlCopyMemory(buffer + writeOffset, pIrp->AssociatedIrp.SystemBuffer, writeLength);
     
        如果buffer类型是CHAR,那么是没问题的,因为它只占一个字节。但在我的程序里buffer的类型是WCHAR,占两个字节,所以当指向它的一个指针加上某个常数N,那么buffer实际上偏移了2N个字节。而传入的writeOffset偏移量是以一个字节为单位,所以它其实多偏移了writeOffset个字节,导致数据写入的位置错误,最后导致乱码出现。
       
     正确的应该为
    //将数据写入缓冲区
    RtlCopyMemory((char*)buffer + writeOffset, pIrp->AssociatedIrp.SystemBuffer, writeLength);
    2. 转义字符0问题
        
        最后在应用程序里,读取到的数据需要在末尾加上转义字符0,才能最终打印出来。
    if(ReadFile(hFile, buffer, fileLengthBytes,&fileLengthToRead, NULL))
    {
        buffer[fileLengthBytes/2]= L'';
        wcout <<"读取缓冲区的长度为"<< fileLengthToRead <<"缓冲区内容为"<< buffer << endl;
    }
    else
    {
        cout <<"读取缓冲区失败"<< endl;
    }

    本文链接:http://www.cnblogs.com/cposture/p/4766378.html
  • 相关阅读:
    压缩与解压缩
    权限和特殊权限
    用户和组
    bash基础特性
    vim编辑器
    目录及文件操作命令
    ye
    软件包的安装与管理
    磁盘管理
    归档与展开归档
  • 原文地址:https://www.cnblogs.com/cposture/p/4766378.html
Copyright © 2020-2023  润新知