هذا هو الأمر perlhacktips الذي يمكن تشغيله في مزود الاستضافة المجانية OnWorks باستخدام إحدى محطات العمل المجانية المتعددة على الإنترنت مثل Ubuntu Online أو Fedora Online أو محاكي Windows عبر الإنترنت أو محاكي MAC OS عبر الإنترنت
برنامج:
اسم
perlhacktips - نصائح لاختراق كود Perl core C
الوصف
سيساعدك هذا المستند على تعلم أفضل طريقة لاختراق لغة Perl core C
شفرة. ويغطي المشكلات الشائعة وتصحيح الأخطاء والتوصيف والمزيد.
إذا لم تكن قد قرأت Perlhack وperlhacktut بعد، فقد ترغب في القيام بذلك أولاً.
COMMON مشاكل
يتم تشغيل مصدر Perl وفقًا لقواعد ANSI C89: لا توجد امتدادات C99 (أو C++). في بعض الحالات علينا أن نفعل ذلك
خذ متطلبات ما قبل ANSI بعين الاعتبار. أنت لا تهتم ببعض معينة
منصة بعد كسر بيرل؟ سمعت أنه لا يزال هناك طلب قوي على مبرمجي J2EE.
بيرل بيئة مشاكل
· لا يتراكم مع الخيوط
يؤدي التجميع باستخدام خيوط (-Duseithreads) إلى إعادة كتابة نماذج الوظائف بالكامل
من بيرل. من الأفضل أن تجرب تغييراتك مع ذلك. ويتعلق بهذا الفرق
بين واجهات برمجة تطبيقات "Perl_-less" و "Perl_-ly" ، على سبيل المثال:
Perl_sv_setiv (aTHX_ ...) ؛
sv_setiv (...) ؛
الأول يمر بشكل صريح في السياق، وهو أمر ضروري على سبيل المثال
يبني. الثاني يفعل ذلك ضمنيًا ؛ لا تختلط عليهم. إذا لم تكن
مرورًا بـ aTHX_، ستحتاج إلى إجراء dTHX (أو dVAR) كأول شيء في
وظيفة.
راجع "كيف يتم دعم العديد من المترجمين الفوريين والتزامن" في perlguts لمزيد من المعلومات
مناقشة حول السياق.
· عدم تجميع مع -DEBUGGING
يعرض تعريف التصحيح المزيد من التعليمات البرمجية للمترجم، وبالتالي المزيد من الطرق للأشياء
ان يحدث خطأ. عليك بتجريبه.
· تقديم (غير للقراءة فقط) globals
لا تقدم أي عالميات قابلة للتعديل، عمومية حقًا أو ملف ثابت. إنهم سيئون
تشكيل وتعقيد تعدد مؤشرات الترابط وأشكال أخرى من التزامن. الطريق الصحيح
لتقديمها كمتغيرات جديدة للمترجم ، انظر انتربفار (في النهاية ل
التوافق الثنائي).
لا بأس في تقديم globals للقراءة فقط (const) ، طالما أنك تتحقق باستخدام مثل "نانومتر"
libperl.a | egrep -v '[TURtr]' "(إذا كان" nm "الخاص بك يحتوي على إخراج بنمط BSD) أن البيانات التي
وأضاف حقا للقراءة فقط. (إذا كان الأمر كذلك، فلا ينبغي أن يظهر في مخرجات ذلك
أمر.)
إذا كنت تريد أن يكون لديك سلاسل ثابتة، فاجعلها ثابتة:
static const char etc[] = "...";
إذا كنت ترغب في الحصول على مصفوفات من السلاسل الثابتة، فلاحظ بعناية التركيبة الصحيحة
من "الثابت":
ثابت const char * const yippee[] =
{"hi"، "ho"، "silver"}؛
هناك طريقة لإخفاء أي عوالم قابلة للتعديل تمامًا (يتم نقلها جميعًا إلى الكومة)،
إعداد الترجمة "-DPERL_GLOBAL_STRUCT_PRIVATE". لا يتم استخدامه عادة، ولكن
يمكن استخدامها للاختبار ، اقرأ المزيد عنها في "الخلفية و PERL_IMPLICIT_CONTEXT"
في بيرلجوتس.
· عدم تصدير وظيفتك الجديدة
تتطلب بعض الأنظمة الأساسية (Win32، وAIX، وVMS، وOS/2، على سبيل المثال لا الحصر) أي وظيفة متاحة.
جزء من API العامة (مكتبة Perl المشتركة) ليتم تعليمها صراحة على أنها مُصدرة.
انظر المناقشة حول تضمين.pl في بيرلجوتس.
· تصدير وظيفتك الجديدة
النتيجة اللامعة الجديدة إما للوظيفة الجديدة الحقيقية أو لإعادة البناء الشاقة
أصبح الآن جاهزًا وتم تصديره بشكل صحيح. فما الذي يمكن أن يحدث خطأ؟
ربما ببساطة لم تكن وظيفتك بحاجة إلى أن يتم تصديرها في المقام الأول. بيرل
لها تاريخ طويل وغير مجيد في تصدير الوظائف التي لا ينبغي لها أن تمتلكها.
إذا تم استخدام الوظيفة داخل ملف شفرة مصدر واحد فقط ، فاجعلها ثابتة. انظر
مناقشة حول تضمين.pl في بيرلجوتس.
إذا تم استخدام الوظيفة عبر عدة ملفات ، ولكنها مخصصة فقط للغة Perl الداخلية
استخدم (ويجب أن تكون هذه هي الحالة الشائعة)، فلا تقم بتصديره إلى واجهة برمجة التطبيقات العامة. انظر
مناقشة حول تضمين.pl في بيرلجوتس.
قابلية النقل مشاكل
فيما يلي الأسباب الشائعة لفشل الترجمة و/أو التنفيذ، وهي غير شائعة
بيرل على هذا النحو. الأسئلة الشائعة حول C هي قراءة جيدة قبل النوم. يرجى اختبار التغييرات الخاصة بك مع أكبر عدد ممكن من C
المجمعين والمنصات قدر الإمكان ؛ سنقوم ، على أي حال ، ومن الجيد أن ينقذ المرء نفسه من
الإحراج العام.
إذا كنت تستخدم gcc، فيمكنك إضافة الخيار "-std=c89" والذي نأمل أن يلتقط معظم هذه الخيارات
عدم القدرة على النقل. (ومع ذلك، فقد يؤدي ذلك أيضًا إلى اكتشاف حالات عدم توافق في رأس نظامك
الملفات.)
استخدم علامة تكوين "-Dgccansipedantic" لتمكين إشارات gcc "-ansi -pedantic" التي
فرض قواعد أكثر صرامة من ANSI.
في حالة استخدام "gcc -Wall" لاحظ أنه ليست كل التحذيرات المحتملة (مثل "-Wunitialized")
يتم إعطاؤها ما لم تقم أيضًا بالتجميع باستخدام "-O".
لاحظ أنه في حالة استخدام gcc ، بدءًا من Perl 5.9.5 ، فإن ملفات شفرة مصدر Perl الأساسية (تلك
في المستوى الأعلى لتوزيع التعليمات البرمجية المصدر، ولكن ليس على سبيل المثال الامتدادات ضمن ext/)
يتم تجميعها تلقائيًا مع أكبر عدد ممكن من "-std=c89"، "-ansi"،
"-pedantic"، ومجموعة مختارة من أعلام "-W" (انظر cflags.SH).
قم أيضًا بدراسة perlport بعناية لتجنب أي افتراضات سيئة حول نظام التشغيل،
أنظمة الملفات ومجموعة الأحرف وما إلى ذلك.
يمكنك من حين لآخر تجربة "إنشاء microperl" لمعرفة ما إذا كان لا يزال بإمكاننا تجميع لغة Perl
مع الحد الأدنى من الواجهات. (راجع الملف README.micro.)
لا تفترض أن نظام التشغيل يشير إلى مترجم معين.
· صب المؤشرات على الأعداد الصحيحة أو صب الأعداد الصحيحة على المؤشرات
المنبوذ باطلة (U8 * ع)
{
الرابع ط = ع؛
or
المنبوذ باطلة (U8 * ع)
{
الرابع أنا = (IV) ص ؛
كلاهما سيء، ومكسور، وغير قابل للنقل. استخدم ال PTR2IV() الماكرو الذي يفعل ذلك بشكل صحيح.
(وبالمثل ، هناك PTR2UV(), PTR2NV(), INT2PTR ()و NUM2PTR ().)
· الصب بين مؤشرات الدالة ومؤشرات البيانات
من الناحية الفنية، يعد الاختيار بين مؤشرات الوظائف ومؤشرات البيانات أمرًا غير قابل للنقل
وغير محدد، ولكن من الناحية العملية يبدو أنه يعمل، ولكن يجب عليك استخدام
FPTR2DPTR () و DPTR2FPTR () وحدات الماكرو. في بعض الأحيان يمكنك أيضًا ممارسة الألعاب مع النقابات.
· بافتراض sizeof(int) == sizeof(long)
هناك منصات حيث يبلغ طولها 64 بتًا ، ومنصات حيث تكون ints 64 بت و
بينما نحن في الخارج لصدمك ، حتى المنصات التي يكون فيها السراويل القصيرة 64 بت. هذا كل شيء
قانوني وفقًا لمعيار C. (وبعبارة أخرى، "طويل طويل" ليس وسيلة محمولة
لتحديد 64 بت ، و "long long" ليس مضمونًا حتى أن يكون أعرض من
"طويل".)
بدلاً من ذلك، استخدم التعريفات IV وUV وIVSIZE وI32SIZE وما إلى ذلك. تجنب أشياء مثل
I32 لأنهم كذلك ليست مضمون أن يكون بالضبط 32 بت ، هم at الأقل 32 بت
ولا هي مضمونة مادبا or التداول الطويل. إذا كنت حقا بحاجة صراحة إلى 64 بت
المتغيرات، استخدم I64 وU64، ولكن فقط إذا كانت محمية بواسطة HAS_QUAD.
· بافتراض أنه يمكن للمرء إلغاء الإشارة إلى أي نوع من المؤشرات لأي نوع من البيانات
شار * ع = ...;
المهر الطويل = * p ؛ /* سيء */
ستمنحك العديد من المنصات، بحق، تفريغًا أساسيًا بدلاً من المهر إذا كان p
يحدث عدم محاذاة بشكل صحيح.
يلقي Lvalue
(int)*p = ...; /* سيء */
ببساطة غير محمولة. اجعل القيمة الخاصة بك من النوع الصحيح، أو ربما استخدمها بشكل مؤقت
المتغيرات ، أو الحيل القذرة مع النقابات.
· يفترض اى شى حول البنيات (خاصة تلك التي لا تتحكم فيها، مثل تلك
قادمة من رؤوس النظام)
· وجود حقل معين في البنية
· عدم وجود مجالات أخرى غير تلك التي تعرفها
· أن يكون الحقل ذو توقيع أو حجم أو نوع معين
· أن تكون الحقول بترتيب معين
· بينما تضمن لغة C الترتيب المحدد في تعريف البنية،
بين منصات مختلفة قد تختلف التعريفات
· أن حجم (البنية) أو المحاذاة هي نفسها في كل مكان
· قد تكون هناك بايتات حشوة بين الحقول لمحاذاة الحقول -
يمكن أن تكون البايتات أي شيء
· يجب أن تتم محاذاة الهياكل إلى الحد الأقصى المطلوب من المحاذاة
حسب الحقول - والتي بالنسبة للأنواع الأصلية تعادل عادةً
sizeof () من الميدان
بافتراض أن مجموعة الأحرف هي ASCIIish
يمكن لـ Perl التجميع والتشغيل ضمن منصات EBCDIC. انظر بيرليبكديك. هذا شفاف
بالنسبة للجزء الأكبر، ولكن نظرًا لاختلاف مجموعات الأحرف، يجب ألا تستخدم الأرقام
(عشري ، ثماني ، ولا عشري) للإشارة إلى الأحرف. يمكنك أن تقول "أ" بأمان ،
ولكن ليس 0x41. يمكنك أن تقول "\ n" بأمان ، لكن ليس "\ 012". ومع ذلك ، يمكنك استخدام وحدات الماكرو
المعرفة في utf8.h لتحديد أي نقطة رمز يمكن نقلها. "LATIN1_TO_NATIVE(0xDF) "هو
ستكون نقطة الرمز التي تعني LATIN SMALL LETTER SHARP S على أي منصة
الذي تعمل عليه (على منصات ASCII يتم تجميعه دون إضافة أي كود إضافي، لذلك
هناك صفر أداء ضرب على هؤلاء). المدخلات المقبولة لـ "LATIN1_TO_NATIVE"
هي من 0x00 إلى 0xFF. إذا لم يكن من المضمون أن تكون مدخلاتك في هذا النطاق، فاستخدم
"UNICODE_TO_NATIVE" بدلاً من ذلك. "NATIVE_TO_LATIN1" و"NATIVE_TO_UNICODE" يترجمان
الاتجاه المعاكس.
إذا كنت بحاجة إلى تمثيل سلسلة أحرف ليس لها اسم ذاكري
في C، يجب عليك إضافته إلى القائمة في regen/unicode_constants.pl، ولديك لغة Perl
قم بإنشاء "#define" لك، بناءً على النظام الأساسي الحالي.
لاحظ أن "هوفو" و لفو" وحدات الماكرو بتنسيق مفيد. ح تعمل بشكل صحيح على الكود الأصلي
النقاط والسلاسل.
أيضًا ، النطاق "A" - "Z" في ASCII هو تسلسل غير منقطع من 26 حالة أبجدية كبيرة
الشخصيات. هذا ليس صحيحا في EBCDIC. ولا من "أ" إلى "ض". لكن "0" - "9" هو
نطاق غير منقطع في كلا النظامين. لا تفترض أي شيء عن النطاقات الأخرى. (لاحظ أن
المعالجة الخاصة للنطاقات في أنماط التعبير العادي تجعلها تظهر لكود Perl
أن النطاقات المذكورة أعلاه كلها غير منقطعة.)
تتجاهل العديد من التعليقات الموجودة في الكود الحالي إمكانية EBCDIC، وربما تكون كذلك
لذا، فهو خاطئ، حتى لو كان الكود يعمل. وهذا في الواقع تكريم للناجحين
إدراج شفاف للقدرة على التعامل مع EBCDIC دون الحاجة إلى تغيير ما قبل
الكود الموجود.
UTF-8 و UTF-EBCDIC هما ترميزات مختلفة تستخدم لتمثيل نقاط رمز Unicode
كتسلسل بايت. وحدات الماكرو بنفس الأسماء (لكن بتعريفات مختلفة) بتنسيق
utf8.h و utfebcdic.h تُستخدم للسماح لرمز الاستدعاء بالاعتقاد بأنه يوجد فقط
واحد من هذا القبيل الترميز. يُشار إلى هذا دائمًا باسم "utf8" ، ولكنه يعني
نسخة EBCDIC كذلك. مرة أخرى، قد تكون التعليقات الموجودة في الكود خاطئة حتى لو كان
الكود نفسه صحيح. على سبيل المثال ، مفهوم UTF-8 "الأحرف الثابتة"
يختلف بين ASCII وEBCDIC. على منصات ASCII، فقط الأحرف التي لا تفعل ذلك
تحتوي على مجموعة بتات عالية الترتيب (أي ترتيباتها صارمة ASCII، من 0 إلى 127)
ثابت، وقد تفترض الوثائق والتعليقات الموجودة في الكود ذلك في كثير من الأحيان
في إشارة إلى شيء مثل ، على سبيل المثال ، "hibit". الوضع يختلف وليس بهذه البساطة
على أجهزة EBCDIC ، ولكن طالما أن الشفرة نفسها تستخدم "NATIVE_IS_INVARIANT ()"
الماكرو بشكل مناسب ، فهو يعمل ، حتى لو كانت التعليقات خاطئة.
كما هو مذكور في "TESTING" في perlhack، عند كتابة البرامج النصية للاختبار، يتم حفظ الملف
ر / charset_tools.pl يحتوي على بعض الوظائف المفيدة لكتابة الاختبارات الصالحة لكليهما
منصات ASCII وEBCDIC. في بعض الأحيان، على الرغم من ذلك، لا يمكن للاختبار استخدام وظيفة وهي كذلك
من غير الملائم أن يكون لديك إصدارات اختبارية مختلفة اعتمادًا على النظام الأساسي. يوجد 20
نقاط الشفرة هي نفسها في جميع مجموعات الأحرف الأربعة التي تتعرف عليها Perl حاليًا
(صفحات رموز EBCDIC الثلاث بالإضافة إلى ISO 3-8859 (ASCII/Latin1)). هذه يمكن استخدامها في مثل هذا
الاختبارات، على الرغم من أن هناك احتمالًا ضئيلًا بأن تصبح لغة Perl متاحة بعد
مجموعة شخصيات أخرى ، كسر الاختبار الخاص بك. جميع نقاط الرمز هذه باستثناء واحدة هي C0
شخصيات التحكم. أهم عناصر التحكم المتشابهة هي "\0"، "\r"،
و"\N{VT}" (يمكن تحديده أيضًا باسم "\cK" أو "\x0B" أو "\N{U+0B}" أو "\013"). الاوحد
عدم التحكم هو U+00B6 PILCROW SIGN. عناصر التحكم التي هي نفسها لها نفس الشيء
النمط في جميع مجموعات الأحرف الأربعة ، بغض النظر عن UTF4ness للسلسلة التي تحتوي على
هم. نمط البت لـ U+B6 هو نفسه في جميع السلاسل الأربعة للسلاسل غير UTF4، ولكنه يختلف
في كل منها عندما تكون السلسلة التي تحتوي عليها بترميز UTF-8. الرمز الوحيد الآخر يشير إلى ذلك
لديك نوع من التشابه عبر جميع مجموعات الأحرف الأربعة هي الزوج 4xDC و 0xFC.
يمثل هذان معًا الأحرف الكبيرة والصغيرة LATIN LETTER U WITH DIAERESIS ، ولكن أيهما
يمكن عكس الجزء العلوي وأيهما أقل: 0xDC هو رأس المال في Latin1 و0xFC هو
الحرف الصغير، في حين أن 0xFC هو رأس المال في EBCDIC و0xDC هو الحرف الصغير. هذا
يمكن استغلال factoid في كتابة اختبارات غير حساسة لحالة الأحرف متشابهة في العرض
جميع مجموعات الأحرف الأربعة.
· بافتراض أن مجموعة الأحرف هي مجرد ASCII
ASCII هو ترميز 7 بت ، لكن البايت بها 8 بتات. 128 حرفًا إضافيًا
لها معاني مختلفة اعتمادًا على اللغة. لا توجد لغة ، هذه حاليا
تعتبر الأحرف الإضافية بشكل عام غير مخصصة، وقد تم تقديم ذلك
بعض المشاكل. تم تغيير هذا بدءًا من 5.12 حتى تتمكن هذه الأحرف من ذلك
تعتبر لاتينية-1 (ISO-8859-1).
· خلط #define و #ifdef
#define BURGLE (x) ... \
#ifdef BURGLE_OLD_STYLE / * BAD * /
... افعلها بالطريقة القديمة ... \
#else
... افعلها بالطريقة الجديدة ... \
#endif
لا يمكنك "تكديس" توجيهات cpp بشكل محمول. على سبيل المثال في ما سبق تحتاج إلى اثنين
مستقل سطا() #تعريف واحد لكل فرع #ifdef.
· إضافة مواد بدون تعليق بعد #endif أو # else
#ifdef سنوش
# آخر! SNOSH / * BAD * /
#endif SNOSH / * BAD * /
#endif و # else لا يمكن نقل أي شيء بعدهما بدون تعليق. اذا أنت
تريد توثيق ما يجري (وهي فكرة جيدة خاصة إذا كانت الفروع كذلك
طويل)، استخدم التعليقات (C):
#ifdef سنوش
#آخر /* !سنوش */
#endif / * SNOSH * /
يحذر خيار gcc "-Wendif-labels" من المتغير السيئ (افتراضيًا عند البدء
من بيرل 5.9.4).
· وجود فاصلة بعد العنصر الأخير في قائمة التعداد
تعداد اللون {
سيروليان ،
شارتروز,
سينابار ، / * BAD * /
};
غير محمول. اترك الفاصلة الأخيرة.
لاحظ أيضًا أن ما إذا كانت التعدادات قابلة للتحويل ضمنيًا إلى ints تختلف بين
المترجمين، قد تحتاج إلى (كثافة العمليات).
· استخدام //-التعليقات
// هذه الوظيفة تفسد الزوركلاتور. /* سيء */
هذا هو C99 أو C ++. قيمة Perl هي C89. استخدام التعليقات // - يسمح بصمت من قبل العديد من C
المترجمين ولكن رفع صرامة ANSI C89 (وهو ما نحب القيام به) يسبب
تجميع للفشل.
· خلط الإعلانات والرمز
zorklator باطل ()
{
كثافة العمليات ن = 3 ؛
set_zorkmids (ن) ؛ /* سيء */
كثافة العمليات ف = 4 ؛
هذا هو C99 أو C ++. تسمح بعض برامج التحويل البرمجي للغة C بذلك، لكن لا ينبغي لك ذلك.
يقوم خيار gcc "-Wdeclaration-after-statements" بالبحث عن مثل هذه المشكلات (بشكل افتراضي
بدءًا من Perl 5.9.4).
· إدخال المتغيرات بالداخل ل()
لـ (int i = ... ؛ ... ؛ ...) {/ * BAD * /
هذا هو C99 أو C++. في حين أنه سيكون أمرًا رائعًا حقًا أن يكون لدينا ذلك أيضًا في C89،
للحد من نطاق متغير الحلقة، للأسف، لا نستطيع ذلك.
· خلط مؤشرات char الموقعة مع مؤشرات char غير الموقعة
int foo (char * s) {...}
غير موقعة char *t = ...; /* أو U8* t = ... */
قدم)؛ /* سيء */
على الرغم من أن هذه ممارسة قانونية، إلا أنها بالتأكيد مشكوك فيها وقاتلة تمامًا على الأقل
منصة واحدة: على سبيل المثال يعتبر VMS cc هذا خطأ فادحًا. سبب واحد للناس
غالبًا ما يرتكب هذا الخطأ "حرفًا عاريًا" وبالتالي يتم إلغاء الإشارة إلى "عارية
"مؤشر char" له توقيع غير محدد: فهو يعتمد على المترجم والأعلام
للمترجم والمنصة الأساسية سواء كانت النتيجة موقعة أو غير موقعة.
لهذا السبب نفسه يعد استخدام "char" كمؤشر مصفوفة أمرًا سيئًا.
· وحدات الماكرو التي تحتوي على ثوابت السلسلة وحججها كسلاسل فرعية للسلسلة
ثابت
#define FOO(n) printf("number = %d\n", n) /* BAD */
فو(10)
كانت دلالات ما قبل ANSI لذلك ما يعادل
printf ("10 عدد =٪ d \ 10") ؛
وهو على الأرجح ليس ما كنت تتوقعه. لسوء الحظ على الأقل واحد معقول
مترجم C الشائع والحديث يفعل "التوافق الحقيقي مع الإصدارات السابقة" هنا ، في AIX
ما الذي لا يزال يحدث على الرغم من أن بقية مترجم AIX هو C89 بسعادة كبيرة.
· استخدام تنسيقات printf لأنواع C غير الأساسية
الرابع أنا = ... ؛
printf("i = %d\n", i); /* سيء */
على الرغم من أن هذا قد يعمل عن طريق الصدفة في بعض الأنظمة الأساسية (حيث يكون IV هو "int")،
بشكل عام لا يمكن. قد يكون الرابع شيئًا أكبر. أسوأ الوضع مع
أنواع أكثر تحديدًا (يتم تحديدها بواسطة خطوة تكوين Perl في التكوين.ح):
Uid_t who = ... ؛
printf("who = %d\n"، who); /* سيء */
تكمن المشكلة هنا في أن Uid_t قد لا يكون فقط على مستوى "int" ولكن قد يكون كذلك
بدون إشارة ، وفي هذه الحالة ستتم طباعة المعرفات الكبيرة كقيم سالبة.
لا يوجد حل بسيط لهذا السبب printf ()ذكاء محدود ، ولكن
بالنسبة للعديد من الأنواع، يتوفر التنسيق الصحيح كما هو الحال مع اللاحقة "f" أو "_f".
مثال:
IVdf / * IV في النظام العشري * /
UVxf / * UV هو رقم سداسي عشري * /
printf("i = %"IVdf"\n", i); /* IVdf هو ثابت سلسلة. * /
Uid_t_f / * Uid_t في النظام العشري * /
printf ("who =٪" Uid_t_f "\ n"، who) ؛
أو يمكنك محاولة الإرسال إلى نوع "واسع بما فيه الكفاية":
printf ("i =٪" IVdf "\ n"، (IV) something_very_small_and_signed) ؛
تذكر أيضًا أن تنسيق %p يتطلب بالفعل مؤشرًا فارغًا:
U8 * p = ... ؛
printf("p = %p\n", (void*)p);
يقوم خيار gcc "-Wformat" بالبحث عن مثل هذه المشكلات.
أعمى استخدام وحدات الماكرو المتغيرة
قامت دول مجلس التعاون الخليجي بتزويدها بصيغة خاصة بها ، وقد جلبتها C99 بامتداد
بناء الجملة موحد. لا تستخدم الأول، واستخدم الأخير فقط إذا كان
تم تعريف HAS_C99_VARIADIC_MACROS.
تمرير أعمى va_list
لا تدعم جميع الأنظمة الأساسية تمرير va_list إلى وظائف varargs (stdarg) الإضافية. ال
الشيء الصحيح الذي يجب فعله هو نسخ va_list باستخدام ملف بيرل_va_copy() إذا كان NEED_VA_COPY
يتم تعريف.
· استخدام عبارات البيان الخليجية
val = ({... ؛ ... ؛ ...}) ؛ /* سيء */
على الرغم من أنه امتداد لطيف، إلا أنه ليس محمولاً. من المسلم به أن رمز Perl يستخدمها إذا
متاح لاكتساب بعض السرعة الإضافية (أساسًا كشكل غير تقليدي من التضمين)، لكنك
لا ينبغي.
· ربط عدة عبارات معًا في ماكرو
استخدم وحدات الماكرو STMT_START وSTMT_END.
STMT_START {
} STMT_END
· اختبار أنظمة التشغيل أو الإصدارات عندما ينبغي اختبار الميزات
#ifdef __FOONIX__ /* سيء */
foo = quux();
#endif
إلا إذا كنت تعرف ذلك بيقين 100٪ Quux() متاح فقط لـ
نظام التشغيل "Foonix" و هذا متاح و تعمل بشكل صحيح ل الكل الماضي،
حاضر، و الإصدارات المستقبلية من "Foonix"، ما ورد أعلاه خاطئ جدًا. هذا أكثر
صحيح (على الرغم من أنه لا يزال غير مثالي، لأن ما يلي هو فحص وقت الترجمة):
#ifdef HAS_QUUX
foo = quux();
#endif
كيف يتم تعريف HAS_QUUX حيث يجب أن يكون؟ حسنًا، إذا حدث ذلك مع Foonix
أن يكون Unixy بما يكفي ليكون قادرًا على تشغيل نص التكوين ، وقد تم تعليم التكوين
حول الكشف والاختبار Quux()سيتم تعريف HAS_QUUX بشكل صحيح. في أخرى
الأنظمة الأساسية ، نأمل أن تفعل خطوة التكوين المقابلة نفس الشيء.
في السؤال ، إذا كنت لا تستطيع الانتظار حتى يتم تعليم التكوين ، أو إذا كان لديك الخير
حدس من أين Quux() قد تكون متاحة، يمكنك تجربة ما يلي مؤقتًا:
#if (المعرفة (__ FOONIX__) || المعرفة (__ BARNIX__))
# حدد HAS_QUUX
#endif
#ifdef HAS_QUUX
foo = quux();
#endif
ولكن على أية حال، حاول إبقاء الميزات وأنظمة التشغيل منفصلة.
· بافتراض محتويات الذاكرة الثابتة التي تشير إليها القيم المرجعة لبيرل
لا تتغير أغلفة وظائف مكتبة C. تعود العديد من وظائف مكتبة C
مؤشرات التخزين الثابت التي يمكن استبدالها بالمكالمات اللاحقة لنفس أو
الوظائف ذات الصلة. تمتلك لغة Perl أغلفة خفيفة الوزن لبعض هذه الوظائف
والتي لا تقوم بعمل نسخ من الذاكرة الثابتة. وخير مثال على ذلك هو واجهة
متغيرات البيئة السارية للبرنامج. يوجد في Perl "PerlEnv_getenv"
للحصول على قيم من البيئة. لكن العودة مؤشر على ذاكرة ثابتة في
مكتبة سي. إذا كنت تستخدم القيمة لاختبار شيء ما على الفور، فهذا
حسنًا، ولكن إذا قمت بحفظ القيمة وتوقعت ألا تتغير من خلال المعالجة اللاحقة، فلن تتمكن من ذلك
سيكون من الخطأ ، لكن ربما لن تعرف ذلك بسبب اختلاف مكتبة سي
تتصرف التطبيقات بشكل مختلف ، وتلك الموجودة على النظام الأساسي الذي تختبر عليه
قد تعمل من أجل وضعك. ولكن على بعض المنصات ، دعوة لاحقة إلى
ستقوم "PerlEnv_getenv" أو الوظيفة ذات الصلة بالكتابة فوق الذاكرة التي استدعتها لأول مرة
نقاط ل. وقد أدى ذلك إلى بعض المشكلات التي يصعب تصحيحها. قم بعمل "savepv" في perlapi
عمل نسخة ، وبالتالي تجنب هذه المشاكل. سيكون عليك تحرير النسخة عندما تكون كذلك
يتم ذلك لتجنب تسرب الذاكرة. إذا لم يكن لديك القدرة على التحكم في وقت تحريره، فسوف تتمكن من ذلك
بحاجة إلى عمل نسخة بأعداد بشرية مميتة ، مثل:
إذا ((s = PerlEnv_getenv("foo") == NULL) {
... / * التعامل مع حالة NULL * /
}
آخر {
s = SvPVX(sv_2mortal(newSVpv(s, 0)));
}
المثال أعلاه يعمل فقط إذا كانت "s" منتهية بـ "NUL"؛ وإلا عليك أن تمر
طوله إلى "newSVpv".
إشكالية واجهات
· malloc(0) إعادة تخصيص(0)، calloc(0, 0) غير محمولة. لتكون المحمولة تخصيص في
بايت واحد على الأقل. (بشكل عام، نادرًا ما تحتاج إلى العمل بهذا المستوى المنخفض، ولكن
بدلاً من ذلك استخدم أغلفة malloc المتنوعة.)
· snprintf () - نوع الإرجاع غير قابل للنقل. يستخدم my_snprintf () بدلا من ذلك.
الأمن مشاكل
وأخيرًا وليس آخرًا، إليك نصائح متنوعة للبرمجة بشكل أكثر أمانًا. انظر أيضًا بيرلكليب لـ
يجب استخدام بدائل libc/stdio.
· لا تستخدم يحصل على()
وإلا فإننا سوف نسخر منك علنا. بجد.
· لا تستخدم tmpfile ()
استعمل mkstemp () بدلا من ذلك.
· لا تستخدم ستركبي () or سترات () or strncpy () or سترنكات()
استعمل my_strlcpy () و my_strlcat() بدلاً من ذلك: إما يستخدمون التنفيذ المحلي ،
أو تطبيق Perl الخاص (مستعار من التطبيق العام لـ INN).
· لا تستخدم سبرينتف () or vsprintf ()
إذا كنت تريد حقًا سلاسل بايت عادية فقط ، فاستخدم my_snprintf () و my_vsnprintf ()
بدلاً من ذلك ، والذي سيحاول استخدامه snprintf () و vsnprintf () إذا كانت واجهات برمجة التطبيقات أكثر أمانًا
متاح. إذا كنت تريد شيئًا أفضل من سلسلة بايت عادية ، فاستخدم "Perl_form" ()
أو SVs و"Perl_sv_catpvf()".
لاحظ أن glibc "printf()" و"sprintf()" وما إلى ذلك هي عربات التي تجرها الدواب قبل الإصدار glibc 2.17.
لن يسمحوا بتنسيق "٪ .s" بدقة لإنشاء سلسلة غير صالحة
UTF-8 إذا كانت اللغة الأساسية الحالية للبرنامج هي UTF-8. ما يحدث هو أن
يتم ببساطة تخطي %s ومعامله دون أي إشعار.
.
· لا تستخدم أتوي ()
استعمل grok_atoUV() بدلا من ذلك. أتوي () لديه سلوك غير محدد على التجاوزات، ولا يمكن أن يكون
تستخدم للتحليل التزايدي. كما أنها تتأثر باللغة، وهو أمر سيء.
· لا تستخدم سترتول () or سترتول()
استعمل grok_atoUV() بدلا من ذلك. سترتول () or سترتول() (أو ماكروها الرابع / الصديق للأشعة فوق البنفسجية
تنكر, سترتول () و سترتول() أو أتول() و أتول () تتأثر بالإعدادات المحلية ، والتي
سيء.
تفكيك
يمكنك تجميع إصدار تصحيح أخطاء خاص من Perl ، والذي يسمح لك باستخدام "-D"
خيار Perl لإخبار المزيد عن ما تفعله Perl. لكن في بعض الأحيان لا يوجد
بدلاً من الغوص مع مصحح أخطاء ، إما لرؤية تتبع مكدس لتفريغ النواة
(مفيد جدًا في تقرير الأخطاء)، أو محاولة معرفة الخطأ الذي حدث قبل النواة
حدث التفريغ، أو كيف انتهى بنا الأمر إلى نتائج خاطئة أو غير متوقعة.
بدس at بيرل
للتجول مع Perl ، ربما تريد بناء Perl لتصحيح الأخطاء ، مثل
هذه:
./تكوين -d -D التحسين=-g
جعل
"-g" هو إشارة لمترجم لغة سي لجعله ينتج معلومات تصحيح الأخطاء التي تسمح بذلك
لنا أن نتنقل عبر برنامج قيد التشغيل، ونرى في أي وظيفة C نحن موجودون (بدون
معلومات تصحيح الأخطاء التي قد نرى فقط العناوين العددية للوظائف ،
وهذا ليس مفيدًا جدًا).
ضبط سيؤدي أيضًا إلى تشغيل رمز التجميع "DEBUGING" الذي يمكّن جميع ملفات
كود التصحيح الداخلي في Perl. هناك مجموعة كاملة من الأشياء التي يمكنك تصحيح الأخطاء بها
هذا: Perlrun يسردها جميعًا، وأفضل طريقة للتعرف عليها هي اللعب بها
معهم. من المحتمل أن تكون الخيارات الأكثر فائدة
ل سياق (حلقة) معالجة المكدس
تتبع التنفيذ
o الطريقة ودقة التحميل الزائد
ج تحويلات سلسلة / رقمية
يمكن تحقيق بعض وظائف كود تصحيح الأخطاء باستخدام وحدات XS.
-Dr => استخدم إعادة "التصحيح"
-Dx => استخدم O 'Debug'
باستخدام a مستوى المصدر المصحح
إذا لم يساعدك إخراج التصحيح لـ "-D"، فقد حان الوقت للتنقل عبر Perl
التنفيذ باستخدام مصحح أخطاء على مستوى المصدر.
· سنستخدم "gdb" لأمثلة لدينا هنا ؛ سيتم تطبيق المبادئ على أي مصحح أخطاء (العديد
يطلق البائعون على مصحح الأخطاء "dbx") ، ولكن تحقق من دليل المصحح الذي تستخدمه.
لبدء تشغيل المصحح ، اكتب
جي دي بي ./بيرل
أو إذا كان لديك تفريغ أساسي:
gdb ./بيرل الأساسية
ستحتاج إلى القيام بذلك في شجرة مصدر Perl الخاصة بك حتى يتمكن مصحح الأخطاء من قراءة كود المصدر.
يجب أن ترى رسالة حقوق النشر ، متبوعة بالمطالبة.
(جدب)
ستنقلك كلمة "مساعدة" إلى الوثائق، ولكن إليك الأوامر الأكثر فائدة:
· تشغيل [الوسائط]
قم بتشغيل البرنامج باستخدام الوسائط المحددة.
· كسر function_name
· كسر source.c:xxx
يخبر مصحح الأخطاء أننا نريد إيقاف التنفيذ مؤقتًا عندما نصل إلى أي من الاسمين
وظيفة (ولكن راجع "الوظائف الداخلية" في perlguts!) أو السطر المحدد في الملف المسمى
مصدر الملف.
· خطوة
خطوات من خلال البرنامج سطرًا تلو الآخر.
· التالي
خطوات خلال البرنامج سطرًا تلو الآخر، دون النزول إلى الوظائف.
· يكمل
تشغيل حتى نقطة التوقف التالية.
· ينهي
قم بالتشغيل حتى نهاية الوظيفة الحالية، ثم توقف مرة أخرى.
· 'يدخل'
مجرد الضغط على Enter سيؤدي إلى إجراء العملية الأخيرة مرة أخرى - إنها نعمة عندما
التنقل عبر أميال من كود المصدر.
· نوع
يطبع تعريف C للوسيطة المقدمة.
(gdb) نوع PL_op
اكتب = هيكل المرجع {
أوب *op_next؛
OP *op_sibparent;
OP * (* op_ppaddr) (باطل) ؛
PADoffSET op_targ;
نوع العملية غير الموقعة: 9 ؛
غير موقعة int op_opt : 1؛
غير موقعة int op_slabbed : 1؛
غير موقعة int op_savefree : 1؛
غير موقعة int op_static : 1;
كثافة العمليات غير الموقعة op_folded : 1؛
كثافة العمليات غير الموقعة op_spare: 2؛
U8 op_flags؛
U8 op_private;
} *
· مطبعة
قم بتنفيذ كود C المحدد وطباعة نتائجه. تحذير: بيرل يستخدم بكثرة
وحدات الماكرو و جدب لا يدعم بالضرورة وحدات الماكرو (انظر لاحقًا "دعم الماكرو gdb").
سيتعين عليك استبدالها بنفسك، أو استدعاء cpp على ملفات التعليمات البرمجية المصدر (انظر
"The .i Targets") لذلك، على سبيل المثال، لا يمكنك القول
طباعة SvPV_nolen(sv)
لكن عليك أن تقول
print Perl_sv_2pv_nolen (sv)
قد تجد أنه من المفيد أن يكون لديك "قاموس ماكرو" ، والذي يمكنك إنتاجه بقول "cpp
-dM perl.c | فرز ". وحتى ذلك الحين ، حزب الشعب الكمبودي لن يتم تطبيق وحدات الماكرو هذه بشكل متكرر نيابةً عنك.
جدب الماكرو تقنية
الإصدارات الأخيرة من جدب لديك دعم ماكرو جيد إلى حد ما، ولكن لاستخدامه ستحتاج
لتجميع Perl مع تعريفات الماكرو المضمنة في معلومات التصحيح. استخدام دول مجلس التعاون الخليجي
الإصدار 3.1، وهذا يعني التكوين باستخدام "-Doptimize=-g3". قد يستخدم المترجمون الآخرون ملف
مفتاح مختلف (إذا كانوا يدعمون تصحيح أخطاء وحدات الماكرو على الإطلاق).
الإغراق بيرل البيانات هياكل
إحدى الطرق للتغلب على هذا الجحيم الكلي هي استخدام وظائف الإغراق في تفريغ ج؛ هؤلاء
تعمل قليلاً مثل Devel :: Peek الداخلي ، لكنها تغطي أيضًا عمليات التشغيل والهياكل الأخرى
التي لا يمكنك الحصول عليها من بيرل. لنأخذ مثالا. سوف نستخدم "$a = $b + $c" نحن
تم استخدامه من قبل، ولكن أعطه القليل من السياق: "$b = "6XXXX"; $c = 2.3;". أين الخير
مكان للتوقف وكزة حولها؟
ماذا عن "pp_add"، الوظيفة التي درسناها سابقًا لتنفيذ عامل التشغيل "+":
(gdb) كسر Perl_pp_add
نقطة التوقف 1 عند 0x46249f: الملف pp_hot.c، السطر 309.
لاحظ أننا نستخدم "Perl_pp_add" وليس "pp_add" - راجع "الوظائف الداخلية" في perlguts. مع
نقطة التوقف في مكانها، يمكننا تشغيل برنامجنا:
(gdb) run -e '$b = "6XXXX"; ج = 2.3 ؛ $ a = $ b + $ c '
سيتم تجاوز الكثير من الرسائل غير المرغوب فيها أثناء قراءة gdb في ملفات المصدر والمكتبات ذات الصلة ، و
ثم:
نقطة التوقف 1، Perl_pp_add () في pp_hot.c:309
309 دي إس بي ؛ مجموعة البيانات ؛ tryAMAGICbin (إضافة ، opASSIGN) ؛
خطوة (جي دي بي).
311 dPOPTOPnnrl_ul;
(جدب)
لقد نظرنا إلى هذا الجزء من التعليمات البرمجية من قبل، وقلنا أن "dPOPTOPnnrl_ul" يرتب لشخصين
سيتم وضع "NV" في "يسار" و"يمين" - دعنا نوسعها قليلاً:
#define dPOPTOPnnrl_ul NV right = POPn ؛ \
SV * leftsv = TOPs ؛ \
NV اليسار = USE_LEFT (leftsv)؟ SvNV (اليسار): 0.0
"POPn" يأخذ SV من أعلى المكدس ويحصل على NV الخاص به إما مباشرة (إذا كان
تم تعيين "SvNOK") أو عن طريق استدعاء الوظيفة "sv_2nv". يأخذ "TOPs" SV التالي من
الجزء العلوي من المكدس - نعم، يستخدم "POPn" "TOPs" - ولكنه لا يقوم بإزالته. ثم نستخدم "SvNV" من أجل
احصل على NV من "leftsv" بنفس الطريقة السابقة - نعم ، "POPn" يستخدم "SvNV".
نظرًا لأننا لا نملك NV مقابل $ b ، فسيتعين علينا استخدام "sv_2nv" لتحويله. إذا خطونا
مرة أخرى ، سنجد أنفسنا هناك:
خطوة (جي دي بي).
Perl_sv_2nv (sv = 0xa0675d0) في sv.c: 1669
1669 إذا (!sv)
(جدب)
يمكننا الآن استخدام "Perl_sv_dump" للتحقيق في SV:
(gdb) print Perl_sv_dump (sv)
إس في = PV(0xa057cc0) at 0xa0675d0
ريفكنت = 1
FLAGS = (POK ، pPOK)
PV = 0xa06a510 "6XXXX" \ 0
العملة = 5
لين = 6
1 دولار = باطل
نحن نعلم أننا سنحصل على 6 من هذا، لذلك دعونا ننهي الروتين الفرعي:
(جي دي بي) انتهى
قم بالتشغيل حتى الخروج من #0 Perl_sv_2nv (sv=0xa0675d0) في sv.c:1671
0x462669 في Perl_pp_add () في pp_hot.c:311
311 dPOPTOPnnrl_ul;
يمكننا أيضًا التخلص من هذا المرجع: يتم تخزين المرجع الحالي دائمًا في "PL_op" ، ويمكننا تفريغه
مع "Perl_op_dump". سيعطينا هذا مخرجات مشابهة لـ B::Debug.
(gdb) طباعة Perl_op_dump(PL_op)
{
13 النوع = إضافة ===> 14
الهدف = 1
الأعلام = (العددية، الأطفال)
{
النوع = خالية ===> (12)
(كان rv2sv)
الأعلام = (العددية، الأطفال)
{
11 النوع = gvsv ===> 12
الأعلام = (العددية)
GV = رئيسي :: ب
}
}
# أنهي هذا لاحقًا #
باستخدام جدب إلى بحث at محدد أجزاء of a برنامج
باستخدام المثال أعلاه ، كنت تعرف أن تبحث عن "Perl_pp_add" ، ولكن ماذا لو كان هناك
مكالمات متعددة إليه في كل مكان ، أو لم تكن تعرف ما هو المرجع الذي كنت عليه
البحث عن؟
إحدى الطرق للقيام بذلك هي إدخال مكالمة نادرة في مكان ما بالقرب مما تبحث عنه. ل
على سبيل المثال، يمكنك إضافة كلمة "study" قبل طريقتك:
يذاكر؛
وفي gdb افعل:
(gdb) فاصل Perl_pp_study
ثم قم بالخطوة حتى تصل إلى ما تبحث عنه. هذا يعمل بشكل جيد في حلقة إذا كنت
تريد كسر بعض التكرارات فقط:
لبلدي $c (1..100) {
ادرس إذا كان $c == 50;
}
باستخدام جدب إلى بحث at ماذا القادم محلل / lexer . فعل
إذا كنت تريد معرفة ما يفعله perl عند تحليل / ترجمة شفرتك ، فيمكنك استخدام "BEGIN
{} ":
طباعة "قبل \ n" ؛
ابدأ {دراسة؛ }
طباعة "بعد \ n" ؛
وفي gdb:
(gdb) فاصل Perl_pp_study
إذا كنت تريد معرفة ما يفعله المحلل اللغوي/المترجم داخل كتل "if" وما شابه ذلك
يجب أن تكون أكثر تعقيدًا:
إذا ($a && $b && do { BEGIN { Study } 1 } && $c) { ... }
مصدر CODE STATIC تحليل
توجد أدوات مختلفة لتحليل كود مصدر C بشكل ثابت، في مقابل حيوي,
أي بدون تنفيذ الكود. من الممكن الكشف عن تسرب الموارد ، غير محدد
السلوك ، عدم التطابق في النوع ، مشاكل قابلية النقل ، مسارات التعليمات البرمجية التي من شأنها أن تسبب غير قانونية
الوصول إلى الذاكرة والمشكلات المماثلة الأخرى عن طريق تحليل رمز C والنظر إلى ملف
الرسم البياني الناتج ، ماذا يقول عن التنفيذ وتدفق البيانات. على سبيل
في الواقع ، هذا هو بالضبط ما يعرفه مترجمي لغة سي لإعطاء تحذيرات حول التعليمات البرمجية المشبوهة.
لينت جبيرة
مفتش جودة كود C القديم الجيد ، "lint" ، متاح في عدة منصات ، ولكن
يرجى العلم أن هناك العديد من التطبيقات المختلفة لها بواسطة مختلف
البائعين، مما يعني أن العلامات ليست متطابقة عبر منصات مختلفة.
يتوفر متغير نسالة يسمى "جبيرة" (Secure Programming Lint) من
http://www.splint.org/ يجب أن يتم تجميعها على أي نظام أساسي يشبه نظام التشغيل Unix.
هناك "لينت" و الأهداف في Makefile ، ولكن قد تضطر إلى العبث بملف
الأعلام (انظر أعلاه).
التغطية
التغطية (http://www.coverity.com/) هو منتج مشابه للوبر وكقاعدة اختبار
منتجهم يقومون بشكل دوري بفحص العديد من المشاريع مفتوحة المصدر، ويعطونها
فتح حسابات مطوري البرامج لقواعد البيانات المعيبة.
التطوير المهني المستمر (قص و لصق كاشف)
تكتشف أداة cpd ترميز القص واللصق. إذا كان مثيل واحد من التعليمات البرمجية التي تم قصها ولصقها
التغييرات، ربما ينبغي تغيير جميع المواقع الأخرى أيضا. ولذلك ينبغي لمثل هذا الرمز
ربما يتم تحويلها إلى روتين فرعي أو ماكرو.
وثيقة البرنامج القطري (http://pmd.sourceforge.net/cpd.html) جزء من مشروع pmd
(http://pmd.sourceforge.net/). تمت كتابة pmd في الأصل لتحليل ثابت لجافا
الكود، ولكن لاحقًا تم توسيع جزء cpd منه ليشمل التحليل أيضًا C وC++.
قم بتنزيل ملف pmd-bin-XYzip () من موقع SourceForge ، واستخرج ملف pmd-XYjar من
، ثم قم بتشغيله على الكود المصدري على هذا النحو:
جافا -cp pmd-XYjar net.sourceforge.pmd.cpd.CPD \
- الحد الأدنى من الرموز 100 - الملفات / بعض / أين / src - اللغة c> cpd.txt
قد تصل إلى حدود الذاكرة، وفي هذه الحالة يجب عليك استخدام الخيار -Xmx:
جافا -Xmx512M ...
دول مجلس التعاون الخليجي تحذيرات
على الرغم من أنه يمكن كتابة الكثير عن مشاكل عدم الاتساق والتغطية لتحذيرات دول مجلس التعاون الخليجي
(مثل "-Wall" لا تعني "جميع التحذيرات" ، أو لا تعني بعض مشكلات قابلية النقل الشائعة
يتم تغطيتها بواسطة "-Wall" ، أو "-ansi" و "-أسطول" على حد سواء كونها سيئة التحديد
مجموعة التحذيرات، وما إلى ذلك)، لا تزال gcc أداة مفيدة في الحفاظ على التعليمات البرمجية لدينا
أنف نظيف.
يتم تشغيل "-Wall" بشكل افتراضي.
سيكون من الجيد أن تكون "-ansi" (وصاحبها "-pedantic") في وضع التشغيل دائمًا، ولكن
ولسوء الحظ، فهي ليست آمنة على جميع المنصات، ويمكن على سبيل المثال أن تسبب الوفاة
يتعارض مع رؤوس النظام (سولاريس هو مثال رئيسي). إذا تكوين
يتم استخدام "-Dgccansipedantic"، وتختار الواجهة الأمامية "cflags" "-ansi -pedantic" لـ
المنصات التي من المعروف أنها آمنة.
بدءًا من Perl 5.9.4 يتم إضافة العلامات الإضافية التالية:
· "-ملصقات Wendif"
· "-Wextra"
· "-الإعلان بعد البيان"
سيكون من الجيد الحصول على الأعلام التالية لكنهم سيحتاجون أولاً إلى Augean الخاص بهم
سيد مستقر:
· "-Wpointer-arith"
· "-ظل"
· "-Wstrict-النماذج"
"-Wtraditional" هو مثال آخر على الاتجاه المزعج لدول مجلس التعاون الخليجي لتجميع الكثير من ملفات
تحذيرات تحت مفتاح واحد (سيكون من المستحيل نشرها عمليًا لأنه سيفعل ذلك
تشكو كثيرًا) ولكنها تحتوي على بعض التحذيرات التي قد يكون من المفيد الحصول عليها
متاحة بمفردها، مثل التحذير بشأن ثوابت السلسلة داخل وحدات الماكرو
تحتوي على وسيطات الماكرو: كان هذا يتصرف بشكل مختلف قبل ANSI عما كان عليه في ANSI،
ولا تزال بعض برامج التحويل البرمجي للغة C في مرحلة انتقالية، ومثال على ذلك AIX.
تحذيرات of أخرى C المجمعين
مترجمين آخرين للغة C (نعم ، هناك . غالبًا ما يكون لمترجمي C الآخرين غير دول مجلس التعاون الخليجي) "صارمة
ANSI "أو" ANSI الصارم مع بعض ملحقات القابلية "قيد التشغيل ، مثل وضع Sun
ورشة العمل لديها وضع "-Xa" الخاص بها (وإن كان ضمنيًا) ، أو DEC (هذه الأيام ، HP ...) لديها
وضع "-std1" قيد التشغيل.
الذاكرة ديبوجرز
نوت 1: يعمل تحت مصححات الذاكرة القديمة مثل Purify أو valgrind أو الدرجة الثالثة
يبطئ التنفيذ بشكل كبير: تصبح الثواني دقائق ، وتصبح الدقائق ساعات. ل
على سبيل المثال اعتبارًا من Perl 5.8.1، يستغرق الملف ext/Encode/t/Unicode.t وقتًا طويلًا للغاية
كاملة تحت مثال Purify ، الدرجة الثالثة ، و valgrind. تحت valgrind يستغرق الأمر أكثر من
ست ساعات، حتى على جهاز كمبيوتر سريع. يجب أن يفعل الاختبار المذكور شيئًا ما تمامًا
غير ودية لمصححي أخطاء الذاكرة. إذا كنت لا ترغب في الانتظار ، يمكنك ببساطة أن تقتل
بعيدا عن عملية بيرل. يؤدي valgrind تقريبًا إلى إبطاء التنفيذ بمقدار 10 ،
العنوانالمطهر حسب العامل 2.
نوت 2: لتقليل عدد الإنذارات الكاذبة لتسرب الذاكرة (راجع "PERL_DESTRUCT_LEVEL" للاطلاع على
لمزيد من المعلومات)، يجب عليك تعيين متغير البيئة PERL_DESTRUCT_LEVEL على 2. For
مثال، مثل هذا:
env PERL_DESTRUCT_LEVEL=2 valgrind ./Perl -Ilib ...
نوت 3: هناك تسرب معروف للذاكرة عند وجود أخطاء في وقت الترجمة داخل Eval أو
تتطلب ، رؤية "S_doeval" في مكدس المكالمات هي علامة جيدة على ذلك. إصلاح هذه التسريبات
غير تافهة ، للأسف ، لكن يجب إصلاحها في النهاية.
نوت 4: لن يقوم DynaLoader بالتنظيف بعد نفسه تمامًا ما لم يتم إنشاء Perl باستخدام
تكوين الخيار "-Accflags = -DDL_UNLOAD_ALL_AT_EXIT".
فالغريند
يمكن استخدام أداة valgrind لاكتشاف تسرب الذاكرة وذاكرة الكومة غير القانونية
الوصول. اعتبارًا من الإصدار 3.3.0، يدعم Valgrind نظام التشغيل Linux فقط على أنظمة x86 وx86-64 وPowerPC
وداروين (OS X) على x86 وx86-64). يمكن استخدام الهدف الخاص "test.valgrind".
قم بإجراء الاختبارات تحت valgrind. تم العثور على أخطاء وتسربات للذاكرة يتم تسجيلها في الملفات المسماة
testfile.valgrind ويتم عرض الإخراج الافتراضي بشكل مضمن.
استخدام المثال:
قم بإجراء الاختبار
نظرًا لأن valgrind تضيف حملًا كبيرًا ، فإن الاختبارات ستستغرق وقتًا أطول للتشغيل. ال
تدعم اختبارات valgrind تشغيلها بالتوازي للمساعدة في هذا:
TEST_JOBS = 9 إجراء اختبار
لاحظ أن الاستدعائين أعلاه سيكونان مطولين جدًا كذاكرة قابلة للوصول وتسرب-
التحقق ممكّن بشكل افتراضي. إذا كنت تريد رؤية الأخطاء البحتة فقط ، فجرّب:
VG_OPTS='-q --leak-check=no --show-reachable=no' TEST_JOBS=9 \
قم بإجراء الاختبار
يوفر Valgrind أيضًا أداة cachegrind ، يتم استدعاؤها في perl على النحو التالي:
VG_OPTS = - الأداة = cachegrind قم بإجراء test.valgrind
نظرًا لأن مكتبات النظام (وأبرزها glibc) تتسبب أيضًا في حدوث أخطاء ، فإن valgrind يسمح بذلك
قمع مثل هذه الأخطاء باستخدام ملفات القمع. ملف القمع الافتراضي الذي يأتي
مع valgrind يمسك بالفعل بالكثير منهم. يتم تعريف بعض عمليات القمع الإضافية في
t / perl.supp.
للحصول على valgrind ولمزيد من المعلومات انظر
http://valgrind.org/
العنوان
AddressSanitizer هو امتداد clang و gcc ، مدرج في clang منذ الإصدار 3.1 و gcc منذ ذلك الحين
v4.8. يقوم بفحص مؤشرات الكومة غير القانونية والمؤشرات العالمية ومؤشرات المكدس واستخدامها بعد ذلك مجانًا
الأخطاء، وهو سريع بما فيه الكفاية بحيث يمكنك بسهولة تجميع تصحيح الأخطاء أو بيرل الأمثل
معها. ومع ذلك، فإنه لا يتحقق من تسرب الذاكرة. AddressSanitizer متاح لنظام التشغيل Linux،
Mac OS X وقريبًا على Windows.
لإنشاء لغة Perl باستخدام AddressSanitizer، يجب أن يبدو استدعاء التكوين بالشكل التالي:
sh تكوين -des -Dcc=clang \
-Accflags=-faddress-sanitizer -Aldflags=-faddress-sanitizer \
-Alddlflags = -shared \ -faddress-sanitizer
حيث تعني هذه الحجج:
· -Dcc=clang
يجب استبدال هذا بالمسار الكامل إلى ملفك القابل للتنفيذ إذا لم يكن في ملف
مسار.
· -Accflags = -faddress-sanitizer
تجميع مصادر perl والإضافات باستخدام AddressSanitizer.
· -Aldflags=-faddress-sanitizer
ربط الملف التنفيذي perl مع AddressSanitizer.
· -Alddlflags=-shared\ -faddress-sanitizer
ربط الامتدادات الديناميكية مع AddressSanitizer. يجب تحديد "-مشاركة" يدويًا
لأن استخدام "-Alddlflags=-shared" سيمنع التكوين من تعيين الإعداد الافتراضي
قيمة "lddlflags" ، والتي تحتوي عادةً على "-shared" (على الأقل في Linux).
أنظر أيضاhttp://code.google.com/p/address-sanitizer/wiki/AddressSanitizer>.
التشكيل
هناك طرق مختلفة لتصنيف لغة Perl، اعتمادًا على النظام الأساسي الخاص بك.
هناك طريقتان شائعتا الاستخدام لتنميط الملفات التنفيذية: إحصائي أخذ العينات الوقت
و الكتلة الأساسية عد.
الطريقة الأولى تأخذ بشكل دوري عينات من عداد برنامج وحدة المعالجة المركزية، ومنذ ذلك الحين
يمكن ربط عداد البرنامج بالكود الذي تم إنشاؤه للوظائف، نحصل على
عرض إحصائي للوظائف التي يقضي البرنامج وقته فيها. المحاذير
أن الوظائف الصغيرة جدًا / السريعة لها احتمالية أقل للظهور في الملف الشخصي ، و
أن مقاطعة البرنامج بشكل دوري (عادة ما يتم ذلك بشكل متكرر إلى حد ما، في
مقياس المللي ثانية) يفرض عبءًا إضافيًا قد يؤدي إلى تحريف النتائج. ال
يمكن تخفيف المشكلة الأولى عن طريق تشغيل الكود لفترة أطول (بشكل عام يعد هذا أمرًا جيدًا
فكرة التنميط) ، فعادة ما يتم الاحتفاظ بالمشكلة الثانية في حراسة بواسطة أدوات التنميط
أنفسهم.
الطريقة الثانية تقسم الكود الذي تم إنشاؤه إلى الأساسية كتل. الكتل الأساسية هي
أقسام التعليمات البرمجية التي يتم إدخالها فقط في البداية والخروج منها فقط في النهاية. ل
على سبيل المثال ، القفزة الشرطية تبدأ كتلة أساسية. عادةً ما يعمل التنميط الأساسي للكتل بواسطة
الأدوات الرمز عن طريق إضافة أدخل الأساسية منع # ننن رمز مسك الدفاتر إلى
رمز تم إنشاؤه. أثناء تنفيذ الكود ، تكون عدادات الكتلة الأساسية
تحديثها بشكل مناسب. التحذير هو أن الشفرة الإضافية المضافة يمكن أن تحرف النتائج:
ومرة أخرى ، تحاول أدوات التنميط عادةً أن تحلل تأثيراتها الخاصة من النتائج.
جبروف جانبي
GPROF هي أداة إنشاء ملفات تعريف متاحة في العديد من منصات Unix التي تستخدم إحصائي زمن-
أخذ العينات. يمكنك إنشاء نسخة ملف تعريف من بيرل من خلال تجميع استخدام دول مجلس التعاون الخليجي مع العلم
"-صفحة". إما تحرير التكوين.sh أو إعادة التشغيل ضبط. تشغيل الإصدار التعريفي من Perl
سيُنشئ ملف إخراج يسمى gmon.out الذي يحتوي على بيانات التنميط التي تم جمعها
أثناء الإعدام.
تلميح سريع:
$ sh تكوين -des -Dusedevel -Accflags = '- pg' \
-Aldflags='-pg' -Alddlflags='-pg -مشترك' \
&& اصنع بيرل
$ ./Perl... # ينشئ gmon.out في الدليل الحالي
$ gprof ./perl> خارج
أقل من دولار
(ربما تحتاج إلى إضافة "-shared" إلى سطر <-Alddlflags> حتى يصبح RT # 118199
تم الحل)
إنّ كافة أنواع عهود الـ GPROF يمكن للأداة بعد ذلك عرض البيانات المجمعة بطرق مختلفة. عادة GPROF
يفهم الخيارات التالية:
· -أ
منع الوظائف المحددة بشكل ثابت من ملف التعريف.
· -ب
منع الأوصاف المطولة في الملف الشخصي.
· -الروتين
استبعاد الروتين المحدد وأحفاده من الملف الشخصي.
· -f الروتين
قم بعرض الروتين المحدد وأحفاده فقط في ملف التعريف.
· -س
قم بإنشاء ملف ملخص يسمى gmon.sum والتي يمكن بعد ذلك إعطاؤها إلى gprof اللاحق
يعمل لتجميع البيانات على مدى عدة أشواط.
· -ض
عرض الإجراءات التي ليس لها أي استخدام.
لمزيد من الشرح التفصيلي للأوامر المتاحة وتنسيقات الإخراج ، راجع الخاص بك
التوثيق المحلي لـ GPROF.
الخليج GCOV جانبي
الأساسية منع جانبي متاح رسميًا في دول مجلس التعاون الخليجي 3.0 والإصدارات الأحدث. يمكنك بناء
نسخة ملفوفة من بيرل عن طريق التجميع باستخدام gcc مع العلامات "-fprofile-arcs
-ftest-coverage". إما التعديل التكوين.sh أو إعادة التشغيل ضبط.
تلميح سريع:
$ sh تكوين -des -Dusedevel -Doptimize='-g' \
-Accflags='-fprofile-arcs -ftest-coverage' \
-Aldflags = '- fprofile-arcs -ftest-Cover' \
-Alddlflags = '- fprofile-arcs -ftest-cover -shared' \
&& اصنع بيرل
$ rm -f regexec.c.gcov regexec.gcda
$ ./بيرل ...
$ gcov regexec.c
$ أقل regexec.c.gcov
(ربما تحتاج إلى إضافة "-shared" إلى سطر <-Alddlflags> حتى يصبح RT # 118199
تم الحل)
سيؤدي تشغيل الإصدار التعريفي من Perl إلى إنشاء مخرجات الملف الشخصي. لكل
الملف المصدر مرفق .gcda سيتم إنشاء الملف.
لعرض النتائج التي تستخدم GCOV الأداة المساعدة (والتي يجب تثبيتها إذا كان لديك gcc
3.0 أو أحدث مثبتة). GCOV يتم تشغيله على ملفات التعليمات البرمجية المصدر، مثل هذا
جيكوف Sv.c
مما سيؤدي sv.c.gcov ليتم انشائه. ال .gcov تحتوي الملفات على التعليمات البرمجية المصدر
مشروح بالترددات النسبية للتنفيذ المشار إليها بعلامات "#". أذا أردت
توليد .gcov لجميع ملفات الكائنات المحددة، يمكنك تشغيل شيء مثل هذا:
للملف في "العثور على . -الاسم \*.gcno`
افعل sh -c "cd `dirname $file` && gcov `basename $file .gcno`"
فعل
خيارات مفيدة من GCOV تتضمن "-b" التي تلخص الكتلة الأساسية والفرع و
تغطية استدعاء الوظيفة، و"-c" والتي بدلاً من الترددات النسبية ستستخدم الفعلي
العد. لمزيد من المعلومات حول استخدام GCOV والتنميط الأساسي للكتلة مع دول مجلس التعاون الخليجي، انظر
أحدث دليل GNU CC. اعتبارًا من 4.8 مجلس التعاون الخليجي ، هذا في
<http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-مقدمة>
متفرقات الخدع
بيرل_DESTRUCT_LEVEL
إذا كنت تريد إجراء أي من الاختبارات بنفسك يدويًا باستخدام valgrind، على سبيل المثال، فيرجى ملاحظة ذلك
ذلك بشكل افتراضي بيرل هل ليست تنظيف كل الذاكرة التي خصصتها بشكل صريح (مثل
ساحات الذاكرة العالمية) ولكن بدلاً من ذلك يتيح لـ خروج() من البرنامج بأكمله "رعاية" من هذا القبيل
المخصصات، والمعروفة أيضًا باسم "التدمير العالمي للأشياء".
هناك طريقة لإخبار Perl بإجراء التنظيف الكامل: قم بتعيين متغير البيئة
PERL_DESTRUCT_LEVEL إلى قيمة غير الصفر. يقوم برنامج تضمين t/TEST بتعيين هذا على 2، وهذا
هو ما يجب عليك فعله أيضًا، إذا كنت لا تريد رؤية "التسريبات العالمية": على سبيل المثال، لـ
يعمل تحت فالجريند
env PERL_DESTRUCT_LEVEL=2 valgrind ./Perl -Ilib t/foo/bar.t
(ملاحظة: تستخدم وحدة mod_perl Apache أيضًا متغير البيئة هذا لأغراضها الخاصة
ووسعت دلالاتها. راجع وثائق mod_perl لمزيد من المعلومات.
كما أن الخيوط التي تم إنتاجها تقوم بما يعادل تعيين هذا المتغير على القيمة 1.)
إذا تلقيت الرسالة في نهاية السباق N عددي تسربت، يمكنك إعادة التحويل البرمجي باستخدام
"-DDEBUG_LEAKING_SCALARS" ، والذي سيؤدي إلى جعل عناوين جميع SVs التي تم تسريبها
ملقاة مع تفاصيل حول المكان الذي تم فيه تخصيص كل SV في الأصل. هذه المعلومة
يتم عرضه أيضًا بواسطة Devel::Peek. لاحظ أن التفاصيل الإضافية المسجلة مع كل SV
يزيد من استخدام الذاكرة، لذلك لا ينبغي استخدامه في بيئات الإنتاج. كذلك
يحول "new_SV ()" من ماكرو إلى وظيفة حقيقية ، بحيث يمكنك استخدام المفضلة لديك
مصحح الأخطاء لاكتشاف مكان تخصيص ملفات SV المزعجة.
إذا رأيت أنك تقوم بتسريب الذاكرة في وقت التشغيل، ولكن لا valgrind ولا
سيعثر "-DDEBUG_LEAKING_SCALARS" على أي شيء، ومن المحتمل أنك تقوم بتسريب ملفات SV التي لا تزال موجودة
يمكن الوصول إليها وسيتم تنظيفها بشكل صحيح أثناء تدمير المترجم. في مثل
في بعض الحالات، يمكن أن يؤدي استخدام المفتاح "-Dm" إلى توجيهك إلى مصدر التسرب. إذا كان الملف القابل للتنفيذ
تم إنشاؤه باستخدام "-DDEBUG_LEAKING_SCALARS"، وسيقوم "-Dm" بإخراج تخصيصات SV بالإضافة إلى
تخصيصات الذاكرة. يحتوي كل تخصيص SV على رقم تسلسلي مميز سيتم كتابته
على إنشاء وتدمير SV. لذلك إذا كنت تنفذ كود التسريب في حلقة ،
تحتاج إلى البحث عن SVs التي تم إنشاؤها، ولكن لم يتم تدميرها مطلقًا بين كل دورة. لو
تم العثور على مثل SV ، قم بتعيين نقطة توقف شرطية داخل "new_SV ()" واجعلها تنكسر فقط
عندما يكون "PL_sv_serial" مساويًا للرقم التسلسلي لـ SV المتسرب. ثم سوف تمسك
المترجم في الحالة التي يتم فيها تخصيص تسرب SV، وهو
يكفي في كثير من الحالات العثور على مصدر التسرب.
نظرًا لأن "-Dm" يستخدم طبقة PerlIO للإخراج، فإنه سيخصص في حد ذاته مجموعة كبيرة من
SVs، وهي مخفية لتجنب التكرار. يمكنك تجاوز طبقة PerlIO إذا كنت تستخدم
يتم توفير تسجيل SV بواسطة "-DPERL_MEM_LOG" بدلاً من ذلك.
بيرل_MEM_LOG
إذا تم تجميعها باستخدام "-DPERL_MEM_LOG" ، فإن عمليات تخصيص الذاكرة و SV تمر عبر التسجيل
وظائف ، وهو مفيد لإعداد نقطة التوقف.
ما لم يتم تجميع "-DPERL_MEM_LOG_NOIMPL" أيضًا، تتم قراءة وظائف التسجيل
$ ENV {PERL_MEM_LOG} لتحديد ما إذا كان سيتم تسجيل الحدث ، وإذا كان الأمر كذلك فكيف:
$ENV{PERL_MEM_LOG} =~ /m/ قم بتسجيل كافة عمليات الذاكرة
$ENV{PERL_MEM_LOG} =~ /s/ قم بتسجيل كافة عمليات SV
$ENV{PERL_MEM_LOG} =~ /t/ تضمين الطابع الزمني في السجل
$ENV{PERL_MEM_LOG} =~ /^(\d+)/ الكتابة إلى FD المحدد (الافتراضي هو 2)
يشبه تسجيل الذاكرة إلى حد ما "-Dm" ولكنه مستقل عن "-DDEBUGGING"، وفي
مستوى أعلى؛ جميع الاستخدامات نيو اكس (), تجديد ()و آمن () مع المتصل
ملف التعليمات البرمجية المصدر ورقم السطر (واسم وظيفة C، إذا كان مدعومًا من قبل مترجم C).
في المقابل، "-Dm" يقع مباشرة عند نقطة "malloc()". تسجيل SV مشابه.
نظرًا لأن التسجيل لا يستخدم PerlIO، يتم تسجيل جميع تخصيصات SV ولا يوجد SV إضافي
يتم تقديم التخصيصات عن طريق تمكين التسجيل. إذا تم تجميعها مع
"-DDEBUG_LEAKING_SCALARS"، يتم أيضًا تسجيل الرقم التسلسلي لكل تخصيص SV.
DDD على مدى جدب
قد يجد هؤلاء تصحيح أخطاء perl بواجهة DDD frontend على gdb ما يلي مفيدًا:
يمكنك توسيع قائمة اختصارات تحويل البيانات، بحيث يمكنك على سبيل المثال عرض ملفات SV
IV بنقرة واحدة، دون القيام بأي كتابة. للقيام بذلك ببساطة تحرير ~/.ddd/init
ملف وإضافة بعد:
! عرض الاختصارات.
Ddd*gdbDisplayShortcuts: \
/t () // تحويل إلى سلة\n\
/ d () // تحويل إلى ديسمبر \ n \
/ x () // تحويل إلى Hex \ n \
/o () // تحويل إلى أكتوبر(\n\
السطرين التاليين:
((XPV *) (()) -> sv_any) -> xpv_pv // 2pvx \ n \
((XPVIV*) (())->sv_any )->xiv_iv // 2ivx
يمكنك الآن إجراء عمليات بحث عن ivx و pvx أو يمكنك إضافة "تحويل" sv_peek:
Perl_sv_peek (my_perl، (SV *) ()) // sv_peek
(إن my_perl مخصص للبنيات المترابطة.) فقط تذكر أن كل سطر ، ولكن الأخير ،
يجب أن ينتهي بـ \ n \
وبدلاً من ذلك، قم بتحرير ملف init بشكل تفاعلي عبر: زر الماوس الثالث -> شاشة جديدة ->
عدل القائمة
ملاحظة: يمكنك تحديد ما يصل إلى 20 اختصارًا للتحويل في قسم gdb.
C تتبع خلفي
في بعض الأنظمة الأساسية، يدعم Perl استرداد التتبع الخلفي للمستوى C (على غرار ما هو رمزي
مصححات الأخطاء مثل gdb تفعل).
يُرجع backtrace تتبع المكدس لإطارات استدعاء C ، مع أسماء الرموز
(أسماء الوظائف)، وأسماء الكائنات (مثل "Perl")، وأيضًا الكود المصدري إذا كان ذلك ممكنًا
المواقع (ملف: سطر).
الأنظمة الأساسية المدعومة هي Linux وOS X (قد تعمل بعض *BSD جزئيًا على الأقل، ولكن
لم يتم اختبارهم بعد).
لم يتم اختبار هذه الميزة مع سلاسل رسائل متعددة، ولكنها ستعرض فقط التتبع الخلفي
من الخيط الذي يقوم بالتتبع الخلفي.
يجب تمكين الميزة من خلال "Configure -Dusecbacktrace".
يتيح "-Dusecbacktrace" أيضًا الاحتفاظ بمعلومات التصحيح عند التجميع / الارتباط
(غالبًا: "-g"). يدعم العديد من المجمعين / الوصلات وجود كل من التحسين والاحتفاظ بامتداد
معلومات التصحيح. معلومات التصحيح مطلوبة لأسماء الرموز والمصدر
المواقع.
قد لا تكون الوظائف الثابتة مرئية للتتبع العكسي.
غالبًا ما تكون مواقع كود المصدر ، حتى لو كانت متاحة ، مفقودة أو مضللة إذا كان امتداد الملف
يحتوي المترجم على رمز مضمّن على سبيل المثال. يمكن للمحسن إجراء مطابقة شفرة المصدر و
رمز الكائن صعب للغاية.
لينكس
أنت يجب قم بتثبيت مكتبة BFD (-lbfd) ، وإلا ستفشل "perl" في الارتباط.
عادةً ما يتم توزيع BFD كجزء من ملفات GNU.
ملخص: "تكوين ... -Dusecbacktrace" وتحتاج إلى "-lbfd".
OS X
يتم دعم مواقع التعليمات البرمجية المصدر فقط إذا كان لديك أدوات المطور
المثبتة. (بي إف دي هو ليست ضروري.)
ملخص: "تكوين ... -Dusecbacktrace" وتثبيت أدوات المطور سيكون
جيدة.
اختياريًا ، لتجربة الميزة ، قد ترغب في تمكين الإغراق التلقائي لملف
backtrace مباشرة قبل إصدار رسالة تحذير أو تموت، وذلك عن طريق الإضافة
"-Accflags=-DUSE_C_BACKTRACE_ON_ERROR" للتكوين.
ما لم يتم تمكين الميزة الإضافية المذكورة أعلاه ، لا شيء يتعلق بوظيفة backtrace
مرئي، باستثناء مستوى Perl/XS.
علاوة على ذلك ، حتى إذا قمت بتمكين هذه الميزة ليتم تجميعها ، فأنت بحاجة إلى تمكينها
في وقت التشغيل مع متغير البيئة: "PERL_C_BACKTRACE_ON_ERROR=10". يجب أن يكون
عدد صحيح أعلى من الصفر، يوضح عدد الإطارات المطلوبة.
سيكون استرداد التتبع الخلفي من مستوى Perl (باستخدام امتداد XS على سبيل المثال) أمرًا كبيرًا
أقل إثارة مما قد يأمله المرء: عادةً ما ترى "runops" و"entersub" وليس
أكثر من ذلك بكثير. تم تصميم واجهة برمجة التطبيقات هذه ليتم استدعاؤها تبدأ من في غضون تنفيذ بيرل، لا
من تنفيذ مستوى بيرل.
واجهة برمجة تطبيقات C للتتبع الخلفي هي كما يلي:
get_c_backtrace
free_c_backtrace
get_c_backtrace_dump
Dump_c_backtrace
سم
إذا رأيت في مصحح الأخطاء منطقة ذاكرة مليئة بشكل غامض بـ 0xABABABAB أو 0xEFEFEFEF ، فأنت
قد ترى تأثير سم() وحدات الماكرو، راجع perlclib.
للقراءة فقط opttrees
تحت المواضيع تتم قراءة optree فقط. إذا كنت ترغب في فرض هذا، للتحقق من الكتابة
الوصول من التعليمات البرمجية التي تجرها الدواب، قم بتجميعها باستخدام "-Accflags=-DPERL_DEBUG_READONLY_OPS" للتمكين
الكود الذي يخصص ذاكرة العمليات عبر "mmap" ، ويضبطها للقراءة فقط عندما تكون متصلة بملف
روتين فرعي. أي وصول للكتابة إلى العملية يؤدي إلى "SIGBUS" وإحباط.
هذا الرمز مخصص للتطوير فقط ، وقد لا يكون قابلاً للنقل حتى في جميع أنظمة Unix
المتغيرات. أيضًا ، إنه حل بنسبة 80٪ ، حيث إنه غير قادر على جعل جميع العمليات للقراءة فقط.
ولا ينطبق هذا على وجه التحديد على الألواح التشغيلية التي تنتمي إلى كتل "BEGIN".
ومع ذلك ، كحل بنسبة 80٪ ، فإنه لا يزال فعالاً ، حيث أنه قد اصطدم بالبق في الماضي.
متى is a منطقي ليست a منطقي؟
في برامج التحويل البرمجي السابقة لـ C99 ، يتم تعريف "bool" على أنه مكافئ لـ "char". وبالتالي التنازل
من أي نوع أكبر إلى "منطقي" غير آمن وقد يتم اقتطاعه. الماكرو "cBOOL" موجود
لتلقيها بشكل صحيح.
على تلك المنصات والمترجمين حيث يكون "bool" منطقيًا حقًا (C++، C99)، يكون الأمر سهلاً
لننسى المدلى بها. يمكنك إجبار "bool" على أن يكون "char" عن طريق التحويل البرمجي باستخدام
"-Accflags=-DPERL_BOOL_AS_CHAR". قد ترغب أيضًا في تشغيل "التكوين" بشيء مثل
-Accflags='-Wconversion -Wno-sign-conversion -Wno-shorten-64-to-32'
أو ما يعادله مترجمك لتسهيل اكتشاف أي عمليات اقتطاع غير آمنة تظهر
يصل.
إنّ كافة أنواع عهود الـ .i الأهداف
يمكنك توسيع وحدات الماكرو في ملف foo.c ملف بالقول
جعل foo.i
والتي سوف توسع وحدات الماكرو باستخدام CPP. لا تخافوا من النتائج.
استخدم perlhacktips عبر الإنترنت باستخدام خدمات onworks.net