반응형

 

메모리를 할당한 후 반드시 리턴값을 확인 할 것

 

커널 메모리가 소진되어 메모리를 더 이상 할당 할 수 없는 경우가 발생할 가능성이 얼마나 될까?

드라이버 관련 유지보수 및 개발담당한지 7개월 남짓이지만,

간간히 레포트가 들어오는 사항이다.

첫번째로 레포트된 문제는 인계받은 드라이버 쪽에서의 메모리 누수로 인한 메모리 할당 실패...
(
찾느라 애좀 먹었다.. 위대하신 PoolTag님의 도움으로 겨우 해결.)
이 경우야 우리 드라이버의 문제이므로, 변명의 여지 없음이고....

그 외에도 ExAllocatePool() 호출이 실패하여 NULL이 리턴되고,
NULL 포인터에 메모리를 쓰려다가 발생한 BSOD도 심심찬게 레포트 된다.


메모리 할당 후 리턴값을 확인하는 것은 왜 필요한가?

내가 작성한 드라이버가 아닌 다른 드라이버가 커널 메모리를 누수시키며 동작하고 있다고 가정하자.

이 문제의 드라이버 때문에 어느 순간인가 메모리 할당이 실패할 것이고,

그렇게 되면 우리 드라이버는 메모리 할당이 실패한 줄도 모르고 잘못된 메모리를 참조하여,
우리 드라이버가 요주의 용의자로 지목되는 BSOD가 발생할 가능성이 다분하다.

그러면 어찌될지는 뻔한 일이다. 분명 우리 드라이버의 문제가 아님에도 우리 쪽으로 버그 레포트가 올테고 우리 드라이버의 문제가 아님을 증명하기 위해 시간과 노력을 투자할 밖에....

이런 의미에서 메모리 할당후에 정상적으로 할당되었는지 확인하는 것은 아주 기본적이지만 중요한 습관이다.

새로 작성하는 코드 전체에 할당 성공 여부를 확인하는 코드를 삽입하고,
DriverVerifier
Low Resource Simulation 옵션을 를 체크하여 테스트 해보니
BSOD
없이 잘 구동된다.....

다만 이경우, 메모리 할당 실패로 우리의 드라이버가 정상적인 동작을 할 수 없을 가능성이 다분하므로, 이러한 상황을 확인 할 수 있는 별도의 조치가 필요하리라..

 

반응형
반응형

DRIVER_POWER_STATE_FAILURE (9f)


A driver is causing an inconsistent power state.
Arguments:
Arg1: 00000500,
The device object completed the irp for the system power
state request, but failed to call PoStartNextPowerIrp
.
Arg2: 00000002
Arg3: 8188ab80, Optional Target device's DEVICE_OBJECT
Arg4: 81982d98, DeviceObject

Debugging Details:

DRVPOWERSTATE_SUBCODE: 500

DEVICE_OBJECT: 8188ab80

DRIVER_OBJECT: 817c7718

IMAGE_NAME: MyDriver.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 49e3e422

MODULE_NAME: MyDriver

FAULTING_MODULE: f7645000 MyDriver

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0x9F

PROCESS_NAME: System

LAST_CONTROL_TRANSFER: from 804f99f7 to 80528fe8

STACK_TEXT:
f9c1a88c 804f99f7 00000003 f9c1abe8 00000000 nt!RtlpBreakWithStatusInstruction
f9c1a8d8 804fa5e4 00000003 00000000 81982d98 nt!KiBugCheckDebugBreak+0x19
f9c1acb8 804fab0f 0000009f 00000500 00000002 nt!KeBugCheck2+0x574
f9c1acd8 80649fec 0000009f 00000500 00000002 nt!KeBugCheckEx+0x1b
f9c1ad18 8064a413 000724f8 00000000 00000005 nt!PopWaitForSystemPowerIrp+0x3c0
f9c1ad34 8064a704 fb0724f8 fb07268c 8055ac90 nt!PopSleepDeviceList+0xcb
f9c1ad5c 80646e7a 00000000 8055c440 8197d3c8 nt!PopSetDevicesSystemState+0x1a4
f9c1ad74 80536006 00000000 00000000 8197d3c8 nt!PopGracefulShutdown+0x12c
f9c1adac 805c6d5a 00000000 00000000 00000000 nt!ExpWorkerThread+0x100
f9c1addc 805431e2 80535f06 00000000 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16


STACK_COMMAND: kb

FOLLOWUP_NAME: MachineOwner

FAILURE_BUCKET_ID: 0x9F_VRF_IMAGE_MyDriver.sys

BUCKET_ID: 0x9F_VRF_IMAGE_MyDriver.sys

Followup: MachineOwner

파일 RW를 감시하는 파일시스템 필터 드라이버 작성 중 위의 버그체크 코드를 만났다.
CD Burning
을 감시하기 위해, CdRomX Attach한 후 시스템을 재 부팅하거나

종료할 때 발생한 문제이다.

WinDbg
가 분석해준 내용을 살펴보면 power관련된 처리를 제대로 하지 못했다는 내용인데
,
좀 자세히 살펴보자

WinDbg
도움말에서 해당 버그첵 코드를 확인해 보면 파라미터 각각에 대한 설명이 상세히 기술되어 있다.

The following parameters appear on the blue screen. Parameter 1 indicates the type of violation.

Parameter 1

Parameter 2

Parameter 3

Parameter 4

Cause

0x1 (Windows 2000 and later)

The device object

Reserved

Reserved

The device object that is being freed still has an outstanding power request that it has not completed.

0x2 (Windows 2000 and later)

The target device's device object, if it is available

The device object

The driver object, if it is available

The device object completed the I/O request packet (IRP) for the system power state request, but it failed to call PoStartNextPowerIrp.

0x3 (Windows 2000 only)

A pointer to the target device object

Apointer to the device object

The IRP

The device driver did not properly set the IRP as "pending" or complete the IRP.

0x3 (Windows XP and later)

The physical device object (PDO) of the stack

The functional device object (FDO) of the stack

The blocked IRP

A device object has been blocking an IRP for too long a time.

0x100 (Windows 2000 only)

A pointer to the nonpaged device object

A pointer to the target device object

A pointer to the device object to notify

The device objects in the devnode inconsistently used DO_POWER_PAGABLE.

0x101 (Windows 2000 only)

The child device object (FDO)

The child device object (PDO)

The parent device object

A parent device object has detected that a child device has not set the DO_POWER_PAGABLE bit.

0x500 (Windows XP and Windows Server 2003 only)

Reserved

The target device's device object, if available

Device object

The device object completed the IRP for the system power state request, but it failed to call PoStartNextPowerIrp.


A driver is causing an inconsistent power state.
(드라이버가 엉터리 파워상태를 야기했다)
Arguments:
Arg1: 00000500,
The device object completed the irp for the system power
state request, but failed to call PoStartNextPowerIrp
.
(디바이스 오브젝트가 시스템 파워 상태 요청에 대해 irp를 완료하기는 했으나
PoStartNextPowerIrp()
를 호출하는 데 실패했다. 머 이런 내용이다.)
Arg2: 00000002
Arg3: 8188ab80, Optional Target device's DEVICE_OBJECT
(이놈은 우리 드라이버가 irp를 잔달한 우리 드라이버의 하위 드라이버의 포인터 이다.)

Arg4: 81982d98, DeviceObject
(문제를 야기한 이놈은 역시나 우리의 드라이버다.)

파일 시스템 드라이버야 WDM이 아닌 레거시 드라이버이다 보니 IRP_MJ_POWER에 대한 별도 처리부분은 없는 상태이고, CdRomX Attach DeviceObject로 파워관련 IRP가 내려오지 싶다.

역시나 확인을 해보니, 시스템 종료시 CdRomX Attach한 디바이스 ObjectIRP_MJ_POWER IRP가 내려온다
.

사실 작업 대상이 디바이스가 아닌 파일시스템 쪽이다 보니, POWER,PNP관련 된 부분은 크게 신경 쓰지 않았거덩....(자랑이냐
?)

여하간에 WDM 관련 책을 보니 IRP_MJ_POWER 요청에 대해서는 어찌 어찌 하라는 코드가 있더란 말이지
...

그래서 IRP_MJ_POWER IRP를 걸러내서 이렇게 변경했다..

IoSkipCurrentIrpStackLocation( Irp );
return IoCallDriver( pDevExt->LowerDevObj, Irp );

PoStartNextPowerIrp( Irp );
IoSkipCurrentIrpStackLocation( Irp );
return PoCallDriver( pDevExt->LowerDevObj, Irp );

일단 문제는 사라졌는데... 좀 더 확인이 필요할것 같다.
현재는 특정 Dispatch함수를 모든 IRP의 디스패치 루틴으로 등록하는 방식인데, IRP_MJ_POWER에 대한 디스패치 루틴을 등록하지 않으면 문제가 발생하지 않을까
?

아 그리고, CdRomX Attach할때 Attach대상 디바이스 객체의 Flags DO_POWER_PAGABLE이 설정되어 있으면, 우리의 디바이스 객체에도 DO_POWER_PAGABLE를 설정해 주어야 한단다
.

추측이 다소 포함된 내용이므로 전적으로 신뢰하지 말것
...
책임질 수 없음.

 

반응형
반응형
WinDbg Vista에서 디버그 프린트 출력하기

출처: http://greemate.tistory.com/81

greemate님의 홈페이지 에서 가져왔습니다.

VISTA 에서 디버그 메시지가 기본적으로 꺼져 있다는 것 알고 계시지요?
Windows Server 2008 도 마찬가지구요.

까먹구 있었는데 디버깅하다가 보니 DbgPrint/KdPrint 로 출력한 디버그 메시지가 안나오더라구요.
어떻게 켜는지 확인해 보니 WinDbg 명령창에서 아래와 같이 Kd_DEFAULT_MASK 를 수정하면 되더군요.
다음 번에 또 찾기 귀찮아서 여기에 적어 둡니다.

* DPFLTR_INFO_LEVEL 로 켜고 싶을 때
kd > ed Kd_DEFAULT_MASK 8

* DPFLTR_ERROR_LEVEL 로 켜고 싶을 때
kd > ed Kd_DEFAULT_MASK 0xF

* 디버그 메시지를 끄고 싶을 때
kd > ed Kd_DEFAULT_MASK 0

8 로 해도 제가 DbgPrint 한 메시지들은 모두 나오더군요.
참고하시기 바랍니다.

자세한 내용은 아래 링크에 있습니다.
http://www.osronline.com/article.cfm?article=295


http://www.driveronline.org/bbs/view.asp?tb=tipbbs&GotoPage=1&s_bulu=&s_key=&no=101
반응형
반응형

strcpy_s등의 _s 류의 문자열처리 함수에 대해

 

VC++ 6.0으로 작성된 프로젝트를 VS 2005 이상으로 변환해서 컴파일 하거나,
VS2005
로 프로젝트 작성시 strcpy, sprintf, strcat 등의 C 런타임 함수를 사용하면 다음과 같은 warning 메시지를 접하게 된다
.

warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

strcpy_s, sprintf_s, strcat_s
와 같은 안전한 스트링 함수를 사용하라는 내용인데
...
이 함수들의 원형을 살펴보면 두번째 인자가 캐릭터의 숫자임을 알 수 있다
.
< 밑에 GrooveFella이 지적해주신대로 sizeof(buffer)가 아니라 _countof(buffer)로 계산해야 한다. >

errno_t strcpy_s( char *strDestination, size_t numberOfElements, const char *strSource );

strDestination 버퍼를 넘어서는 메모리 복사를 방지하는 스트링 함수라 이해하면 되겠다.
그래서 _s(afe)로 추측되는 함수들을 만들어 놨을 테고
...

그럼 이 보기 싫은 warnig을 어떻게 처리할 것인가
?
1.
제일 무식한 방법으로는 아래의 pragma를 설정하여, 해당 warnig을 표시하지 않도록 설정한다
.
  #pragma warning(disable: 4996)
2.
그게 아니면 당연히 _s류의 함수로 바꿔야 겠지?
여기서 한가지 집고 넘어가자면

char szBuf[MAX_PATH];
strcpy_s( szBuf, "aaa" );

형태의 코딩이 가능하다는 거다.

char *pszBuf = new char[MAX_PATH];
strcpy_s( pszBuf, "aaa");

이러한 코딩은 error C2660: 'strcpy_s' : 함수는2개의매개변수를사용하지않습니다.”라는 컴파일 에러가 발생한다.

두 코드의 차이점이 보이는가?
그렇다. _s류 함수의 첫번째 인자로 배열이 들어가면, 매크로에 의해 사이즈가 자동으로 계산된다.


3.
... 그럼 조금 더 생각해 보자.
strcpy_s
strncpy와 무엇이 다를까? 아니면 똑같이 동작하는가
?
아래의 코드를 돌려보면 답은 명확해 진다.

char *pszBuf = new char[6];
strncpy( pszBuf,
"aaaaaaaa", 7 ); // --> (1)
strcpy_s( pszBuf, 7,
"aaaaaaa"); // --> (2)

(1) 의 코드는 할당된 메모리(6byte)를 넘어서서 7byte까지 'a'로 채운 후 다음 코드가 진행된다.
(
머 이후의 상황이야 엄한 곳에서 메모리를 할당하거나 해제 할 때 문제가 발생 할 테지, 운이 억수로

나쁘다면 문제가 없는 것처럼 보일 수 도 있을 테고...)
(2)
의 코드는 메모리 에러를 발생시키며, 프로그램이 종료된다
.

귀찮다고 방치하지 말고, 이 기회에 바꿔보는 건 어떨까?

 

 

반응형
반응형

대학교때, 시험문제에 "오버로드와 오버라이드의 차이점을 기술하라"는 문제가 나왔던것이 아직도 기억난다.
한줄의 답도 적지 못했던 기억도
...

워낙 공부를 등한시한 터라, 오버로드라고는 스타크래프트의 저그 밥통(?) 외에는 떠오르는게  없었다
.

경력 6년 차인 지금이라면 답을 적을 수 있을까
?
.. 확신이 안선다
.

두가지가 의미하는 정의는 알고 있지만, 단어와 정의가 항상 매치가 안된다
.

해서. 이 글을 쓰며 머리속에 각인시키려 한다.

·        오버로드(Overload)
함수(메소드) 이름은 같고 인자 갯수나 타입이 다른 함수를 정의하는 것을 의미한다.
(
리턴값만을 달리하는 오버로드는 작성 할 수 없다)

int OverloadFuncAdd( int x, int y );
double OverlaodFuncAdd( double x, double y);

OverloadFuncAdd() 함수가 오버로드된 것이다

·        오버라이드(Override)
상위 클래스의 매소드를 재정의 하는 것이다.
메소드 이름은 물론 인자 갯수나 타입도 동일해야 하며, 주로 상위 클래스의 동작을 상속받은 하위클래스에서 메소드의 동작을 변경하기 위해 사용된다.

class BaseClass
{
protected:
    virtual int OverrideFuncAdd( int x, int
y);
};

class SubClass : public
BaseClass
{
    int OverrideFuncAdd( int x, int
y);
}

와 같은 형태로 사용된다



명확하게 기억하자.

 

반응형
반응형

IRP_MJ_DEVICE_CONTROL Irp의 완료처리

 

irp->IoStatus.Information = outbuf_len;

irp->IoStatus.Status = status;

IoCompleteRequest( irp, IO_NO_INCREMENT );

 

IRP_MJ_DEVICE_CONTROL IRP의 처리를 완료할 때 사용하는 일반적인(?) 코드이다.

 

irp->IoStatus.Informationirp->IoStatus. Status 는 정확히 어떠한 용도로 사용되는가?

드라이버 입문서적을 자세히 읽어 본 사람이라면 잘 알고 있겠지만, 드라이버 개발 초기 많이 실수를 하기도 했던 부분이라 정리해 본다.

 

n  irp->IoStatus.Status

ü  IRP의 처리 결과를 설정한다. 여기에 설정한 Status값에 따라 User-mode에서 DeviceIoControl()함수를 호출한 후, 이어서 호출하는 GetLastError()의 에러값이 설정된다.

n  irp->IoStatus.Information

ü  Buffered-Methord방식으로 버퍼를 관리하는 DeviceIoCotrol의 경우, 시스템 버퍼에서 user-buffer로 복사되는 사이즈를 기술한다. 예를 들어 irp->AssociatedIrp.SystemBuffer 10Byte를 복사했더라도 irp->IoStatus.Information 0을 대입한 후 리턴해 주면, user-buffer에는 어떠한 데이터도 복사되지 않는다.( user-mode에서는 드라이버에서 복사한 내용을 확인 할 수 없다)

 

반응형

+ Recent posts