본문 바로가기

Programming/C#/Xna/Kinect/WPF

C# Attempted to read or write protected memory 에러

Managed Code에서 "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." 와 같은 오류가 발생하는 것은 흔하지 않다이것은 Native Code에서 잘못된 메모리를 참조하는 경우에 발생하는 데아시다시피 Managed환경에서는 포인터를 이용한 직접적인 메모리를 다루는 경우가 거의 없기 때문에 경험할 일이 없을 것이다하지만, PInvoke 와 같은 Interop 를 사용하는 경우라면 달라질 수 있다이는 결국 Native COM Managed 에서 사용하는 것이므로여전히 Native COM에서의 문제가 Managed환경으로 전달되었을 때, Access Violation의 위험성이 있는 것이다결국, Pageheap enable 하거나 해서 Crash Dump를 다시 잡는 것이 필요할 수도 있다일단, Memory Dump를 확인하면 문제가 발생한 Callstack에 아래와 같은 System.AccessViolationException을 볼 수 있다.

 

0:131> !dso

OS Thread Id: 0xacc (131)

RSP/REG          Object           Name

0000000027bda3f0 00000008d0fff488 System.Threading.Thread

0000000027bda438 00000008d0fff488 System.Threading.Thread

0000000027bda588 00000009710807f8 System.String

0000000027bda5a8 00000009710807f8 System.String

0000000027bda5b0 0000000971080908 System.String

0000000027bda668 0000000971080908 System.String

0000000027bda7d0 00000008d100adc8 System.String

0000000027bda7f8 00000008d100ca20 System.String

0000000027bda840 00000008d100b930 System.String

0000000027bda900 00000008d100b930 System.String

0000000027bda9c0 00000008d0fff7c0 System.String

0000000027bda9c8 00000008d0fff7c0 System.String

0000000027bdaaf0 00000008d10095f8 System.String

0000000027bdab08 00000008d100ca20 System.String

0000000027bdab68 00000008d100ca20 System.String

0000000027bdab80 00000008d0fff340 System.AccessViolationException

0000000027bdabe0 00000008d0fff340 System.AccessViolationException

0000000027bdad28 00000008d0fff340 System.AccessViolationException

0000000027bdb0f0 00000008d0ffd308 System.String

0000000027bdb108 00000008d0ffd290 System.String

0000000027bdb110 00000008d0ffd2b0 System.String

0000000027bdb138 00000008d0ffd270 System.String

0000000027bdb140 00000008d0ffd240 System.String

0000000027bdb148 00000008d0ffd208 System.String

0000000027bdb680 00000008d0fff340 System.AccessViolationException

0000000027bdb910 00000008d0fff340 System.AccessViolationException

0000000027bdb938 00000008d0fff340 System.AccessViolationException

. . .

그리고먼저, !verifyheap 을 통해서 Managed Heap Check 하는 것도 필요하다.

 

0:131> !verifyheap

-verify will only produce output if there are errors in the heap

------------------------------

Heap 0

object 0000000880ff00d0: does not have valid MT

curr_object : 0000000880ff00d0

Last good object: 0000000880ff00b0

----------------

total 4 objects

 

출력된 결과는 curr_object가 corruption되었다는 것과 메모리 영역에서 가장 가까운 Object중에 정상적인 Object address를 알려준다그러므로, curr_object 를 살펴보면 invalid 하다는 결과를 얻는다.

 

0:131> !do 0000000880ff00d0

<Note: this object has an invalid CLASS field>

Invalid object

 

0:131> !do 0000000880ff00b0

Name: System.String

MethodTable: 00000642784365a0

EEClass: 000006427803e4f0

Size: 32(0x20) bytes

GC Generation: 0

 (C:\WINDOWS\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

String: AES

Fields:

              MT            Field           Offset                 Type VT             Attr            Value Name

0000000000000000  4000096        8         System.Int32  1 instance                4 m_arrayLength

0000000000000000  4000097        c         System.Int32  1 instance                3 m_stringLength

0000000000000000  4000098       10          System.Char  1 instance               41 m_firstChar

0000000000000000  4000099       20        System.String  0   shared           static Empty

                                 >> Domain:Value  00000000d75a2aa0:NotInit Unable to get AppDomain d7900cc0

0000000000000000  400009a       28              SZARRAY  0   shared           static WhitespaceChars

                                 >> Domain:Value  00000000d75a2aa0:NotInit Unable to get AppDomain d7900cc0

 

정상적인 Data를 같이 보여주는 것은 GC에서는 Memory Allocation이 순차적으로 일어난다는 것과 무관하지 않다. low address에서 아래와 같이 Check 하여  Data를 살펴보거나 해당 Object MethodTable 정보를 Check 하는 것은 개발자가 관련있는 Code verify 하는 데 도움이 될 수 있기 때문이다.

 

0:131> dc 0000000880ff00b0

00000008`80ff00b0  784365a0 00000642 00000004 00000003  .eCxB...........  <--- valid Object

00000008`80ff00c0  00450041 00000053 00000000 00000000  A.E.S...........

00000008`80ff00d0  7843e5e0 00000642 0000000d 00000000  ..CxB...........  <--- invalid Object

00000008`80ff00e0  32313338 30323031 .................

 

또한 !gcroot 에 대한 결과로 관련된 Object 등을 Check 할 수 있는 데아래의 경우는 조금 실망스러운 결과이다.

 

0:131> !gcroot 0000000880ff00b0

Note: Roots found on stacks may be false positives. Run "!help gcroot" for

more info.

Scan Thread 52 OSThread 1440

Scan Thread 79 OSThread f4c

Scan Thread 145 OSThread 1f64

Scan Thread 149 OSThread 144c

Scan Thread 99 OSThread 18e4

Scan Thread 148 OSThread 1d38

Scan Thread 93 OSThread 1c0c

Scan Thread 91 OSThread 149c

Scan Thread 146 OSThread 1980

Scan Thread 96 OSThread 1dac

Scan Thread 136 OSThread f84

Scan Thread 98 OSThread 6ac

RSP:33c6cbb8:Root:  0000000880ff00b0(System.String)

RSP:33c6cd88:Root:  0000000880ff00b0(System.String)

RSP:33c6ce28:Root:  0000000880ff00b0(System.String)

RSP:33c6cfc0:Root:  0000000880ff00b0(System.String)

Scan Thread 106 OSThread 1a10

Scan Thread 108 OSThread 1ce4

Scan Thread 122 OSThread 190c

Scan Thread 121 OSThread 1698

Scan Thread 110 OSThread 14a8

Scan Thread 107 OSThread 1c10

Scan Thread 116 OSThread 1b80

Scan Thread 117 OSThread 141c

Scan Thread 131 OSThread acc

Scan Thread 135 OSThread 6e8

Scan Thread 126 OSThread 1d1c

Scan Thread 132 OSThread 1e18

 

해당 Object가 존재하는 98 Thread에서 연관된 Callstack Check 할 수 있다하지만, Native에서도 마찮가지로 Heap Corruption이 발생한 것은 Dumping 시점 이전에 문제가 발생한 것이 이후에 해당 Managed Heap의 사용에 의해 AV가 발생한 경우가 많기 때문에 문제가 정확히 드러나지 않을 수 있다그러므로다소 시간을 걸리더라도 Pageheap enable 하고 여러 차례 Dump를 수집할 필요가 있을 지도 모른다그리고, 1st chance AV 및 기타Exception에 대해서도 Callstack Check 라던가 관련성 여부를 살펴보는 것이 필요할 수 있다.



출처 : http://byung.egloos.com/4987870