يتعطل إنشاء /MT و/MD، ولكن فقط عندما لا يتم إرفاق مصحح الأخطاء:كيفية التصحيح؟[ينسخ]

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

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

لدي تطبيق C++ صغير ذو ترابط واحد، تم تجميعه وربطه باستخدام Visual Studio 2005، والذي يستخدم التعزيز (CRC، وprogram_options، وtokenizer)، ومجموعة صغيرة من STL، ورؤوس النظام الأخرى المتنوعة.

(الغرض الأساسي منه هو القراءة في ملف .csv وإنشاء ملف .dat ثنائي مخصص وملف .h مقترن للإعلان عن الهياكل التي "تشرح" تنسيق ملف .dat.)

تتعطل الأداة (انتهاك الوصول إلى NULL) عند تشغيلها خارج مصحح الأخطاء، فقط في الإصدار.على سبيل المثالالضغط على F5 لا يؤدي إلى تعطل الأداة، كما يفعل Ctrl-F5.عندما أقوم بإعادة توصيل مصحح الأخطاء، أحصل على هذه المكدس:

ntdll.dll!_RtlAllocateHeap@12()  + 0x26916 bytes    
csv2bin.exe!malloc(unsigned int size=0x00000014)  Line 163 + 0x63 bytes C
csv2bin.exe!operator new(unsigned int size=0x00000014)  Line 59 + 0x8 bytes C++
>csv2bin.exe!Record::addField(const char * string=0x0034aac8)  Line 62 + 0x7 bytes  C++
csv2bin.exe!main(int argc=0x00000007, char * * argv=0x00343998)  Line 253   C++
csv2bin.exe!__tmainCRTStartup()  Line 327 + 0x12 bytes  C

الخط الذي يتعطل عليه هو تخصيص ذو مظهر غير ضار إلى حد ما:

pField = new NumberField(this, static_cast<NumberFieldInfo*>(pFieldInfo));

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

تختفي المشكلة عند التحويل البرمجي باستخدام /MTd أو /MDd (وقت تشغيل التصحيح)، وتعود مرة أخرى عند استخدام /MT أو /MD.

يتم تحميل NULL من المكدس، ويمكنني رؤيته في عرض الذاكرة._RtlAllocateHeap@12 + 0x26916 بايت يبدو وكأنه ضخم إزاحة، مثل إجراء قفزة غير صحيحة.

لقد حاولت _HAS_ITERATOR_DEBUGGING في بنية تصحيح الأخطاء والتي لم تثير أي شيء مشبوه.

يؤدي إسقاط HeapValidate في بداية ونهاية Record::addField إلى إظهار كومة الذاكرة المؤقتة "موافق" حتى وقت تعطلها.

كان هذا يعمل - لست متأكدًا تمامًا مما تغير من الآن وحتى آخر مرة قمنا فيها بتجميع الأداة (ربما منذ سنوات مضت، ربما في ظل VS أقدم).لقد جربنا إصدارًا أقدم من التعزيز (1.36 مقابل 1.38).

قبل العودة إلى التحقيق اليدوي للكود أو تغذية هذا إلى PC-Lint والتمشيط من خلال مخرجاته، هل هناك أي اقتراحات حول كيفية تصحيح هذا بشكل فعال؟

[سأكون سعيدًا بتحديث السؤال بمزيد من المعلومات، إذا طلبت معلومات في التعليقات.]

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

المحلول

هناك فرق واحد لا يعرفه أحد بين التشغيل مع مصحح الأخطاء المرفق أم لا وهو OS Debug Heap (انظر أيضًا لماذا يعمل الكود الخاص بي ببطء عندما يكون لدي مصحح أخطاء مرفق؟).يمكنك إيقاف تشغيل كومة التصحيح باستخدام متغير البيئة _NO_DEBUG_HEAP .يمكنك تحديد ذلك إما في خصائص جهاز الكمبيوتر الخاص بك، أو في إعدادات المشروع في Visual Studio.

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

ومع ذلك، كن على علم بأن تلف الذاكرة قد يكون من الصعب تصحيحه، حيث غالبًا ما يكون السبب الحقيقي للفساد (مثل تجاوز سعة المخزن المؤقت) بعيدًا جدًا عن المكان الذي ترى فيه الأعراض (التعطل).

نصائح أخرى

التحقق من التطبيق كان مفيدًا للغاية في حل هذه المشكلة بمجرد حصولي على _NO_DEBUG_HEAP=1 في البيئة، راجع الإجابة المقبولة هنا: هل تبحث عن المكان الذي تم فيه تحرير الذاكرة آخر مرة؟

ربما من الجدير بالذكر أيضًا كومة الصفحة, ، والذي وجدته أثناء البحث في أداة التحقق من التطبيق.يبدو أنه يغطي بعض الأرضية المماثلة.

(لمعلوماتك، لقد كان تجاوز سعة المخزن المؤقت مكونًا من حرف واحد:

m_pEnumName = (char*)malloc(strlen(data) /* missing +1 here */);
strcpy(m_pEnumName, data);

…حجة أخرى جيدة يبعث على السخرية لعدم استخدامها strcpy مباشرة.)

عادةً ما يكون التعطل داخل new أو malloc بمثابة إشارة إلى تلف البنية (الداخلية) لتطبيق malloc.ويتم ذلك في أغلب الأحيان عن طريق الكتابة بعد التخصيص السابق (تجاوز سعة المخزن المؤقت).ثم في المكالمة التالية إلى new أو malloc، يتعطل التطبيق لأن البنية الداخلية تحتوي الآن على بيانات غير صالحة.

تحقق مما إذا كان بإمكانك الكتابة فوق أي مساحة مخصصة سابقة.

إذا كان تطبيقك محمولاً، فيمكنك محاولة إنشائه على نظام التشغيل Linux وتشغيله عليه فالغريند.

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