سؤال

هذا غريب جدا بالنسبة لي، لكنني أحصل على خطأ تجزئة غير متوقع وعشوائي عند تشغيل برنامجي. في بعض الأحيان تعمل، في بعض الأحيان تعطل .. يشير مصحح الأخطاء من dev-c ++ إلى خط الملف: stl_constress.h

/**
   * @if maint
   * Constructs an object in existing memory by invoking an allocated
   * object's constructor with an initializer.
   * @endif
   */
  template<typename _T1, typename _T2>
    inline void
    _Construct(_T1* __p, const _T2& __value)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_]allocator::construct
     -> ::new(static_cast<void*>(__p)) _T1(__value);
    }

أنا أستخدم STL على نطاق واسع بالمناسبة .. ماذا علي أن أفعل للكشف عن أصل segfault؟ هل هناك أي أدوات يمكن أن تساعد؟ ما هي الأسباب التي يمكن أن تؤدي إلى تعطل عشوائي مثل هذا.

يحرر:

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

يحرر:

انتقلت إلى Code::Blocks الآن، ها هي مكدس المكالمات:

#0 00464635 std::_Construct<std::pair<double const, int>, std::pair<double const, int> >(__p=0xb543e8, __value=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_construct.h:81)
#1 00462306 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_create_node(this=0x406fe50, __x=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:367)
#2 00461DA7 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_clone_node(this=0x406fe50, __x=0x0) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:379)
#3 004625C6 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_copy(this=0x406fe50, __x=0x0, __p=0x406fe54) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:1029)
#4 00462A9D std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_Rb_tree(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:559)
#5 0045A928 std::map<double, int, std::less<double>, std::allocator<std::pair<double const, int> > >::map(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_map.h:166)
#6 0040B7E2 VehicleManager::get_vehicles_distances(this=0xb59a50) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/VehicleManager.cpp:232)
#7 00407BDA Supervisor::IsMergeInstruction(id_vehicle=1) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:77)
#8 00408430 CheckingInstructionsThread(arg=0x476100) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:264)
#9 00413950 _glfwNewThread@4() (??:??)
#10 75A24911    KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll:??)
#11 00476100    std::__ioinit() (??:??)
#12 0406FFD4    ??() (??:??)
#13 76E5E4B6    ntdll!RtlInitializeNtUserPfn() (C:\Windows\system32\ntdll.dll:??)
#14 00476100    std::__ioinit() (??:??)
#15 70266582    ??() (??:??)
#16 00000000    ??() (??:??)

بعض الاعتمادات:

1 / إنه تطبيق متعدد الخيوط. 2 / الطريقة: get_vehicles_distances ()؛ إرجاع خريطة. 3 / من الممكن أن لا تعثر الخريطة بحلول الوقت الذي يطلق عليه بواسطة ISMergeinstruction ()؛

يحرر:

يبدو أن الخط الذي يسبب segfault هو:

vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

حيث المركبات_distances_ هي الخريطة. هذا الخط هو جزء من الطريقة: vehiclemanager :: moveallvehicles ()؛

void VehicleManager::MoveAllVehicles() {

     vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

     vector<Vehicle>::iterator iter_end = VehicleManager::vehicles_.end();
     for(vector<Vehicle>::iterator iter = VehicleManager::vehicles_.begin();
     iter != iter_end; ++iter) {

          (*iter).MoveVehicle();

          vehicles_distances_[(*iter).get_vec_vehicle_position().y] = (*iter).get_id_vehicle();

     }

}

ما هو الخطأ في ذلك ؟

يحرر:

حاولت استخدام الخريطة :: مسح ()؛ كإعداد لاستبدال الخريطة :: محو ()؛ لكن المشكلة نفسها تحدث!

يحرر:

أعتقد أنني أحصل عليه ... يحاول الخيط الاستفادة من المركبات_Distances_ أثناء مسحها .. (؟)

يحرر:

تم حل المشكلة! لذلك كان قادما من الخريطة :: محو ()؛ كما هو متوقع. تجاوزت المشكلة عن طريق إنشاء متغير خريطة آخر حيث الزوج <key, value> تم قلبه حتى أتمكن من تحديث الخريطة. (نظرا لأن المفتاح الذي أحتاجه هو المسافة، والمسافة ليست فريدة من نوعها لأنها تتغير في كل مرة ولكن iD_Vehicle فريدة من نوعها!). في النهاية أخذت للتو هذه الخريطة، مقلوبة <key, value> مرة أخرى ونقلها إلى الخريطة الأصلية التي يمكن إعادة reedeclared في كل دورة ...

شكرا لكم جميعا !

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

المحلول

أولا، من أجل حب كل ما هو، حسنا، محبوب، لا تستخدم DEV-C ++. وبعد أتمنى لو كنت أعرف كيف يستمر الناس يعملون في تلك القطعة من غير المرغوب فيه. لم يتم الحفاظ عليها سنوات, وحتى عندما يتم الاحتفاظ بها، كان لا يزال قطعة عربات التي تجرها الدواب من غير المرغوب فيه والتي تفتقر إلى وظائف أساسية للغاية. خندقها، وتذهب لأحد بدائل حالية لا تعد ولا تحصى.

الآن، على سؤالك: برنامجك Segfachults عشوائيا لأنك قمت بعمل شيء غير قانوني سابقا. لا تفعل ذلك. ؛)

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

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

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

يحتوي MSVC على خيار SCL آمن ممكن افتراضيا مما سيؤدي إلى التحقق من الحدود على رمز STL، والذي يمكن أن يساعد في اكتشاف الأخطاء مثل هذا.

أعتقد أن GCC لديه خيار للقيام بشيء مماثل (ولكن لم يتم تمكينه بشكل افتراضي).

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

نصائح أخرى

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

السؤال الواضح سيكون "ما هو _p". في المصحح، يجب أن تكون قادرا على إلقاء نظرة على CallStack. اتبع _p مرة أخرى إلى أصلها. تأكد من الحجم الصحيح، أنه لم يتم حذفه، وأنه يحدث في الواقع.

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

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

يمكنك استخدام _CrtSetDbgFlag() في بداية برنامجك لتمكين بعض خيارات تصحيح الذاكرة المؤقتة. أنظر أيضا كومة تصحيح CRT. وبعد قد يساعدك ذلك في تعقب حيث كنت تقوم بأشياء سيئة مع الذاكرة. إنها متوفرة في وقت التشغيل C Microsoft، والتي تقوم بها روابط مترجم MINGW مقابل الافتراضي. إذا كنت بدلا من ذلك باستخدام وقت تشغيل G جنو، فلن تتمكن من الذهاب إلى هذا الطريق.

المشكلة أكثر عرضة بكثير في الكود الخاص بك من STL_Constress.h. أفترض أن الملف هو جزء من توزيع STL ل DEV-C ++. قد يحدث خطأ التجزئة في التعليمات البرمجية التي تم إنشاء مثيل لها باستخدام القوالب في stl_Constress.h، ولكن السبب الجذري للمشكلة سيكون في مكان آخر. سأحاول حل هذا عن طريق الحصول على تتبع المكدس في وقت التعطل. لكل وظيفة في تتبع المكدس (خاصة تلك التي كتبت حديثا)، حاول فحص التعليمات البرمجية والبحث عن الأنواع التالية من الأخطاء المحتملة:

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

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

على سبيل المثال، قد يكون برنامجك كائن foo هذا يعتمد على الكائن bar; ؛ ولكن قد يكون البرنامج يدعو المنشئ foo قبل أن يبني bar. وبعد سيكون ذلك سيئا، ويمكن أن يسبب نوع المشكلة التي تصفها. (يكون CheckingInstructionsThread متغير ثابت يفلت موضوعا؟ يمكن أن تكون المشكلة هناك.)

لإصلاح هذا، قد تحتاج إلى إلقاء نظرة على ملفات .cpp للبرنامج الخاص بك للمتغيرات الثابتة (بما في ذلك الفصلية الفئة والكبراءات)، وخاصة تلك التي هي من نوع من الفئة. قد يساعد أو لا تساعد في تعديل منشئيك لكتابة بعض الآثار إلى Stderr؛ استعمال fprintf بدلا من cerr إذا فعلت ذلك.

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

 fprintf(stderr, "main() entered\n");

هذا لن يستبعد التهيئة الثابتة كسبب للمشكلة؛ حتى لو لم يكن يصطدم قبل main(), ، لا يزال بإمكانك إعداد هياكل البيانات بشكل غير صحيح. ولكن، إذا لم تصل إلى FPRINTF، فأنت أعرف هذا التهيئة الثابتة هو السبب.

ماذا تخبرك تتبع المكدس بعد تشغيل المصحح مع الملف الأساسي؟ تشغيل GDB الطريقة العادية GDB A.OUT

ثم فحص الملف الأساسي

الأساسية A.COUT.CORE.

وإلقاء نظرة على المكدس

بات

من المحتمل أن يكون هذا على الأرجح بمكرر Inlastated - ابحث عن الأماكن التي تقوم فيها بتكرار الحاويات و / أو الحفاظ على المحفوظات في حاويات وإزالة / إدراج عناصر في نفس الوقت.
وكما لاحظ الجميع - استخدم كومة استدعاء للعثور على المكان المحدد.

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

في مكدسة المكشوف، فإن أهم موقع للمشكلة هو في التعليمات البرمجية (المتصل) والمعلمات التي مرت بها إلى الوظيفة التي اتصلت بها (الكالي).

بدون هذه المعلومات، لا يمكننا مساعدتك أكثر. ؛-)

المزيد حول أخطاء تجزئة: http://en.wikipedia.org/wiki/segalation_fault.
(يجب أن تقرأ، انظر أيضا الروابط في "انظر أيضا" و "الروابط الخارجية")

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

يبدو وكأنه وظيفة خطيرة :)

شيء واحد ضربة لي رغم ذلك. أين تذهب الذاكرة المخصصة؟ أود بشكل حدسي أن يكون لديك مؤشر إلى مؤشر كحجة أولا ثم إلغاء الأمر. مثله:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1** __p, const _T2& __value)
    {

       ::new(static_cast<void*>(*__p)) _T1(__value);
    }

بدلا من ذلك، إشارة إلى مؤشر:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1*& __p, const _T2& __value)
    {

       ::new(static_cast<void*>(__p)) _T1(__value);
    }

يجب أن يتيح لك المصحح صعود مكدس المكالمات. بهذه الطريقة يجب أن تكون قادرا على رؤية المكان في التعليمات البرمجية الخاصة بك والتي تسبب خطأ SEG.

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