سؤال

لدي مشكلة غريبة في ذاكرة. بعد ساعات طويلة تصحيح الأخطاء والمحاولة أعتقد أنني وجدت شيئًا.

على سبيل المثال: أقوم بتخصيص سلسلة بسيطة:

sTest := 'SET LOCK_TIMEOUT ';

ومع ذلك ، تصبح النتيجة أحيانًا:

sTest = 'SET LOCK'#0'TIMEOUT '

لذلك ، يتم استبدال _ ببايت 0.

لقد رأيت هذا يحدث مرة واحدة (إعادة إنتاج أمر صعب ، يعتمد على التوقيت) في وظيفة system.move ، عندما يستخدم مكدس FPU (FILD ، FISTP) لنسخة الذاكرة السريعة (في حالة 9 حتى 32 بايت للتحرك):

...
@@SmallMove: {9..32 Byte Move}
fild    qword ptr [eax+ecx] {Load Last 8}
fild    qword ptr [eax] {Load First 8}
cmp     ecx, 8
jle     @@Small16
fild    qword ptr [eax+8] {Load Second 8}
cmp     ecx, 16
jle     @@Small24
fild    qword ptr [eax+16] {Load Third 8}
fistp   qword ptr [edx+16] {Save Third 8}
...

باستخدام عرض FPU و 2 طرق عرض تصحيح للذاكرة (Delphi -> View -> Debug -> CPU -> الذاكرة) رأيت أنه يحدث خطأ ... بمجرد ... لم أستطع إعادة إنتاج ...

قرأت هذا الصباح شيئًا عن وضع 8087CW ، ونعم ، إذا تم تغيير هذا إلى 27 دولارًا أمريكيًا ، احصل على فساد الذاكرة! عادة ما يكون 133 دولارًا أمريكيًا:

الفرق بين 133F و 027F $ هو أن 027F $ يقوم بإعداد FPU للقيام بحسابات أقل دقة (الحد من مضاعفة في وضع ممتد) ومعالجة Infiniti المختلفة (التي تم استخدامها في FPU الأقدم ، ولكن لم يتم استخدامها بعد الآن).

حسنًا ، لقد وجدت الآن لماذا لكن لا متى!

لقد غيرت عمل بلدي Asmprofiler مع فحص بسيط (بحيث يتم فحص جميع الوظائف عند الإدخال والمغادرة):

if Get8087CW = $27F then    //normally $1372?
  if MainThreadID = GetCurrentThreadId then  //only check mainthread
    DebugBreak;

لقد "تمتعت" ببعض الوحدات و DLL's و Bingo (انظر المكدس):

Windows.StretchBlt(3372289943,0,0,514,345,4211154027,0,0,514,345,13369376)
pngimage.TPNGObject.DrawPartialTrans(4211154027,(0, 0, 514, 345, (0, 0), (514, 345)))
pngimage.TPNGObject.Draw($7FF62450,(0, 0, 514, 345, (0, 0), (514, 345)))
Graphics.TCanvas.StretchDraw((0, 0, 514, 345, (0, 0), (514, 345)),$7FECF3D0)
ExtCtrls.TImage.Paint
Controls.TGraphicControl.WMPaint((15, 4211154027, 0, 0))

لذلك يحدث في stretchblt ...

ماذا تفعل الآن؟ هل هو خطأ من Windows ، أو خطأ في PNG (مدرج في D2007)؟ أم أن وظيفة System.Move لا تفشل؟

ملحوظة: ببساطة محاولة إعادة إنتاج لا تعمل:

  Set8087CW($27F);
  sSQL := 'SET LOCK_TIMEOUT ';

يبدو أنه أكثر غرابة ... ولكن عن طريق تصحيح الأخطاء على "get8087cw = 27f $ 'يمكنني إعادة إنتاجه على سلسلة أخرى: FPU الجزء 1:FPU part 1FPU الجزء 2:FPU part 2FPU الجزء 3:FPU part 3FPU النهائي: فاسد!:FPU Final: corrupt!

ملاحظة 2: ربما يجب مسح مكدس FPU في النظام.

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

المحلول

لم أر هذه القضية بالذات ، لكن Move يمكن أن تفسد بالتأكيد إذا كانت FPU في حالة سيئة. يمكن لبرنامج VPN الخاص بـ Cisco أن يفسد الأمور بشكل فظيع ، حتى لو كنت لا تفعل أي شيء يتعلق بالشبكة.

http://brianorr.blogspot.com/2006/11/intel-pentium-d-floating-point-unit.html مكسور

https://web.archive.org/web/2016001043520/http://www.dankohn.com/archives/343

http://blog.excastle.com/2007/08/28/delphi-bug-of-the-day-fpu-stack-leak/ (تعليقات ريتشي أناند)

في حالتنا ، نكتشف برنامج تشغيل VPN عربات التي تجرها الدواب وتبادل الحركة وملاء تشاردو مع إصدارات Delphi 7 ، واستبدل inttoSt تحرك الحجم أيضًا ، لأنها أكثر عرضة من System.move.

نصائح أخرى

قد يكون خطأ في برنامج تشغيل الفيديو الخاص بك لا يحافظ على كلمة التحكم 8087 عند تنفيذ عملية StretchBlt.
في الماضي ، رأيت سلوكًا مشابهًا عند استخدام برامج تشغيل طابعة معينة. يعتقدون أنهم يمتلكون 8087 CW وهم مخطئون ...

لاحظ أن القيمة الافتراضية لـ 8087 CW في Delphi تبدو 1372 دولارًا ؛ للحصول على شرح أكثر تفصيلاً لقيم CW ، انظر هذه المقالة: هذا ما يفسر أيضًا الموقف الذي وصفه مايكل جوستين عندما حصل 8087cw.

-جيرون

فقط للحصول على معلوماتك (في حالة وجود نفس المشكلة أيضًا): قمنا بترقية لبرنامجنا للعميل ، والشاشة التي تعمل باللمس الكاملة عند بدء تطبيقنا! تم تجميد Windows بالكامل! كان لا بد من إعادة تشغيل الكمبيوتر (إيقاف الطاقة). استغرق الأمر بعض الوقت لمعرفة سبب التجميد الكامل.

لحسن الحظ كان لدينا واحد (فقط 1!) stacktrace من AV في fastmove.largessemove. لقد عطلت استخدام SSE في Fastmove ، وذهبت المشكلة.

بالمناسبة: لدى الشاشة التي تعمل باللمس وحدة المعالجة المركزية في Nehemiah مع مجموعة شرائح S3.

لذلك ليس فقط يمكنك الحصول على فساد الذاكرة عند استخدام FPU ، ولكن أيضًا تجميد كامل!

بالنسبة لأولئك الذين ما زالوا مهتمين بهذا: هناك سبب محتمل آخر للمشاكل:

لا يزال Delphi Rio يشحن مع إصدار ASM مكسور من Move.

كان من دواعي سروري أن أواجه هذا الخطأ اليوم ، لحسن الحظ ، كان لدي حالة اختبار قابلة للتكرار. القضية هي هذه الكود:

* ***** BEGIN LICENSE BLOCK *****
 *
 * The assembly function Move is licensed under the CodeGear license terms.
 *
 * The initial developer of the original code is Fastcode
 *
 * Portions created by the initial developer are Copyright (C) 2002-2004
 * the initial developer. All Rights Reserved.
 *
 * Contributor(s): John O'Harrow
 *
 * ***** END LICENSE BLOCK ***** *)

// ... some less interesting parts omitted ...

@@LargeMove:
        JNG     @@LargeDone {Count < 0}
        CMP     EAX, EDX
        JA      @@LargeForwardMove

        // the following overlap test is broken
        // when size>uint(destaddr), EDX underflows to $FFxxxxxx, in which case 
        // we jump to @LargeForwardMove even if a backward loop would be appropriate
        // this will effectively shred everything at EDX + size
        SUB     EDX, ECX              // when this underflows ...
        CMP     EAX, EDX              // ... we also get CF=1 here (EDX is usually < $FFxxxxxx)
        LEA     EDX, [EDX+ECX]        // (does not affect flags)
        JNA     @@LargeForwardMove    // ... CF=1 so let's jump into disaster!

        SUB     ECX, 8 {Backward Move}
        PUSH    ECX
        FILD    QWORD PTR [EAX+ECX] {Last 8}
        FILD    QWORD PTR [EAX] {First 8}
        ADD     ECX, EDX
        AND     ECX, -8 {8-Byte Align Writes}
        SUB     ECX, EDX

مراجع

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