انتهاك وصول استثناء / تحطم من C ++ الاستدعاء إلى C # وظيفة

StackOverflow https://stackoverflow.com/questions/1411110

سؤال

وهكذا لدي 3rd الطرف C قاعدة التعليمات البرمجية الأصلية ++ أنا أعمل مع (.LIB وملفات .hpp) التي استعملتها لبناء المجمع في C ++ / CLI لاستخدامها في نهاية المطاف في C #.

ولقد واجهت مشكلة خاصة عند التبديل من تصحيح لبيان الوضع، في أن أحصل على انتهاك استثناء وصول عندما يعود كود الاستدعاء ل.

ورمز من الملفات سكان المرتفعات الأصلية لوظيفة تنسيق رد:

typedef int (*CallbackFunction) (void *inst, const void *data);

ورمز من C ++ / CLI التفاف على وظيفة تنسيق رد: (ساوضح لماذا أنا أعلن اثنان في لحظة)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

و- بسرعة، والسبب أنا أعلن الثانية "UnManagedCallbackFunction" هي التي حاولت خلق رد "وسيط" في المجمع، لذلك غيرت سلسلة من الأصلية C ++> C # إلى إصدار الأصلية C ++> C ++ / CLI المجمع> C # ... الكشف الكامل، والمشكلة ما زالت تعيش، انها مجرد قد دفعت إلى C ++ / CLI المجمع الآن على نفس الخط (عودة).

وأخيرا، رمز تحطمها من C #:

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
    {
        Console.WriteLine("in hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);

        // provide object context for static member function
        helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
        if (hw == null || pData == null)
        {
            Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
            return 0;
        }

        // typecast data to DataLogger object ptr
        IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
        DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

        //Do Logging Stuff

        Console.WriteLine("exiting hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("Setting pData to zero...");
        pData = IntPtr.Zero;
        pInstance = IntPtr.Zero;
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("pInstance: {0}", pInstance);

        return 1;
    }

جميع يكتب إلى وحدة التحكم تتم ومن ثم فإننا نرى الحادث المروع على عودة:

<اقتباس فقرة>   

واستثناء غير معالج في 0x04d1004c في   helloworld.exe: 0xC0000005: وصول   انتهاك قراءة موقع 0x04d1004c.

إذا كنت خطوة إلى المصحح من هنا، كل ما أراه هو أن الإدخال الأخير على مكدس الاستدعاءات هو:> "04d1004c ()" الذي يقيم إلى قيمة عشرية من: 80805964

ما هي مثيرة للاهتمام إلا إذا نظرتم الى وحدة مما يدل على:

entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0

والآن، وأنا أعلم أن ما بين التصحيح والافراج عن بعض الأمور مختلفة تماما في العالم مايكروسوفت. أنا، من قلق بالطبع عن الحشو بايت وتهيئة المتغيرات، لذلك اذا كان هناك شيء أنا لا تقدم هنا، فقط اسمحوا لي أن أعرف وأنا أضيف إلى هذا المنصب (طويلة بالفعل). وأعتقد أيضا تعليمات برمجية تمت إدارتها قد لا يكون الافراج عن ملكية ومن ثم الاشياء C ++ الأصلي (وهو ما لم يكن لديك رمز) قد يكون محاولة لحذف أو تقتل الكائن pData، وبالتالي تحطمها التطبيق.

والمزيد من الكشف الكامل، كل ذلك يعمل بشكل جيد (على ما يبدو) في وضع التصحيح!

وهناك قضية الصفر رئيس حقيقي من شأنه أن نقدر أي مساعدة!

هل كانت مفيدة؟

المحلول

وأعتقد أن كومة حصلت على سحق بسبب غير متطابقة الاتفاقيات الدعوة: تجربة لوضع السمة

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

وعلى إعلان رد مندوب.

نصائح أخرى

<وأ href = "http://nicholas.piasecki.name/blog/2009/08/quicktip-when-your-app-crashes-in-release-mode-but-runs-fine-under-the- مصحح / "يختلط =" نوفولو noreferrer "> هذا لا يجيب مباشرة سؤالك ، لكنها قد تقودك في الاتجاه الصحيح بقدر ما وضع التصحيح بخير مقابل الافراج وضع لا بخير:

<اقتباس فقرة>   

ومنذ المصحح يضيف الكثير من المعلومات إلى المكدس، عموما الحشو من حجم وتخطيط برنامجي في الذاكرة، وكنت "الحصول على محظوظ" في وضع التصحيح من قبل الخربشة على 912 بايت من الذاكرة التي فالرجاء ملاحظة "حفظ السجلات. ر مهم جدا. بدون المصحح، على الرغم من أنني كنت الخربشة على رأس الأمور الهامة بدلا من ذلك، في نهاية المطاف المشي خارج مساحة الذاكرة بلدي، مما تسبب في إمكانية التشغيل المتداخل لحذف الذاكرة التي لا تملك.

ما هو تعريف DataLoggerWrap؟ قد يكون حقل حرف صغير جدا بالنسبة البيانات التي تتلقاها.

ولست متأكدا ما بك تحاول تحقيق.

وهناك بعض النقاط:

1) جامع القمامة هو أكثر عدوانية في وضع الافراج حتى مع ملكية سيئة السلوك الذي وصف ليس من غير المألوف.

2) أنا لا يفهم ما تحاول رمز أدناه أن تفعل؟

IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

ويمكنك استخدام GCHandle.Alloc لقفل مثيل DataLoggerWrap في الذاكرة، ولكن بعد ذلك لا يمكن ان يمر بها لغير المدارة - لذلك لماذا قفله؟ يمكنك أيضا تحرير أبدا ذلك؟

والسطر الثاني ثم الاستيلاء على العودة إشارة - لماذا مسار دائري؟ لماذا الإشارة - كنت تستخدم أبدا أنه

و3) تعيين IntPtrs لاغية - لماذا؟ - هذا لن يكون له أي تأثير خارج نطاق الدالة

و4) عليك أن تعرف ما عقد من رد الاتصال. الذي يملك pData الاستدعاء أو وظيفة الدعوة؟

وأنا معjdehaan، إلا CallingConvetion.StdCall يمكن أن يكون الجواب، وخصوصا عندما تتم كتابة ليب 3rd الطرف في BC ++، على سبيل المثال.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top