سؤال

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

في C# و Python ، عند حدوث استثناء غير معتمد ، يحصل المستخدم على تتبع مكدس لطيف وبشكل عام مفيد جدا معلومات التصحيح التي لا تقدر بثمن. إذا كنت تعمل على تطبيق OSS ، فإن وجود المستخدمين لصق هذه المعلومات في تقارير المشكلات هو ... حسنًا ، دعنا نقول فقط أنني أجد صعوبة في العيش بدون ذلك. بالنسبة لمشروع C ++ هذا ، أحصل على "تعطل التطبيق" ، أو من المستخدمين الأكثر استنارة ، "لقد فعلت X و Y و Z ، ثم تحطمت". لكني أريد أن تصحيح المعلومات أيضًا!

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

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

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

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

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

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

المحلول

لف كل الكود الخاص بك في واحد try/catch الكتلة هي A-OK. لن يتباطأ تنفيذ أي شيء بداخله ، على سبيل المثال. في الواقع ، جميع برامجي لديها (رمز مشابه) لهذا الإطار:

int execute(int pArgc, char *pArgv[])
{
    // do stuff
}

int main(int pArgc, char *pArgv[])
{
    // maybe setup some debug stuff,
    // like splitting cerr to log.txt

    try
    {
        return execute(pArgc, pArgv);
    }
    catch (const std::exception& e)
    {
        std::cerr << "Unhandled exception:\n" << e.what() << std::endl;
        // or other methods of displaying an error

        return EXIT_FAILURE;
    }
    catch (...)
    {
        std::cerr << "Unknown exception!" << std::endl;

        return EXIT_FAILURE;
    }
}

نصائح أخرى

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

لن يكون استثناء C ++ مفيدًا جدًا أيضًا. الاحتمالات التي يموت البرنامج على استثناء مشتق من STD :: استثناء ضئيلة للغاية. على الرغم من أنه يمكن أن يحدث. من المرجح أن يكون الأمر على الأرجح في تطبيق C/C ++ هو الموت بسبب استثناءات الأجهزة ، حيث يكون AccessViolation numero uno. يتطلب محاصرة هذه الكلمات الرئيسية __try و __except في طريقة () Main (). مرة أخرى ، لا يتوفر سياق قليل جدًا ، بل لديك رمز استثناء فقط. يخبرك AV أيضًا أي موقع ذاكرة دقيق تسبب في الاستثناء.

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

ما عليك القيام به هو تصحيح هذا النوع من المشكلات بطريقة C/C ++. تحتاج إلى إنشاء Minidump. إنه مماثل تقريبًا لـ "تفريغ الأساس" القديم ، وهي لقطة من صورة العملية في الوقت الذي يحدث فيه الاستثناء. في ذلك الوقت ، حصلت بالفعل على تفريغ كامل من النواة. كان هناك تقدم ، في الوقت الحاضر إنه "صغير" ، ضروري إلى حد ما لأن تفريغ الأساس الكامل سيستغرق ما يقرب من 2 جيجابايت. إنه في الواقع يعمل بشكل جيد لتشخيص حالة البرنامج.

على Windows ، يبدأ ذلك عن طريق استدعاء SetUnhandleDexceptionFilter () ، يمكنك تقديم مؤشر وظيفة رد الاتصال إلى وظيفة سيتم تشغيلها عندما يموت البرنامج في استثناء غير معقول. أي استثناء ، C ++ وكذلك SEH. موردك التالي هو dbghelp.dll ، المتاح في أدوات تصحيح الأخطاء لتنزيل Windows. يحتوي على نقطة دخول تسمى MinidUmpritedUmp () ، فإنه يخلق قاطرة مصغرة.

بمجرد أن تحصل على الملف بواسطة MinidUmpriteMump () ، فأنت ذهبيًا جدًا. يمكنك تحميل ملف .dmp في Visual Studio ، مثل مشروعه تقريبًا. اضغط على F5 و VS يطحن بعيدًا لفترة من الوقت في محاولة لتحميل ملفات .pdb لـ DLLs المحملة في العملية. ستحتاج إلى إعداد خادم الرموز ، هذا جداً من المهم الحصول على آثار مكدس جيدة. إذا كان كل شيء يعمل ، فستحصل على "استراحة تصحيح" في الموقع الدقيق الذي تم فيه إلقاء الاستثناء ". مع تتبع المكدس.

الأشياء التي تحتاج إلى القيام بها لجعل هذا العمل بسلاسة:

  • استخدم خادم البناء لإنشاء الثنائيات. يحتاج إلى دفع رموز تصحيح الأخطاء (.PDB) إلى خادم رمز حتى تكون متاحة بسهولة عند تصحيح Minidump.
  • قم بتكوين مصحح الأخطاء حتى يتمكن من العثور على رموز تصحيح الأخطاء لجميع الوحدات النمطية. يمكنك الحصول على رموز تصحيح الأخطاء لنظام التشغيل Windows من Microsoft ، يجب أن تأتي الرموز الخاصة بالرمز الخاص بك من خادم الرمز المذكور أعلاه.
  • اكتب الكود لفخ الاستثناء غير المعدل وإنشاء Minidump. لقد ذكرت SetUnhandleDexceptionFilter () ولكن لا ينبغي أن يكون الرمز الذي ينشئ Minidump في البرنامج الذي تحطمت. الاحتمالات التي يمكن أن تكتب Minidump بنجاح ضئيلة إلى حد ما ، فإن حالة البرنامج غير محددة. أفضل ما يجب فعله هو تشغيل عملية "حراسة" تراقب Mutex المسماة. يمكن لمرشح الاستثناء الخاص بك ضبط Mutex ، يمكن للحارس إنشاء Minidump.
  • قم بإنشاء وسيلة لإجراء نقل Minidump من جهاز العميل إلى عميلك. نستخدم خدمة Amazon S3 لذلك ، terabytes بسعر معقول.
  • قم بتوصيل معالج Minidump إلى قاعدة بيانات التصحيح الخاصة بك. نحن نستخدم JIRA ، ويحتوي على خدمة ويب تتيح لنا التحقق من دلو التصادم مقابل قاعدة بيانات من حوادث الحوادث السابقة مع نفس "التوقيع". عندما تكون فريدة من نوعها ، أو ليس لديها ما يكفي من الزيارات ، نطلب من رمز Manager Crash تحميل Minidump إلى Amazon وإنشاء إدخال قاعدة بيانات الأخطاء.

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

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

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

أقوم بتضمين السجلات ، وإصدار التطبيق ورقم البناء ، ونوع الاستثناء وتفريغ المكدس في Hex المشروح بأسماء الوحدات النمطية وإعدادات قيم السداسي التي يمكن أن تكون عناوين رمز. تأكد من تضمين رقم الإصدار ورقم البناء/تاريخ EXE الخاص بك.

تستطيع ايضا استخذام VirtualQuery لتحويل قيم المكدس إلى "Modulename+Offset" بسهولة تامة. وهذا ، إلى جانب ملف .map غالبًا ما يخبرك بالمكان الذي تحطمت فيه بالضبط.

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

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

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

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