هل من الممكن وضع علامة على جزء من الذاكرة على أنها "خارج الحدود" حتى لا يخصص مدير الكومة منه؟

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

سؤال

في وقت سابق اليوم سألت هذا السؤال.

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

إطلاق وحدة الاختبار من مصحح الأخطاء

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194     /* Different memory location */

إطلاق وحدة الاختبار من سطر الأوامر

// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960

// Lots of other code
// ...

// Destroy object
delete pObject;

// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960     /* Same memory location */

في تلخيص:

  • عند إطلاق اختبار الوحدة من سطر الأوامر, مكالمات لاحقة إلى new لتخصيص Object (deleteجي السابق Object قبل تخصيص واحدة جديدة) ارجع دائمًا نفس العنوان في الذاكرة.
  • عند إطلاق اختبار الوحدة من تصحيح الأخطاء, مكالمات لاحقة إلى new لتخصيص Object (deleteجي السابق Object قبل تخصيص واحدة جديدة) ارجع دائمًا فريدة من نوعها العنوان في الذاكرة.

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

هناك جزأان لسؤالي:

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

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


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

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

المحلول

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

ما تفعله هو:

Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed

يجب عليك بدلاً من ذلك إعادة هيكلة اختبار الوحدة بحيث يعمل مثل هذا:

Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it.  If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests

نصائح أخرى

يمكنك استبدال new و delete مع الإصدارات الخاصة بك التي لديها السلوك الذي تريده.

بادئ ذي بدء - ليس في مدير الذاكرة "العادي". بمجرد تعامل الذاكرة ، يمكنك نقل ملكيةها إلى مدير الذاكرة ويمكن أن يعيد استخدامها الأخير.

يمكنك اكتب مديرًا مخصصًا كما المستخدم أندرياس برينك يقترح ، ولكن ماذا ستفعل؟ لا تصنع الذاكرة من الهواء ، فهو يطلبها من مكان مثل كومة CRT أو كومة نظام التشغيل.

السيناريو A. لن يعيد الذاكرة إلى الكومة الأساسية - سيكون لديك تسرب وسيظل كتلة الذاكرة في مساحة العنوان وسيكون متاحًا.

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

خلاصة القول هي أنك مشدود. محاولة اختبار السلوك غير المحدد لن تكون مثمرة للغاية.

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

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