انتهاك الوصول إلى VC++ 6.0 عند تشغيله في مصحح الأخطاء
-
22-08-2019 - |
سؤال
أحاول إضافة تحسينات إلى برنامج VC++ 6.0 عمره 4 سنوات.يتم تشغيل بناء تصحيح الأخطاء من سطر الأوامر ولكن ليس في مصحح الأخطاء:يتعطل بسبب انتهاك الوصول داخل printf().إذا قمت بتخطي printf، فسوف يتعطل في malloc() (يتم استدعاؤه من داخل fopen()) ولا يمكنني تخطي ذلك.
هذا يعني أنه لا يمكنني العمل في مصحح الأخطاء ويجب علي الاعتماد على عبارات printf القديمة لمعرفة ما يحدث.من الواضح أن هذا يجعل الأمر أصعب بكثير.
هل لديك أي فكرة عن سبب فشل printf() و malloc() عند التشغيل ضمن مصحح أخطاء VC++؟أنا لست جيدًا في هذه الأشياء ذات المستوى المنخفض!
إليك مكدس الاستدعاءات بعد انتهاك الوصول:
_heap_alloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 394 + 8 bytes
_nh_malloc_dbg(unsigned int 24, int 0, int 2, const char * 0x0046b3d8 `string', int 225) line 242 + 21 bytes
_malloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 163 + 27 bytes
_lock(int 2) line 225 + 19 bytes
_getstream() line 55 + 7 bytes
_fsopen(const char * 0x00468000 `string', const char * 0x00466280 `string', int 64) line 61 + 5 bytes
fopen(const char * 0x00468000 `string', const char * 0x00466280 `string') line 104 + 15 bytes
open_new_log(const char * 0x00468000 `string') line 66 + 14 bytes
log_open(const char * 0x00468000 `string', int 0) line 106 + 9 bytes
Xlog_open(const char * 0x00468000 `string', int 0) line 51 + 13 bytes
service_start(unsigned long 1, char * * 0x009a0e50) line 3152 + 12 bytes
service_init2(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, char * 0x00466540 `string', unsigned long 1, char * * 0x009a0e50) line 508 + 13 bytes
service_init(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, unsigned long 2, char * * 0x009a0e50) line 548
main(unsigned long 2, char * * 0x009a0e50) line 3131
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817067()
فيما يلي تفكيك التصحيح حتى العملية التي فشلت:
0041EA7E jmp _heap_alloc_dbg+2B3h (0041eb23)
0041EA83 mov edx,dword ptr [_lTotalAlloc (004b4294)]
0041EA89 add edx,dword ptr [nSize]
0041EA8C mov dword ptr [_lTotalAlloc (004b4294)],edx
0041EA92 mov eax,[_lCurAlloc (004b429c)]
0041EA97 add eax,dword ptr [nSize]
0041EA9A mov [_lCurAlloc (004b429c)],eax
0041EA9F mov ecx,dword ptr [_lCurAlloc (004b429c)]
0041EAA5 cmp ecx,dword ptr [_lMaxAlloc (004b42a0)]
0041EAAB jbe _heap_alloc_dbg+249h (0041eab9)
0041EAAD mov edx,dword ptr [_lCurAlloc (004b429c)]
0041EAB3 mov dword ptr [_lMaxAlloc (004b42a0)],edx
0041EAB9 cmp dword ptr [_pFirstBlock (004b4298)],0
0041EAC0 je _heap_alloc_dbg+25Fh (0041eacf)
0041EAC2 mov eax,[_pFirstBlock (004b4298)]
0041EAC7 mov ecx,dword ptr [pHead]
0041EACA mov dword ptr [eax+4],ecx
هنا هو المصدر الذي يستدعي fopen() ويفشل في malloc()
FILE *open_new_log( const char *logfile )
{
FILE *fp;
int retry = 0;
while( ( fp = fopen( logfile, "w" ) ) == NULL && ++retry < 300 )
Sleep( 1000 );
return( fp );
}
الخطأ الذي أحصل عليه هو
Unhandled exception inPISCOOP.exe: 0xC00000005: Access Violation
يعتبر،
--- أليستير.
المحلول
ويمكنك استخدام _CrtSetDbgFlag()
لتمكين مجموعة من التقنيات كومة التصحيح مفيدة. هناك مجموعة من ظائف التصحيح CRT المتاحة من شأنها أن تساعد على تعقب حيث مشكلتك هي.
نصائح أخرى
عند تشغيل من المصحح، يستخدم كومة مختلفة. هذا ويشار إليها باسم كومة التصحيح م>. وهذا له سلوك مختلف عن كومة استخدامها خارج المصحح، وهناك لمساعدتك على التقاط المشاكل مثل هذا واحد.
لاحظ أن Win32 و"كومة التصحيح" متميزة من VC ++ "كومة التصحيح". وتهدف على حد سواء لبذل المزيد من الجهد أو أقل نفس الشيء، ولكن. انظر هذه المقالة الذي يصف الفرق في السلوك عند تشغيل التطبيق تحت المصحح.
في هذه الحالة، وربما كنت قد تلف كومة قبل استدعاء هذه الوظيفة، إما عن طريق شطب نهاية أو إيقاف تشغيله بداية كتلة الكومة.
أسهل الطرق (شريطة أن تطبيقك لا يستخدم الذاكرة على نطاق واسع) هو تمكين التحقق من كومة الصفحة الكاملة (والذي سيضع ما يسمى بصفحة الحماية بعد صفحة الذاكرة التي يتم توفير التخصيص منها، والتي بدورها ستحدد بدقة مكان في التعليمات البرمجية الخاصة بك حيث يحدث الفساد).
بالنظر إلى أن لديك أدوات تصحيح أخطاء Windows في متناول يديك، قم بتشغيل الأمر gflags التالي لتكوين كومة الصفحة الكاملة:
gflags[.exe] /p /enable yourapp.exe /full
ملاحظة، يجب عليك تقديم اسم قابل للتنفيذ وحيد (أي.بدون بادئة المسار!)
ثم قم فقط بتشغيله ضمن مصحح الأخطاء - وسوف ينقطع عن المحاولة الأولى لإفساد الكومة.الفرق هنا هو أن تلف الكومة هو في الغالب عيوب متأخرة تظهر نفسها لاحقًا، عندما تكون عملية كومة الذاكرة المؤقتة (المحتملة) سارية المفعول.
لاحظ ايضا:
gflags[.exe] /p /enable yourapp.exe /full /backwards
بالإضافة إلى ذلك، سيتم وضع صفحة حماية قبل التخصيص الخاص بك.
سيؤدي التشغيل باستخدام رمز التبديل /p وحده إلى عرض خيارات صفحة الكومة سارية المفعول حاليًا.
قد يكون لديك علة الفساد الكومة. قد يكون طلبك تلف كومة قبل أن يتم استدعاء open_new_log()
.
أظن أن جماتياس على حق.من المحتمل أن يكون السبب الجذري للمشكلة في مكان آخر غير مكان التعطل.
هناك الكثير من الأشياء التي يمكن أن تسبب تلف الكومة.
- الكتابة بعد نهاية (أو بداية) كتلة الذاكرة التي تم تخصيصها.
- تحرير مؤشر مرتين، أو تحرير مؤشر لم يتم تخصيصه.
- تعدد مؤشرات الترابط لبرنامجك والربط مع RTL أحادي الترابط (غير آمن).
- تخصيص الذاكرة من كومة واحدة وتحريرها على كومة أخرى.
- الخ، الخ،
نظرًا لأنك تستخدم Visual C++، يمكنك استخدام ميزة _CrtSetDbgFlag() الخاصة بكومة التصحيح لتشغيل التحقق من الأخطاء.يمكنك ضبطه للتحقق من سلامة الكومة عند كل مكالمة إلى malloc أو مجانًا.سيتم تشغيل ذلك ببطء شديد، ولكن يجب أن يحدد لك مكان الخطأ.
ابحث عن _CrtSetDbgFlag في مستندات المترجم.
ولدي شكوك بأن هناك DLL مترجمة مع إصدار مختلف من وقت التشغيل C ++ من بقية التطبيق. وهذا غالبا ما يؤدي إلى "الذاكرة في عنوان XXX تعذر 'قراءة' / 'كتب'" الانتهاكات.