أسباب شائعة للأخطاء في إصدار الإصدار غير موجود في وضع التصحيح

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

  •  21-09-2019
  •  | 
  •  

سؤال

ما هي الأسباب النموذجية للخلل وسلوك البرنامج غير الطبيعي الذي يظهر فقط في وضع تجميع الإصدار ولكن لا يحدث عندما يكون في وضع التصحيح؟

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

المحلول

في كثير من الأحيان ، في وضع التصحيح في C ++ ، يتم تهيئة جميع المتغيرات الفارغة ، في حين أن نفس الشيء لا يحدث في وضع الإصدار ما لم ينص بشكل صريح.

تحقق من وجود أي وحدات ماكرو تصحيح ومتغيرات غير مؤهلة

هل يستخدم برنامجك الخيوط ، ثم يمكن أن يؤدي التحسين أيضًا إلى بعض المشكلات في وضع الإصدار.

تحقق أيضًا من جميع الاستثناءات ، على سبيل المثال غير مرتبط بشكل مباشر بوضع الإصدار ، ولكن في وقت ما نتجاهل بعض الاستثناءات الحرجة ، مثل انتهاك الوصول إلى MEM في VC ++ ، ولكن يمكن أن يكون الشيء نفسه مشكلة على الأقل في نظام التشغيل Linux ، Solaris. من الناحية المثالية ، يجب ألا يلتقط البرنامج مثل هذه الاستثناءات الحرجة مثل الوصول إلى مؤشر فارغ.

نصائح أخرى

يتم استخدام مأزق شائع تعبير ذو تأثير جانبي داخل تأكيد.

قد تكون الاختلافات الأخرى:

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

لقد تعرضت للعض من عدد من الأخطاء في الماضي والتي كانت جيدة في بناء التصحيح ولكن تعطل في بنيات الإصدار. هناك العديد من الأسباب الكامنة (بما في ذلك بالطبع تلك التي تم تلخيصها بالفعل في هذا الموضوع) وقد وقعت في كل ما يلي:

  • متغيرات الأعضاء أو وظائف الأعضاء في #ifdef _DEBUG, ، بحيث يكون الفصل مختلفًا في بناء التصحيح. أحيانا #ifndef NDEBUG يستخدم في بناء الإصدار
  • وبالمثل ، هناك مختلف #ifdef الذي يحدث ليكون موجودًا فقط في أحد المباني
  • يستخدم إصدار Debug إصدارات التصحيح من مكتبات النظام ، وخاصة وظائف تخصيص الكومة والذاكرة
  • وظائف محفوظة في بناء الإصدار
  • ترتيب إدراج ملفات الرأس. هذا لا ينبغي أن يسبب مشاكل ، ولكن إذا كان لديك شيء مثل أ #pragma pack لم يتم إعادة تعيين ذلك ، فإن هذا يمكن أن يؤدي إلى مشاكل سيئة. يمكن أن تحدث مشكلات مماثلة أيضًا باستخدام الرؤوس المسبقة ويشمل القسري
  • ذاكرة التخزين المؤقت: قد يكون لديك رمز مثل ذاكرة التخزين المؤقت التي يتم استخدامها فقط في بنيات الإصدار ، أو حدود حجم ذاكرة التخزين المؤقت المختلفة
  • تكوينات المشروع: قد تحتوي تكوينات التصحيح والإصدار على إعدادات بناء مختلفة (من المحتمل أن يحدث هذا عند استخدام IDE)
  • ظروف السباق ، وقضايا التوقيت والآثار الجانبية المتنوعة التي تحدث نتيجة لتصحيح رمز فقط

بعض النصائح التي جمعتها على مر السنين للوصول إلى أسفل أخطاء/حشرات الإصدار:

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

نعم! ، إذا كان لديك تجميع مشروط ، فقد يكون هناك أخطاء توقيت (رمز الإصدار المحسّن ، رمز التصحيح غير المحسّن) ، إعادة استخدام الذاكرة مقابل Debug Heap.

يمكن أن يكون ، خاصة إذا كنت في عالم C.

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

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

تحرير: أرى الآخر المذكور: بالطبع قد يكون لديك أقسام رمز كاملة يتم استبعادها بشكل مشروط إذا لم يتم تجميعها في وضع التصحيح. إذا كان هذا هو الحال ، آمل أن يكون هذا هو رمز تصحيح الأخطاء وليس شيئًا حيويًا لصحة البرنامج نفسه!

تتصرف وظائف مكتبة CRT بشكل مختلف في إصدار Debug vs ( /MD VS /MDD).

على سبيل المثال ، غالبًا ما تقوم إصدارات التصحيح بتجهيز المخازن المؤقتة التي تنقلها إلى الطول المشار إليها للتحقق من مطالبتك. الامثله تشمل strcpy_s, StringCchCopy, ، إلخ. حتى لو انتهت السلاسل في وقت سابق ، Szdest أفضل ن بايت طويل!

بالتأكيد ، على سبيل المثال ، إذا كنت تستخدم الإنشاءات مثل

#if DEBUG

//some code

#endif

في .NET ، حتى لو لم تستخدم التجميع الشرطي مثل #if DEBUG, ، لا يزال المترجم أكثر ليبرالية مع تحسينات في وضع الإصدار مما هو عليه في وضع التصحيح ، مما قد يؤدي إلى إطلاق الأخطاء فقط.

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

بدون مزيد من التفاصيل ، سأفترض أن "NOT OP" يعني أنه لا يجمع أو يرمي نوعًا من الخطأ في وقت التشغيل. تحقق مما إذا كان لديك رمز يعتمد على إصدار التجميع ، إما عبر #if DEBUG العبارات أو عبر طرق تحمل علامة مع Conditional ينسب.

هذا ممكن ، إذا كان لديك تجميع مشروط بحيث يختلف رمز التصحيح ورمز الإصدار ، وهناك خطأ في الكود الذي يستخدم فقط في وضع الإصدار.

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

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

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

هناك تحسينات برمجية يمكن كسر الرمز الصحيح لأنها عدوانية للغاية.

حاول تجميع الكود الخاص بك مع تشغيل أقل تحسين.

في وظيفة غير void ، يجب أن تنتهي جميع مسارات التنفيذ ببيان العودة.

في وضع التصحيح ، إذا نسيت إنهاء مثل هذا المسار ببيان الإرجاع ، فعادة ما تُرجع الوظيفة 0 بشكل افتراضي.

ومع ذلك ، في وضع الإصدار قد تُرجع وظيفتك قيم القمامة ، والتي قد تؤثر على كيفية تشغيل البرنامج.

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

لقد واجهت للتو أنه عندما كنت أتصل بوظيفة التجميع التي لم تستعيد القيم السابقة للسجلات.

في تكوين "الإصدار" ، تم تجميع VS مع /O2 مما يحسن الرمز للسرعة. وبالتالي بعض المتغيرات المحلية حيث مجرد رسم الخرائط لسجلات وحدة المعالجة المركزية (للتحسين) والتي تمت مشاركتها مع الوظيفة المذكورة أعلاه مما يؤدي إلى فساد ذاكرة خطير.

على أي حال ، انظر إذا كنت لا تعبث بشكل غير مباشر مع سجلات وحدة المعالجة المركزية في أي مكان في الكود الخاص بك.

أتذكر بينما كنا نبني DLL و PDB في C/C ++.

أتذكر هذا:

  • من شأن إضافة بيانات السجل أن تجعل الأخطاء تحرك أو تختفي أو تختفي أو يظهر خطأ آخر تمامًا (لذلك لم يكن خيارًا حقًا).
  • العديد من هذه الأخطاء حيث بسبب تخصيص char في strcpy و strcat ومصفوفات char [] وما إلى ذلك ...
  • لقد أفسدنا بعضًا عن طريق تشغيل Checker Bounds وببساطة إصلاح مشكلات تخصيص الذاكرة/Dealloc.
  • في كثير من الأحيان ، مررنا بشكل منهجي من خلال الكود ونصلحوا تخصيص char (مثل من خلال جميع الملفات).
  • بالتأكيد هو شيء يتعلق بتخصيص الذاكرة وإدارتها والقيود والاختلافات بين وضع التصحيح ووضع الإصدار.

ثم تأمل في الأفضل.

أحيانًا ، قمت بتسليم إصدارات تصحيح الأخطاء من DLLs مؤقتًا للعملاء ، حتى لا أتوقف عن الإنتاج ، أثناء العمل على هذه الأخطاء.

أسباب أخرى يمكن أن تكون مكالمات DB. هل تقوم بحفظ وتحديث السجل نفسه عدة مرات في نفس الموضوع ، وأحيانًا للتحديث. من المحتمل أن التحديث فشل أو لم يعمل كما هو متوقع لأن الأمر CREATE السابق كان لا يزال معالجًا وللتحديث ، فشلت استدعاء DB في العثور على أي سجل. لن يحدث هذا في Debug حيث يتأكد Debugger من إكمال جميع المهام المعلقة قبل الهبوط.

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