2016-02-10 14 views
5

पर काम करता है रात की बिल्ड मशीन पर बनाया गया एक एप्लीकेशन विंडोज सर्वर 2012 पर काम नहीं करता है लेकिन अन्य डेस्कटॉप पर ठीक काम करता है।विंडोज 7 पर निर्मित बिनरी विंडोज सर्वर 2012

का अपवाद "संरक्षित स्मृति को पढ़ने या लिखने का प्रयास किया गया। यह प्रायः एक संकेत है कि अन्य स्मृति भ्रष्ट है।" फेंक दिया गया है

जब मैं WindowsServer2012 मशीन और मशीन बनाने के लिए दूरस्थ डिबगिंग का उपयोग करके डीबग करता हूं, तो मुझे लगता है कि यह अपवाद उस स्थान पर फेंक दिया गया है जहां कर्नेल 32 कॉल HeapSize कोड में बनाया गया है। यहाँ कैसे HeapSize आयात किया जाता है जाता है और कहा जाता है:

public UnManagedBuffer(StringBuilder sb) 
    { 
     PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
     Size = UnManagedMemory.SizeOf(PtrStart); 
     PtrWriteNextValue = PtrStart + Size - 1; 
     PtrReturnNextValue = PtrStart; 
    } 

क्या याद आ रही है और कैसे इसे ठीक करने के किया जा सकता है पर कोई सुराग:

[DllImport("kernel32")] 
static extern int HeapSize(int hHeap, int flags, void* block); 
// Returns the size of a memory block. 

public static int SizeOf(void* block) 
{ 
    int result = HeapSize(ph, 0, block); 
    if (result == -1) throw new InvalidOperationException(); 
    return result; 
} 

यह कहा जाता है एक असुरक्षित वर्ग के निर्माता के हिस्से के रूप?

यह है कि मैं क्या Windbg में देखते हैं:

This is what I see in Windbg

इवेंटलॉग पता चलता है:

Log Name:  Application 
    Source:  .NET Runtime 
    Level:   Error 
    Keywords:  Classic 
    Description: 
Application: TestEngine.exe 
Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.AccessViolationException 
    at Core.Utils.UnManagedMemory.HeapSize(Int32, Int32, Void*) 
    at Core.Utils.UnManagedMemory.SizeOf(Void*) 
    at Core.Utils.UnManagedBuffer..ctor</Event> 

Faulting application name: TestEngine.exe, version: 1.0.0.0, time stamp: 0x56b532bb 
Faulting module name: ntdll.dll, version: 6.3.9600.18185, time stamp: 0x5683f0c5 
Exception code: 0xc0000005 
Fault offset: 0x0000000000057306 
Faulting process id: 0x2eb8 
Faulting application start time: 0x01d164e45b12d7dd 
Faulting application path: C:\NGDLM\Lib\TestEngine.exe 
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll 
Report Id: bea6eb89-d0d7-11e5-80eb-0050568cd888 
Faulting package full name: 
Faulting package-relative application ID: 
+0

आप PInvoke का उपयोग कर रहे HeapSize कॉल करने के लिए? क्या आप विधि घोषणा दिखा सकते हैं? (इसके अलावा, सभी मशीनों एक ही वास्तुकला, यानी 86 64 बनाम हैं?) – stuartd

+1

, एक क्रैश डंप ले लो [windbg + एसओएस] (https://blogs.msdn.microsoft.com/kaevans/2011/04 साथ उस पर प्रहार/11/परिचय-से-विंडबग-नेट-डेवलपर्स /) –

+0

हाँ कॉन्फ़िगरेशन समान है - दोनों मशीनें x64 हैं और कोड x64 कॉन्फ़िगरेशन में बनाया गया है। कोड है: [डीएलआईएमपोर्ट ("कर्नेल 32")] स्थैतिक बाहरी int हेपसाइज (int hHeap, int flags, शून्य * ब्लॉक); // स्मृति ब्लॉक के आकार को वापस करता है। सार्वजनिक स्थैतिक int sizeof (शून्य * ब्लॉक) { पूर्णांक परिणाम = HeapSize (पीएच, 0, ब्लॉक); अगर (परिणाम == -1) नया अवैधऑपरेशन अपवाद(); वापसी परिणाम; } – NVK

उत्तर

2

कोड आपके द्वारा लिखी गई कभी नहीं काम किया जाना चाहिए था।

HeapSize एक ढेर का आकार देता है, उदाहरण के लिए, HeapAlloc पर कॉल करके आवंटित कुछ।

lpMem [में]

स्मृति ब्लॉक जिसका आकार समारोह प्राप्त करेंगे के लिए एक सूचक: HeapSize लिए प्रदान की जाती सूचक सूचक HeapAlloc फोन करके लौटे होना चाहिए। यह एक पॉइंटर हैपएलोक या हेपआरएलोक फ़ंक्शन द्वारा लौटाया गया है।

आप HeapSize कॉल कर रहे हैं, लेकिन एक सूचक है कि कहीं भी है कि ढेर के भीतर हो सकता है प्रदान करने, या नहीं है कि ढेर बिल्कुल में:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

इतना ही नहीं Marshal.StringToHGlobalAnsi() एक सूचक कहीं ढेर में ही करने के लिए एक सूचक वापस आ जाएगी ढेर में, और नहीं, तो आप भी नहीं जानते कि जो सूचक ढेर आवंटित किया गया था से, क्योंकि प्रक्रिया आवंटित एकाधिक ढेर हो सकता है।

इससे कोई फर्क नहीं पड़ता, क्योंकि ऐसा लगता है कि आपको इस कार्य के उद्देश्य की मौलिक गलतफहमी है - आप एक ढेर के अंदर किए गए आवंटन के आकार को पुनः प्राप्त करने के लिए इसका उपयोग कर रहे हैं। Marshal.StringToHGlobalAnsi() द्वारा लौटाई गई स्मृति HeapAlloc() पर कॉल करके आवंटित नहीं की गई है (क्योंकि यह ढेर नहीं है!), इसे AllocHGlobal पर कॉल करके आवंटित किया गया है।क्योंकि इस विधि अप्रबंधित एक स्ट्रिंग के लिए आवश्यक स्मृति आबंटित करता है, हमेशा FreeHGlobal फोन करके स्मृति मुक्त

: स्मृति यह द्वारा आवंटित Marshal.FreeHGlobal() फोन करके मुक्त हो गया है:

Marshal.StringToHGlobal() के प्रलेखन से।

यह Marshal विधि HeapAlloc, HeapSize या संबंधित कार्यों के साथ कोई संबंध नहीं है।

आप वास्तव में सूचक Marshal.StringToHGlobal() द्वारा वापस की स्मृति आवंटन के आकार पता लगाने के लिए करना चाहता था, तो आप source of the the Marshal class के माध्यम से खुदाई और है कि यह Win32 समारोह LocalAlloc का उपयोग करता है यह पता लगाने सकता है। ऐसा इसलिए होता है कि LocalAlloc में एक बहन फ़ंक्शन LocalSize है, जिसका उपयोग वास्तव में आवंटन के आकार को खोजने के लिए किया जा सकता है।

हालांकि, इस बात की कोई गारंटी नहीं है कि ऐसा करने से भविष्य में काम होगा, क्योंकि नेट फ्रेमवर्क कोई गारंटी नहीं देता है कि यह LocalAlloc का उपयोग जारी रखेगा। अगर वे आंतरिक बदलते हैं LocalSize काम करना बंद कर सकता है।

...

कि सब के सब ने कहा:

मुझे नहीं लगता कि इस के किसी भी है कि तुम क्या पहली जगह

में करने के लिए फिर से अपने कोड को देखते हुए मतलब है:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

आप एएनएसआई स्ट्रिंग आपको लौटा की लंबाई खोजने की कोशिश कर रहे हैं।

HeapSize या LocalSize का यह व्यवसाय पूरी तरह से अप्रासंगिक है।

तुम सिर्फ एक 'एएनएसआई' स्ट्रिंग की लंबाई को खोजने के लिए चाहते हैं, तो आप सिर्फ एक बेवकूफ सरल स्ट्रिंग की लंबाई को लागू, या आप के लिए पहले से ही वहाँ कार्यान्वयन के किसी भी उपयोग करने के लिए की जरूरत है।

निम्नलिखित कार्यक्रम Marshal.StringToHGlobal() का उपयोग करता है, और प्रिंट:

स्ट्रिंग: 'हैलो'; लंबाई: 5

public static void Main(string[] args) 
    { 
     IntPtr strPtr = IntPtr.Zero; 
     string str = "Hello"; 
     try 
     { 
      strPtr = Marshal.StringToHGlobalAnsi(str); 

      Console.Out.WriteLine("String: '{0}'; Length: {1}", str, AnsiStrLen(strPtr)); 
     } 
     finally 
     { 
      if(strPtr != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(strPtr); 
      } 
     } 
    } 

    public static int AnsiStrLen(IntPtr strPtr) 
    { 
     int size = 0; 

     while(Marshal.ReadByte(strPtr) != 0) 
     { 
      size++; 
      strPtr = IntPtr.Add(strPtr, 1); 
     } 

     return size; 
    }