Amazon Best VPN GoSearch

סמל OnWorks

perlhacktips - מקוון בענן

הפעל perlhacktips בספק אירוח חינמי של OnWorks על אובונטו מקוון, פדורה מקוון, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

זוהי הפקודה perlhacktips שניתן להריץ בספק האירוח החינמי של OnWorks באמצעות אחת מתחנות העבודה המקוונות המרובות שלנו, כגון Ubuntu Online, Fedora Online, אמולטור מקוון של Windows או אמולטור מקוון של MAC OS

תָכְנִית:

שֵׁם


perlhacktips - טיפים לפריצת קוד C של ליבת Perl

תיאור


מסמך זה יעזור לך ללמוד את הדרך הטובה ביותר להתמודד עם פריצה על ליבת Perl C
קוד. זה מכסה בעיות נפוצות, ניפוי באגים, פרופילים ועוד.

אם עדיין לא קראת את perlhack ו-perlhacktut, אולי תרצה לעשות את זה קודם.

משותף בעיות


מקור Perl משחק לפי חוקי ANSI C89: אין הרחבות C99 (או C++). במקרים מסוימים אנחנו חייבים
לקחת בחשבון את הדרישות שלפני ANSI. לא אכפת לך ממשהו מסוים
הפלטפורמה שברה את פרל? שמעתי שעדיין יש דרישה חזקה למתכנתי J2EE.

פרל סביבה בעיות
· לא קומפילציה עם שרשור

קומפילציה עם שרשור (-Duseithreads) משכתבת לחלוטין את אבות הטיפוס של הפונקציות
של פרל. כדאי לנסות את השינויים שלך עם זה. קשור לזה ההבדל
בין ממשקי API של "Perl_-less" ו-"Perl_-ly", לדוגמה:

Perl_sv_setiv(aTHX_ ...);
sv_setiv(...);

הראשון עובר במפורש בהקשר, הדרוש למשל לשרשור
בונה. השני עושה זאת במרומז; אל תערבבו אותם. אם אתה לא
עובר ב-aTHX_, תצטרך לעשות dTHX (או dVAR) בתור הדבר הראשון ב-
פונקציה.

ראה "כיצד נתמכים במספר מתורגמנים ובמקבילות" ב-perlguts להמשך
דיון על הקשר.

· לא קומפילציה עם -DDEBUGGING

ה-DEBUGGING define חושף יותר קוד לקומפיילר, ולכן יותר דרכים לדברים
לטעות. אתה צריך לנסות את זה.

· היכרות עם גלובלים (לא לקריאה בלבד).

אל תציג גלובלים הניתנים לשינוי, גלובליים באמת או סטטיים של קבצים. הם רעים
ליצור ולסבך ריבוי פתילים וצורות אחרות של במקביל. הדרך הנכונה היא
להציג אותם כמשתנים מתורגמנים חדשים, ראה intrpvar.h (בסוף עבור
תאימות בינארית).

הצגת גלובליות לקריאה בלבד (const) היא בסדר, כל עוד אתה מאמת עם למשל "nm
libperl.a|egrep -v ' [TURtr] '" (אם ל-"nm" שלך יש פלט בסגנון BSD) שהנתונים שאתה
נוסף הוא באמת לקריאה בלבד. (אם כן, זה לא אמור להופיע בפלט של זה
פקודה.)

אם אתה רוצה לקבל מחרוזות סטטיות, הפוך אותן לקבועות:

static const char etc[] = "...";

אם אתה רוצה לקבל מערכים של מחרוזות קבועות, שים לב היטב את השילוב הנכון
של "const"s:

סטטי const char * const yippee[] =
{"היי", "הו", "כסף"};

יש דרך להסתיר לחלוטין את כל הגלובליות הניתנות לשינוי (כולם מועברים לערימה),
הגדרת ההידור "-DPERL_GLOBAL_STRUCT_PRIVATE". זה לא בשימוש בדרך כלל, אבל
יכול לשמש לבדיקה, קרא עוד על זה ב"רקע ו-PERL_IMPLICIT_CONTEXT"
בפרלוגים.

· לא מייצא את הפונקציה החדשה שלך

פלטפורמות מסוימות (Win32, AIX, VMS, OS/2, אם להזכיר כמה) דורשות כל פונקציה שהיא
חלק מה-API הציבורי (ספריית Perl המשותפת) שיסומן במפורש כמיוצא.
ראה את הדיון על embed.pl בפרלוגים.

· ייצוא הפונקציה החדשה שלך

התוצאה הנוצצת החדשה של פונקציונליות חדשה אמיתית או של עיבוד מחדש מפרך שלך
כעת מוכן ומיוצא כהלכה. אז מה יכול להשתבש?

אולי פשוט שלא היה צורך לייצא את הפונקציה שלך מלכתחילה. פרל
יש היסטוריה ארוכה ולא כל כך מפוארת של ייצוא פונקציות שאסור שיהיו לה.

אם הפונקציה משמשת רק בתוך קובץ קוד מקור אחד, הפוך אותה לסטטית. ראה את
דיון על embed.pl בפרלוגים.

אם הפונקציה משמשת על פני מספר קבצים, אך מיועדת רק לחלק הפנימי של Perl
השתמש (וזה אמור להיות המקרה הנפוץ), אל תייצא אותו ל-API הציבורי. ראה את
דיון על embed.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).

כמו כן, למד היטב את הפרלפורט כדי למנוע הנחות רעות לגבי מערכת ההפעלה,
מערכות קבצים, ערכת תווים וכן הלאה.

אתה יכול מדי פעם לנסות "עשה מיקרופרל" כדי לראות אם אנחנו עדיין יכולים להרכיב את Perl
עם המינימום המינימלי של ממשקים. (ראה README.micro.)

אל תניח שמערכת הפעלה מציינת מהדר מסוים.

· יציקת מצביעים למספרים שלמים או יציקת מספרים שלמים למצביעים

בטל נשלח (U8* p)
{
IV i = p;

or

בטל נשלח (U8* p)
{
IV i = (IV)p;

שניהם גרועים, שבורים, ואינם ניתנים לנייד. להשתמש ב PTR2IV() מאקרו שעושה את זה נכון.
(כמו כן, יש PTR2UV(), PTR2NV(), INT2PTR(), ו NUM2PTR().)

· יציקה בין מצביעי פונקציה ומצביעי נתונים

מבחינה טכנית ליהוק בין מצביעי פונקציה ומצביעי נתונים אינו ניתן לניוד
ולא מוגדר, אבל בפועל נראה שזה עובד, אבל אתה צריך להשתמש ב
FPTR2DPTR()‎ ו DPTR2FPTR() פקודות מאקרו. לפעמים אתה יכול גם לשחק משחקים עם איגודים.

· בהנחה של sizeof(int) == sizeof(long)

יש פלטפורמות שבהן longs הם 64 סיביות, ופלטפורמות שבהן ints הם 64 סיביות, ו
בזמן שאנחנו יוצאים לזעזע אותך, אפילו פלטפורמות שבהן מכנסיים קצרים הם 64 סיביות. זה הכל
חוקי לפי תקן C. (במילים אחרות, "ארוך ארוך" אינו דרך ניידת
כדי לציין 64 סיביות, ו"ארוך ארוך" אפילו לא מובטח להיות רחב יותר מ
"ארוך".)

במקום זאת, השתמש בהגדרות IV, UV, IVSIZE, I32SIZE וכן הלאה. הימנע מדברים כמו
I32 כי הם כן לֹא מובטח שיהיה בדיוק 32 ביטים, הם at הכי פחות 32 ביטים,
וגם לא מובטח שהם יהיו int or ארוך. אם אתה באמת צריך 64 סיביות במפורש
משתנים, השתמשו ב-I64 וב-U64, אך רק אם נשמרים על ידי HAS_QUAD.

· בהנחה שניתן להפנות כל סוג של מצביע לכל סוג של נתונים

char *p = ...;
פוני ארוך = *p; /* גרוע */

פלטפורמות רבות, בצדק רב, יתנו לך מזבלה הליבה במקום פוני אם ה-p
במקרה לא מיושר נכון.

· יציקות Lvalue

(int)*p = ...; /* גרוע */

פשוט לא נייד. קבל את ה-lvalue שלך ​​מהסוג הנכון, או אולי השתמש בזמני
משתנים, או טריקים מלוכלכים עם איגודים.

· נניח דבר על מבנים (במיוחד אלה שאתה לא שולט בהם, כמו אלה
מגיע מכותרות המערכת)

· ששדה מסוים קיים במבנה

· שלא קיימים תחומים נוספים מלבד אלו שאתה מכיר

· ששדה הוא בעל סימן מסוים, גודל או סוג מסוים

· שהשדות בסדר מסוים

· בעוד ש-C מבטיח את הסדר המצוין בהגדרת המבנה,
בין פלטפורמות שונות ההגדרות עשויות להיות שונות

· שה-sizeof(struct) או היישורים זהים בכל מקום

· ייתכן שיהיו בתים ריפוד בין השדות ליישור השדות -
הבתים יכולים להיות כל דבר

· מבנים נדרשים להיות מיושרים ליישור המקסימלי הנדרש
לפי השדות - אשר עבור טיפוסים מקומיים הוא בדרך כלל שווה ערך ל
sizeof () של השדה

· בהנחה שקבוצת התווים היא ASCIIish

Perl יכולה לקמפל ולהריץ תחת פלטפורמות EBCDIC. ראה perlebcdic. זה שקוף
לרוב, אבל בגלל שקבוצות התווים שונות, לא כדאי להשתמש במספרים
קבועים (עשרוניים, אוקטליים או הקסדיים) להתייחסות לתווים. אתה יכול לומר בבטחה 'א',
אבל לא 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" עבורך, בהתבסס על הפלטפורמה הנוכחית.

שימו לב שה-"isFOO" ולFOO" פקודות מאקרו ב שימושי.ח לעבוד כמו שצריך על קוד מקורי
נקודות ומיתרים.

כמו כן, הטווח 'A' - 'Z' ב-ASCII הוא רצף רצוף של 26 אותיות אלפביתיות גדולות
דמויות. זה לא נכון ב-EBCDIC. גם לא עבור 'a' עד 'z'. אבל '0' - '9' הוא an
טווח בלתי שבור בשתי המערכות. אל תניח כלום לגבי טווחים אחרים. (ציין זאת
טיפול מיוחד בטווחים בדפוסי ביטוי רגולרי גורם לזה להופיע בקוד Perl
שהטווחים הנ"ל כולם לא נשברים.)

רבות מההערות בקוד הקיים מתעלמות מהאפשרות של EBCDIC, וייתכן שכן
שגוי לכן, גם אם הקוד עובד. זו בעצם מחווה למצליחנים
הכנסה שקופה של יכולת להתמודד עם EBCDIC ללא צורך בשינוי מראש
קוד קיים.

UTF-8 ו-UTF-EBCDIC הם שני קידודים שונים המשמשים לייצוג נקודות קוד Unicode
כרצפים של בתים. מאקרו עם אותם שמות (אך הגדרות שונות) ב
utf8.h ו utfebcdic.h משמשים כדי לאפשר לקוד הקורא לחשוב שיש רק
קידוד אחד כזה. זה מכונה כמעט תמיד "utf8", אבל זה אומר את
גם גרסת EBCDIC. שוב, הערות בקוד עשויות להיות שגויות גם אם
הקוד עצמו נכון. לדוגמה, הרעיון של UTF-8 "תווים בלתי משתנה"
שונה בין ASCII ל-EBCDIC. בפלטפורמות ASCII, רק תווים שלא
יש להגדיר את הסיביות בסדר גבוה (כלומר שהאורדינלים שלהם הם ASCII קפדניים, 0 - 127) הם
בלתי משתנה, והתיעוד וההערות בקוד עשויים להניח זאת, לעתים קרובות
הכוונה למשהו כמו, נגיד, "הימנע". המצב שונה ואינו כל כך פשוט
במכונות EBCDIC, אבל כל עוד הקוד עצמו משתמש ב-"NATIVE_IS_INVARIANT()"
מאקרו כראוי, זה עובד, גם אם ההערות שגויות.

כפי שצוין ב-"TESTING" ב-perlhack, בעת כתיבת סקריפטים למבחן, הקובץ
t/charset_tools.pl מכיל כמה פונקציות מועילות לכתיבת מבחנים התקפים בשניהם
פלטפורמות ASCII ו-EBCDIC. עם זאת, לפעמים בדיקה לא יכולה להשתמש בפונקציה והיא כן
לא נוח לקבל גרסאות בדיקה שונות בהתאם לפלטפורמה. יש 20
נקודות קוד זהות בכל 4 ערכות התווים המוכרות כעת על ידי Perl
(שלושת דפי הקוד של EBCDIC בתוספת ISO 3-8859 (ASCII/Latin1)). אלה יכולים לשמש כאלה
בדיקות, אם כי ישנה אפשרות קטנה ש-Perl יהפוך זמין עדיין
מערכת תווים נוספת, שוברת את המבחן שלך. כל נקודות הקוד הללו מלבד אחת הן C0
דמויות בקרה. הפקדים המשמעותיים ביותר שהם זהים הם "\0", "\r",
ו-"\N{VT}" (ניתן לציין גם כ-"\cK", "\x0B", "\N{U+0B}", או "\013"). הרווק
אי שליטה הוא U+00B6 PILCROW SIGN. לפקדים שהם זהים יש את אותו סיביות
דפוס בכל 4 ערכות התווים, ללא קשר ל-UTF8ness של המחרוזת המכילה
אוֹתָם. דפוס הסיביות עבור U+B6 זהה בכל 4 המחרוזות שאינן UTF8, אך שונה
בכל אחד כאשר המחרוזת המכילה שלו מקודדת UTF-8. הקוד היחיד האחר מצביע על כך
יש איזושהי זהות בכל 4 ערכות התווים הם הזוג 0xDC ו-0xFC.
יחד אלה מייצגים אותיות גדולות וקטנות לטינית U WITH DIAERESIS, אבל
הוא עליון ומה נמוך יותר עשוי להיות הפוך: 0xDC היא הבירה בלטינית1 ו-0xFC היא
האות הקטנה, בעוד 0xFC היא הבירה ב-EBCDIC ו-0xDC היא הקטנה. זֶה
ניתן לנצל factoid בכתיבת בדיקות חסרות רגישות לאותיות המקרים שהן זהות לאורך
כל 4 ערכות התווים.

· בהנחה שקבוצת התווים היא רק ASCII

ASCII הוא קידוד של 7 סיביות, אך בתים מכילים 8 סיביות. 128 התווים הנוספים
יש משמעויות שונות בהתאם למקום. חסר מקום, כרגע אלה
תווים נוספים נחשבים בדרך כלל כבלתי מוקצים, וזה הוצג
כמה בעיות. זה השתנה החל מ-5.12 כך שתווים אלה יכולים
להיחשב כ-Latin-1 (ISO-8859-1).

· ערבוב #define ו-#ifdef

#define BURGLE(x) ... \
#ifdef BURGLE_OLD_STYLE /* BAD */
... תעשה את זה בדרך הישנה ... \
#else
... לעשות את זה בדרך החדשה ... \
#endif

אתה לא יכול "לערם" הנחיות cpp בצורה ניידת. לדוגמא לעיל אתה צריך שניים
נפרד לִפְרוֹץ() #מגדיר, אחד לכל סניף #ifdef.

· הוספת דברים שאינם מעירים לאחר #endif או #else

#ifdef SNOSH
...
#else !SNOSH /* BAD */
...
#endif SNOSH /* BAD */

ה-#endif ו-#else לא יכולים להכיל שום דבר שאינו תגובה אחריהם. אם אתה
רוצה לתעד מה קורה (וזה רעיון טוב במיוחד אם הסניפים
ארוך), השתמש בהערות (C):

#ifdef SNOSH
...
#else /* !SNOSH */
...
#endif /* SNOSH */

אפשרות gcc "-Wendif-labels" מזהירה מפני הגרסה הרעה (כברירת מחדל בהתחלה
מתוך Perl 5.9.4).

· פסיק אחרי הרכיב האחרון של רשימת מנויים

Enum color {
CERULEAN,
ירקרק,
CINNABAR, /* BAD */
};

אינו נייד. עזוב את הפסיק האחרון.

כמו כן, שים לב שהאם ה-enums ניתנים לשינוי במרומז ל-ints משתנה בין
מהדרים, ייתכן שתצטרך (int).

· שימוש ב-//-הערות

// פונקציה זו מעניקה את הזורקלטור. /* גרוע */

כלומר C99 או C++. פרל הוא C89. השימוש ב-//-הערות מותר בשקט על ידי C רבים
מהדרים, אבל הגברת ההקפדה על ANSI C89 (מה שאנחנו אוהבים לעשות) גורמת ל
קומפילציה להיכשל.

· ערבוב הצהרות וקוד

void zorklator()
{
int n = 3;
set_zorkmids(n); /* גרוע */
int q = 4;

כלומר C99 או C++. כמה מהדרים של C מאפשרים זאת, אבל אתה לא צריך.

אפשרות gcc "-Wdeclaration-after-statements" סורקת בעיות כאלה (כברירת מחדל ב-
החל מ- Perl 5.9.4).

· הכנסת משתנים בפנים ל()

for(int i = ...; ...; ...) { /* BAD */

כלומר C99 או C++. אמנם זה יהיה מאוד נחמד לקבל את זה גם ב-C89,
כדי להגביל את היקף משתנה הלולאה, למרבה הצער, אנחנו לא יכולים.

· ערבוב מצביעי תווים חתומים עם מצביעי תווים לא חתומים

int foo(char *s) { ... }
...
char unsigned *t = ...; /* או U8* t = ... */
כף רגל); /* גרוע */

אמנם מדובר בפרקטיקה משפטית, אבל זה בהחלט מפוקפק, וקטלני לחלוטין לפחות
פלטפורמה אחת: למשל VMS cc רואה בכך שגיאה קטלנית. סיבה אחת לאנשים
לעתים קרובות עושה את הטעות הזו "צ'אר עירום" ולכן ניתנת ל"עירום".
ל-char pointer" יש חתימה לא מוגדרת: זה תלוי במהדר ובדגלים
של המהדר והפלטפורמה הבסיסית בין אם התוצאה חתומה או לא חתומה.
בדיוק מאותה סיבה השימוש ב'char' כאינדקס מערך הוא רע.

· מאקרו שיש להם קבועי מחרוזת והארגומנטים שלהם כמחרוזות משנה של המחרוזת
קבוע

#define FOO(n) printf("number = %d\n", n) /* BAD */
FOO(10);

סמנטיקה טרום-ANSI עבור זה היה שווה ערך

printf("10umber = %d\10");

וזה כנראה לא מה שציפית. לצערי לפחות אחד באופן סביר
מהדר C הנפוץ והמודרני עושה כאן "תאימות לאחור אמיתית", כלומר ב-AIX
מה עדיין קורה למרות ששאר מהדר AIX הוא בשמחה רבה C89.

· שימוש בפורמטים של printf עבור סוגי C שאינם בסיסיים

IV i = ...;
printf("i = %d\n", i); /* גרוע */

למרות שזה עשוי לפעול במקרה בפלטפורמה כלשהי (שם IV הוא במקרה "int"),
באופן כללי זה לא יכול. IV יכול להיות משהו גדול יותר. אפילו יותר גרוע המצב עם
סוגים ספציפיים יותר (מוגדרים על ידי שלב התצורה של Perl config.h):

Uid_t who = ...;
printf("מי = %d\n", מי); /* גרוע */

הבעיה כאן היא ש-Uid_t עשוי להיות לא רק שאינו רחב "int" אלא יכול להיות שהוא גם כן
unsigned, ובמקרה זה יודפס UID גדול כערכים שליליים.

אין לזה פתרון פשוט בגלל 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)משהו_מאוד_קטן_וחתום);

זכור גם שהפורמט %p באמת דורש מצביע ריק:

U8* p = ...;
printf("p = %p\n", (void*)p);

אפשרות gcc "-Wformat" סורקת בעיות כאלה.

· שימוש עיוור בפקודות מאקרו וריאדיות

ל-gcc יש אותם במשך זמן מה עם תחביר משלו, ו-C99 הביא אותם עם a
תחביר מתוקנן. אל תשתמש בראשון, והשתמש באחרון רק אם
HAS_C99_VARIADIC_MACROS מוגדר.

· העברת va_list בצורה עיוורת

לא כל הפלטפורמות תומכות בהעברת va_list לפונקציות נוספות של varargs (stdarg). ה
הדבר הנכון לעשות הוא להעתיק את ה-va_list באמצעות Perl_va_copy() אם ה-NEED_VA_COPY
מוגדר.

· שימוש בביטויי הצהרת gcc

val = ({...;...;...}); /* גרוע */

אמנם הרחבה נחמדה, אבל היא לא ניידת. קוד Perl אמנם משתמש בהם אם
זמינים כדי להשיג קצת מהירות נוספת (בעצם כצורה פאנקית של אינליין), אבל אתה
לא צריך.

· חיבור של מספר משפטים במאקרו

השתמש בפקודות המאקרו STMT_START ו-STMT_END.

STMT_START {
...
} STMT_END

· בדיקת מערכות הפעלה או גרסאות מתי צריכה להיות בדיקת תכונות

#ifdef __FOONIX__ /* BAD */
foo = quux();
#endif

אלא אם כן אתה יודע זאת בוודאות של 100%. quux() זמין תמיד רק עבור
מערכת הפעלה "Foonix". ו זה זמין ו עובד נכון עבור את כל עבר,
מתנה, ו גרסאות עתידיות של "Foonix", האמור לעיל שגוי מאוד. זה יותר
נכון (אם כי עדיין לא מושלם, מכיוון שהמאמר שלהלן הוא בדיקת זמן הידור):

#ifdef HAS_QUUX
foo = quux();
#endif

כיצד ה-HAS_QUUX הופך להיות מוגדר היכן שהוא צריך להיות? ובכן, אם פוניקס יקרה
להיות Unixy מספיק כדי להיות מסוגל להפעיל את הסקריפט Configure, ו-Configure נלמד
על איתור ובדיקה quux(), ה-HAS_QUUX יוגדר כהלכה. באחר
פלטפורמות, שלב התצורה התואם יעשה את אותו הדבר.

בקיצור, אם אתה לא יכול לחכות ל-Configure כדי לקבל השכלה, או אם יש לך טוב
תחושה לאן quux() עשוי להיות זמין, אתה יכול לנסות זמנית את הפעולות הבאות:

#if (defined(__FOONIX__) || defined(__BARNIX__))
# הגדר את HAS_QUUX
#endif

...

#ifdef HAS_QUUX
foo = quux();
#endif

אבל בכל מקרה, נסו להפריד בין התכונות לבין מערכות ההפעלה.

· בהנחה שהתוכן של זיכרון סטטי הצביע עליו ערכי ההחזר של Perl
עטיפות עבור פונקציות ספריית C אינן משתנות. פונקציות רבות של ספריית C חוזרות
מצביעים לאחסון סטטי שניתן לדרוס על ידי קריאות עוקבות לאותו או
פונקציות קשורות. לפרל יש עטיפות קלות משקל עבור חלק מהפונקציות הללו, ו
שאינם יוצרים עותקים של הזיכרון הסטטי. דוגמה טובה היא הממשק ל-
משתני סביבה בתוקף עבור התוכנית. לפרל יש "PerlEnv_getenv"
לקבל ערכים מהסביבה. אבל החזרה היא מצביע לזיכרון סטטי ב
ספריית C. אם אתה משתמש בערך כדי לבדוק מיד משהו, זה
בסדר, אבל אם אתה שומר את הערך ומצפה שהוא ישתנה על ידי עיבוד מאוחר יותר, אתה
יהיה שגוי, אבל אולי לא תדע את זה בגלל ספריית C שונה
יישומים מתנהגים אחרת, וזה בפלטפורמה שבה אתה בודק
עשוי לעבוד עבור המצב שלך. אבל בכמה פלטפורמות, קריאה לאחר מכן ל
"PerlEnv_getenv" או פונקציה קשורה תחליף את הזיכרון שהתקשרת הראשונה שלך
נקודות ל. זה הוביל לכמה בעיות שקשה לאפות באגים. תעשה "savepv" בפרלפי ל
ליצור עותק, ובכך למנוע בעיות אלה. תצטרך לשחרר את העותק כשתהיה
נעשה כדי למנוע דליפות זיכרון. אם אין לך שליטה על מתי זה ישתחרר, תהיה לך
צריך ליצור את העותק בסקלאר בן תמותה, כך:

if ((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() במקום.

אבטחה בעיות
אחרון חביב, הנה טיפים שונים לקידוד בטוח יותר. ראה גם perlclib עבור
יש להשתמש בתחליפים של libc/stdio.

· אל תשתמש מקבל ()

או שנלעג אותך בפומבי. ברצינות.

· אל תשתמש tmpfile()

השתמש mkstemp() במקום.

· אל תשתמש strcpy () or strcat() or strncpy () or strncat()

השתמש my_strlcpy() ו my_strlcat() במקום זאת: הם משתמשים ביישום המקורי,
או היישום של פרל עצמו (ששאיל מהיישום ברשות הרבים של INN).

· אל תשתמש sprintf () or vsprintf()

אם אתה באמת רוצה רק מחרוזות בייט פשוטות, השתמש my_snprintf() ו my_vsnprintf()
במקום זאת, אשר ינסה להשתמש snprintf () ו vsnprintf () אם ממשקי API בטוחים יותר כאלה
זמין. אם אתה רוצה משהו מהודר יותר ממחרוזת בתים רגילה, השתמש ב-"Perl_form"()
או SVs ו-"Perl_sv_catpvf()".

שימו לב ש-glibc "printf()", "sprintf()" וכו' הם באגים לפני גרסה 2.17 של glibc.
הם לא יאפשרו לפורמט "%s" עם דיוק ליצור מחרוזת שאינה חוקית
UTF-8 אם המקום הבסיסי הנוכחי של התוכנית הוא UTF-8. מה שקורה זה
ה-%s והאופרנד שלו פשוט מדלגים ללא כל הודעה מוקדמת.
.

· אל תשתמש atoi ()

השתמש grok_atoUV() במקום. atoi () יש התנהגות לא מוגדרת על הצפות, ולא יכול להיות
משמש לניתוח מצטבר. זה גם מושפע מהמקום, וזה רע.

· אל תשתמש strtol () or strtoul()

השתמש grok_atoUV() במקום. strtol () or strtoul() (או המאקרו הידידותי ל-IV/UV שלהם
תחפושות, Strtol() ו Strtoul(), או Atol() ו Atoul() מושפעים מהמקום, אשר
רע.

פיתרון


אתה יכול להרכיב גרסת ניפוי באגים מיוחדת של Perl, המאפשרת לך להשתמש ב-"-D"
אפשרות של Perl לספר יותר על מה פרל עושה. אבל לפעמים אין
אלטרנטיבה מאשר לצלול פנימה עם מאפר באגים, או כדי לראות את עקבות הערימה של מזבלה ליבה
(שימושי מאוד בדוח באג), או בניסיון להבין מה השתבש לפני הליבה
התרחשה dump, או איך בסופו של דבר קיבלנו תוצאות שגויות או בלתי צפויות.

Poking at פרל
כדי לחטט באמת עם Perl, סביר להניח שתרצה לבנות Perl לניפוי באגים, כמו
זֶה:

./Configure -d -D optimize=-g
לעשות

"-g" הוא דגל לקומפיילר C כדי שייצר מידע איתור באגים שיאפשר
לנו לעבור דרך תוכנית פועלת, ולראות באיזו פונקציה C אנחנו נמצאים (בלי
את מידע איתור הבאגים אנו עשויים לראות רק את הכתובות המספריות של הפונקציות,
מה שלא ממש עוזר).

גדר יפעיל גם את סמל ההידור "DEBUGGING" המאפשר את כל
קוד ניפוי באגים פנימי ב- Perl. יש הרבה דברים שאתה יכול לבצע איתם באגים
זה: perlrun מפרט את כולם, והדרך הטובה ביותר לגלות עליהם היא לשחק עליהם
איתם. האפשרויות השימושיות ביותר הן כנראה

l עיבוד מחסנית בהקשר (לולאה).
• מעקב אחר ביצוע
o שיטה ורזולוציית עומס יתר
ג המרות מחרוזות/מספריות

ניתן להשיג חלק מהפונקציונליות של קוד איתור הבאגים באמצעות מודולי XS.

-Dr => השתמש מחדש ב-'debug'
-Dx => השתמש ב-O 'Debug'

שימוש a ברמת המקור הבאגים
אם פלט ניפוי הבאגים של "-D" לא עוזר לך, זה הזמן לעבור דרך של perl
ביצוע עם מאתר באגים ברמת המקור.

· נשתמש ב-"gdb" עבור הדוגמאות שלנו כאן; העקרונות יחולו על כל מאפר באגים (רבים
הספקים קוראים לאיבאג שלהם "dbx"), אבל בדוק את המדריך של זה שאתה משתמש בו.

כדי להפעיל את מאתר הבאגים, הקלד

gdb ./perl

או אם יש לך מזבלה ליבה:

gdb ./perl core

תרצה לעשות זאת בעץ המקור של Perl שלך כדי שהמאתר באגים יוכל לקרוא את קוד המקור.
אתה אמור לראות את הודעת זכויות היוצרים, ואחריה את ההנחיה.

(gdb)

"עזרה" יכניס אותך לתיעוד, אבל הנה הפקודות השימושיות ביותר:

· להפעיל [args]

הפעל את התוכנית עם הארגומנטים הנתונים.

· break function_name

· הפסקת source.c:xxx

אומר למאתר הבאגים שנרצה להשהות את הביצוע כשנגיע לאחד מהשמות
פונקציה (אך ראה "פונקציות פנימיות" ב-perlguts!) או את השורה הנתונה ב-named
קובץ מקור.

· שלב

עובר בתוכנית שורה בכל פעם.

· הבא

עובר בתוכנית שורה בכל פעם, מבלי לרדת לפונקציות.

· להמשיך

הפעל עד לנקודת השבירה הבאה.

· סיים

הפעל עד סוף הפונקציה הנוכחית, ואז עצור שוב.

· 'להיכנס'

רק לחיצה על Enter תבצע שוב את הפעולה האחרונה - זה מבורך מתי
לעבור דרך מיילים של קוד מקור.

· ptype

מדפיס את ההגדרה C של הטיעון שניתן.

(gdb) ptype PL_op
type = struct op {
OP *op_next;
OP *op_sibparent;
OP *(*op_ppaddr)(void);
PADOFFSET op_targ;
unsigned int op_type: 9;
unsigned int op_opt: 1;
unsigned int op_slabbed : 1;
unsigned int op_savefree : 1;
unsigned int op_static : 1;
unsigned int op_folded : 1;
unsigned int op_spare : 2;
U8 op_flags;
U8 op_private;
} *

· הדפס

בצע את קוד C הנתון והדפיס את תוצאותיו. אזהרה: פרל עושה בו שימוש רב
פקודות מאקרו, ו gdb אינו תומך בהכרח בפקודות מאקרו (ראה בהמשך "תמיכה במאקרו gdb").
תצטרך להחליף אותם בעצמך, או להפעיל cpp בקובצי קוד המקור (ראה
"מטרות .i") אז, למשל, אתה לא יכול לומר

הדפס SvPV_nolen(sv)

אבל אתה חייב לומר

הדפס Perl_sv_2pv_nolen(sv)

יכול להיות שיעזור לך להחזיק "מילון מאקרו", אותו תוכל להפיק על ידי אמירת "cpp
-dM perl.c | מיון". גם אז, cpp לא יחיל באופן רקורסיבי את פקודות המאקרו הללו עבורך.

gdb מאקרו תמיכה
גרסאות אחרונות של gdb יש תמיכת מאקרו טובה למדי, אבל כדי להשתמש בה תצטרך
להדר perl עם הגדרות מאקרו הכלולות במידע באגים. באמצעות gcc
גרסה 3.1, המשמעות היא הגדרה עם "-Doptimize=-g3". מהדרים אחרים עשויים להשתמש ב-a
מתג שונה (אם הם תומכים בכלל בפקודות מאקרו באגים).

הצפת שוק פרל נתונים מבנים
אחת הדרכים לעקוף את גיהינום המאקרו הזה היא להשתמש בפונקציות ההשלכה פנימה dump.c; אלה
עובדים קצת כמו Devel::Peek פנימי, אבל הם מכסים גם OPs ומבנים אחרים
שאתה לא יכול להגיע אליו מפרל. בואו ניקח דוגמה. נשתמש ב-"$a = $b + $c" אנחנו
בשימוש בעבר, אבל תן לו קצת הקשר: "$b = "6XXXX"; $c = 2.3;". איפה טוב
מקום לעצור ולחטט?

מה לגבי "pp_add", הפונקציה שבדקנו קודם כדי ליישם את האופרטור "+":

(gdb) break Perl_pp_add
נקודת שבירה 1 ב-0x46249f: קובץ pp_hot.c, שורה 309.

שימו לב שאנו משתמשים ב-"Perl_pp_add" ולא ב-"pp_add" - ראו "פונקציות פנימיות" ב-perlguts. עם
נקודת השבירה במקום, נוכל להפעיל את התוכנית שלנו:

(gdb) הרץ -e '$b = "6XXXX"; $c = 2.3; $a = $b + $c'

הרבה זבל יעבור בזמן ש-gdb יקרא בקבצי המקור והספריות הרלוונטיים, ו
לאחר מכן:

נקודת שבירה 1, Perl_pp_add () בכתובת pp_hot.c:309
309 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
(gdb) צעד
311 dPOPTOPnnrl_ul;
(gdb)

הסתכלנו על קטע הקוד הזה בעבר, ואמרנו ש"dPOPTOPnnrl_ul" מסדר שניים
יש למקם "NV" בין "שמאל" ו"ימין" - בואו נרחיב את זה מעט:

#define dPOPTOPnnrl_ul NV right = POPn; \
SV *leftsv = TOPs; \
NV left = USE_LEFT(leftsv) ? SvNV(leftsv) : 0.0

"POPn" לוקח את ה-SV מהחלק העליון של הערימה ומשיג את ה-NV שלו ישירות (אם
"SvNOK" מוגדר) או על ידי קריאה לפונקציה "sv_2nv". "TOPs" לוקח את ה-SV הבא מה-
בחלק העליון של הערימה - כן, "POPn" משתמש ב-"TOPs" - אבל לא מסיר אותו. לאחר מכן אנו משתמשים ב-"SvNV" כדי
קבל את ה-NV מ-"leftsv" באותו אופן כמו קודם - כן, "POPn" משתמש ב-"SvNV".

מכיוון שאין לנו NV עבור $b, נצטרך להשתמש ב-"sv_2nv" כדי להמיר אותו. אם נצעד
שוב, נמצא את עצמנו שם:

(gdb) צעד
Perl_sv_2nv (sv=0xa0675d0) בכתובת sv.c:1669
1669 if (!sv)
(gdb)

כעת נוכל להשתמש ב-"Perl_sv_dump" כדי לחקור את ה-SV:

(gdb) print Perl_sv_dump(sv)
SV = PV(0xa057cc0) at 0xa0675d0
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0xa06a510 "6XXXX"\0
CUR = 5
LEN = 6
$1 = בטל

אנחנו יודעים שאנחנו הולכים לקבל 6 מזה, אז בואו נסיים את תת-השגרה:

(gdb) לסיים
רץ עד היציאה מ-#0 Perl_sv_2nv (sv=0xa0675d0) בכתובת sv.c:1671
0x462669 ב-Perl_pp_add () בכתובת pp_hot.c:311
311 dPOPTOPnnrl_ul;

אנחנו יכולים גם לזרוק את ה-op הזה: ה-op הנוכחי תמיד מאוחסן ב-"PL_op", ואנחנו יכולים dump
זה עם "Perl_op_dump". זה ייתן לנו פלט דומה ל-B::Debug.

(gdb) print Perl_op_dump(PL_op)
{
13 TYPE = הוסף ===> 14
TARG = 1
דגלים = (סקאלר,ילדים)
{
TYPE = null ===> (12)
(היה rv2sv)
דגלים = (סקאלר,ילדים)
{
11 TYPE = gvsv ===> 12
דגלים = (סקלאר)
GV = main::b
}
}

# סיים את זה מאוחר יותר #

שימוש gdb ל להסתכל at ספציפי חלקים of a התוכנית
עם הדוגמה שלמעלה, ידעת לחפש "Perl_pp_add", אבל מה אם יש
שיחות מרובות אליו בכל מקום, או שלא ידעת מה האופציה שאתה
מחפש?

אחת הדרכים לעשות זאת היא להזריק שיחה נדירה איפשהו ליד מה שאתה מחפש. ל
לדוגמה, אתה יכול להוסיף "מחקר" לפני השיטה שלך:

לימוד;

וב-gdb תעשה:

(gdb) break Perl_pp_study

ואז צעד עד שתגיע למה שאתה מחפש. זה עובד היטב בלולאה אם ​​אתה
רוצה להישבר רק באיטרציות מסוימות:

עבור $c שלי (1..100) {
למד אם $c == 50;
}

שימוש gdb ל להסתכל at מה מה היא מנתח/לקסר יש לו עושה
אם אתה רוצה לראות מה Perl עושה בעת ניתוח/לקס הקוד שלך, אתה יכול להשתמש ב-"BEGIN
{}":

הדפס "לפני\n";
BEGIN { מחקר; }
הדפס "אחרי\n";

וב-gdb:

(gdb) break Perl_pp_study

אם אתה רוצה לראות מה המנתח/לקסר עושה בתוך בלוקים של "אם" וכדומה
צריך להיות קצת יותר מסובך:

if ($a && $b && do { BEGIN { study } 1 } && $c) { ... }

מקור CODE סטטיסטי אָנָלִיזָה


קיימים כלים שונים לניתוח קוד מקור C סטטית, בניגוד ל באופן דינמי,
כלומר, מבלי להפעיל את הקוד. אפשר לזהות דליפות משאבים, לא מוגדרות
התנהגות, אי התאמה בין סוגים, בעיות ניידות, נתיבי קוד שיגרמו לבלתי חוקיים
גישה לזיכרון ובעיות דומות אחרות רק על ידי ניתוח קוד C והסתכלות על
הגרף המתקבל, מה הוא אומר על הביצוע ועל זרימות הנתונים. כעניין של
למעשה, זה בדיוק איך מהדרים C יודעים לתת אזהרות לגבי קוד מפוקפק.

מוֹך, סַד
מפקח איכות קוד ה-C הישן והטוב, "מוך", זמין במספר פלטפורמות, אבל
אנא שים לב שיש כמה יישומים שונים שלו על ידי שונים
ספקים, מה שאומר שהדגלים אינם זהים בפלטפורמות שונות.

יש וריאנט מוך בשם "סד" (Secure Programming Lint) זמין מ
http://www.splint.org/ שאמור לקמפל על כל פלטפורמה דמוית Unix.

יש "מוך" ו מטרות ב-Makefile, אבל ייתכן שתצטרך להתעסק עם ה-
דגלים (ראה למעלה).

כיסוי
כיסוי (http://www.coverity.com/) הוא מוצר דומה למוך וכמיטת בדיקה עבור
את המוצר שלהם הם בודקים מעת לעת מספר פרויקטים של קוד פתוח, והם מוותרים
חשבונות למפתחי קוד פתוח לבסיסי הנתונים הפגומים.

cpd (חתוך והדבק גַלַאִי)
כלי ה-cpd מזהה קידוד גזור והדבק. אם מופע אחד של קוד החתך והדבק
שינויים, כנראה שגם את כל שאר הנקודות צריך לשנות. לכן קוד כזה צריך
כנראה יהפוך לתת-שגרה או מאקרו.

cpd (http://pmd.sourceforge.net/cpd.html) הוא חלק מפרויקט pmd
(http://pmd.sourceforge.net/). pmd נכתב במקור לניתוח סטטי של Java
קוד, אבל מאוחר יותר חלק ה-cpd שלו הורחב לנתח גם C ו-C++.

הורד את ה-pmd-bin-XYzip () מאתר SourceForge, חלץ את ה-pmd-XYjar מ
את זה, ואז הרץ את זה על קוד המקור כך:

java -cp pmd-XYjar net.sourceforge.pmd.cpd.CPD \
--minimum-tokens 100 --files /some/where/src --language c > cpd.txt

אתה עלול להיתקל במגבלות זיכרון, ובמקרה זה עליך להשתמש באפשרות -Xmx:

java -Xmx512M ...

gcc אזהרות
למרות שניתן לכתוב הרבה על חוסר העקביות ובעיות הכיסוי של אזהרות gcc
(כמו "-Wall" לא אומר "כל האזהרות", או כמה בעיות ניידות נפוצות לא
להיות מכוסה על ידי "-Wall", או "-ansi" ו-"-pedantic" שניהם מוגדרים בצורה גרועה
אוסף אזהרות, וכן הלאה), gcc הוא עדיין כלי שימושי בשמירה על הקידוד שלנו
אף נקי.

ה-"-Wall" פועל כברירת מחדל.

ה-"-ansi" (והצד שלו, "-pedantic") יהיה נחמד להיות בו תמיד, אבל
למרבה הצער, הם לא בטוחים בכל הפלטפורמות, הם יכולים למשל לגרום למוות
מתנגש עם כותרות המערכת (Solaris היא דוגמה מצוינת). אם הגדר
נעשה שימוש ב-"-Dgccansipedantic", הקצה הקדמי של "cflags" בוחר ב-"-ansi -pedantic" עבור
פלטפורמות שבהן ידוע שהם בטוחים.

החל מ-Perl 5.9.4 מתווספים הדגלים הנוספים הבאים:

· "-Wendif-labels"

· "-ווקסטרה"

· "-Wdeclaration-after-statement"

יהיה נחמד לקבל את הדגלים הבאים אבל הם יצטרכו קודם כל את אוג'אן משלהם
מאסטר אורוות:

· "-Wpointer-arith"

· "-Wshadow"

· "-Wstrict-אבות טיפוס"

ה-"-Wtraditional" הוא דוגמה נוספת לנטייה המעצבנת של gcc לאגד הרבה
אזהרות תחת מתג אחד (אי אפשר יהיה לפרוס אותו בפועל כי זה יהיה
להתלונן הרבה) אבל הוא מכיל כמה אזהרות שיהיה מועיל לקבל
זמין בפני עצמם, כגון האזהרה לגבי קבועי מחרוזת בתוך פקודות מאקרו
המכיל את ארגומנטי המאקרו: זה התנהג בצורה שונה לפני ANSI מאשר ב-ANSI,
וכמה מהדרים C עדיין במעבר, AIX הוא דוגמה.

אזהרות of אַחֵר C מהדרים
מהדרים אחרים של C (כן, שם יש לו למהדרי C אחרים מאשר gcc) יש לעתים קרובות את ה"מחמיר
מצבי ANSI" או "ANSI קפדני עם כמה הרחבות ניידות", כמו למשל השמש
לסדנה יש את מצב ה-"-Xa" שלה (אם כי באופן מרומז), או ל-DEC (בימים אלה, HP...)
מצב "-std1" מופעל.

זיכרון באגרים


הערה 1: פועל תחת מאגי זיכרון ישנים יותר כגון Purify, valgrind או Third Degree
מאט מאוד את הביצוע: שניות הופכות לדקות, דקות הופכות לשעות. ל
לדוגמה, החל מ-Perl 5.8.1, ה-ext/Encode/t/Unicode.t לוקח זמן רב במיוחד
להשלים תחת למשל Purify, Third Degree, ו-valgrind. תחת valgrind זה לוקח יותר מאשר
שש שעות, אפילו במחשב קלוש. המבחן האמור בטח עושה משהו די
לא ידידותי עבור מאפי זיכרון. אם לא בא לך לחכות, אתה יכול פשוט להרוג
להרחיק את תהליך perl. ולגרינד בערך מאט את הביצוע לפי פקטור 10,
AddressSnitizer לפי גורם 2.

הערה 2: כדי למזער את מספר אזעקות השווא של דליפת זיכרון (ראה "PERL_DESTRUCT_LEVEL" עבור
מידע נוסף), עליך להגדיר את משתנה הסביבה PERL_DESTRUCT_LEVEL ל-2. עבור
דוגמה, כך:

env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib ...

הערה 3: ישנן דליפות זיכרון ידועות כאשר יש שגיאות בזמן הידור בתוך eval or
require, לראות את "S_doeval" בערימת השיחות הוא סימן טוב לכך. תיקון הדליפות הללו
הוא לא טריוויאלי, למרבה הצער, אבל יש לתקן אותם בסופו של דבר.

הערה 4: DynaLoader לא ינקה אחרי עצמו לחלוטין אלא אם כן Perl נבנה עם
הגדר את האפשרות "-Accflags=-DDL_UNLOAD_ALL_AT_EXIT".

ולגרינד
ניתן להשתמש בכלי valgrind כדי לגלות גם דליפות זיכרון וגם זיכרון ערימה לא חוקי
גישה. החל מגרסה 3.3.0, Valgrind תומך רק ב-Linux ב-x86, x86-64 ו-PowerPC
ו-Darwin (OS X) ב-x86 ו-x86-64). ניתן להשתמש ביעד המיוחד "test.valgrind".
הרץ את הבדיקות תחת valgrind. נמצאו שגיאות ודליפות זיכרון נרשמות בקבצים בשם
testfile.valgrind וכברירת מחדל הפלט מוצג בשורה.

שימוש לדוגמא:

לעשות test.valgrind

מכיוון שלואלגרינד מוסיף תקורה משמעותית, ביצוע הבדיקות ייקח הרבה יותר זמן. ה
בדיקות valgrind תומכות בהפעלה במקביל כדי לעזור בכך:

TEST_JOBS=9 עשה test.valgrind

שים לב ששתי הפניות לעיל יהיו מאוד מילוליות כזיכרון נגיש ודליפה-
בדיקה מופעלת כברירת מחדל. אם אתה רוצה רק לראות שגיאות טהורות, נסה:

VG_OPTS='-q --leak-check=no --show-reachable=no' TEST_JOBS=9 \
לעשות test.valgrind

Valgrind מספק גם כלי cachegrind, המופעל ב-perl כ:

VG_OPTS=--tool=cachegrind לעשות test.valgrind

מכיוון שספריות מערכת (בעיקר glibc) גם מעוררות שגיאות, valgrind מאפשר זאת
לדכא שגיאות כאלה באמצעות קבצי דיכוי. קובץ הדיכוי המוגדר כברירת מחדל שמגיע
עם valgrind כבר תופס הרבה מהם. כמה דיכויים נוספים מוגדרים ב
t/perl.supp.

לקבלת valgrind ולמידע נוסף ראה

http://valgrind.org/

AddressSnitizer
AddressSanitizer היא הרחבה של clang ו-gcc, הכלולה ב-clang מאז v3.1 ו-gcc מאז
v4.8. זה בודק מצביעי ערימה לא חוקיים, מצביעים גלובליים, מצביעי מחסנית ושימוש לאחר חינם
שגיאות, והוא מהיר מספיק כדי שתוכל להרכיב בקלות את ניפוי הבאגים או את ה-perl המותאם
עם זה. זה לא בודק דליפות זיכרון. AddressSnitizer זמין עבור לינוקס,
Mac OS X ובקרוב ב-Windows.

כדי לבנות perl עם AddressSanitizer, הפצת Configure שלך ​​צריכה להיראות כך:

sh הגדר -des -Dcc=clang \
-Accflags=-faddress-sanitizer -Aldflags=-faddress-sanitizer \
-Alddlflags=-shared\ -faddress-sanitizer

כאשר הטיעונים הללו מתכוונים:

· -Dcc=clang

זה צריך להיות מוחלף על ידי הנתיב המלא לקובץ ההפעלה clang שלך אם הוא לא קיים שלך
נתיב.

· -Accflags=-faddress-sanitizer

הידור מקורות perl והרחבות עם AddressSanitizer.

· -Aldflags=-faddress-sanitizer

קשר את קובץ ההפעלה של perl עם AddressSanitizer.

· -Alddlflags=-shared\ -faddress-sanitizer

קשר הרחבות דינמיות עם AddressSanitizer. עליך לציין באופן ידני "-shared"
מכיוון ששימוש ב-"-Alddlflags=-shared" ימנע מ-Configure להגדיר ברירת מחדל
ערך עבור "lddlflags", שבדרך כלל מכיל "-shared" (לפחות בלינוקס).

ראה גםhttp://code.google.com/p/address-sanitizer/wiki/AddressSanitizer>.

פרופילינג


בהתאם לפלטפורמה שלך ישנן דרכים שונות ליצירת פרופיל של Perl.

ישנן שתי טכניקות נפוצות ליצירת פרופילי הפעלה: סטטיסטי דגימת זמן
ו בלוק בסיסי ספירה.

השיטה הראשונה לוקחת מדי פעם דגימות של מונה תוכניות המעבד, ומאז ה-
ניתן לתאם את מונה התוכנית עם הקוד שנוצר עבור פונקציות, נקבל א
תצוגה סטטיסטית באילו פונקציות התוכנית מבלה את זמנה. הסייגים הם
שלפונקציות קטנות/מהירות מאוד יש סבירות נמוכה יותר להופיע בפרופיל, ו
שמפסיקים את התוכנית מעת לעת (בדרך כלל זה נעשה לעתים קרובות למדי, ב-
בקנה מידה של אלפיות שניות) מטיל תקורה נוספת שעלולה להטות את התוצאות. ה
ניתן להקל על הבעיה הראשונה על ידי הפעלת הקוד למשך זמן ארוך יותר (באופן כללי זה טוב
רעיון ליצירת פרופילים), הבעיה השנייה נשמרת בדרך כלל על ידי כלי הפרופיל
עצמם.

השיטה השנייה מחלקת את הקוד שנוצר ל בסיסי אבני. בלוקים בסיסיים הם
קטעי קוד המוזנים רק בהתחלה ויוצאים רק בסוף. ל
לדוגמה, קפיצה מותנית מתחילה בלוק בסיסי. פרופיל בלוק בסיסי עובד בדרך כלל לפי
מכשור הקוד על ידי הוספה להיכנס בסיסי בלוק #nnnn קוד הנהלת חשבונות ל
קוד שנוצר. במהלך ביצוע הקוד מונים הבלוקים הבסיסיים הם אז
מעודכן כראוי. האזהרה היא שהקוד הנוסף שנוסף יכול להטות את התוצאות:
שוב, כלי הפרופיל בדרך כלל מנסים להביא את ההשפעות שלהם מתוך התוצאות.

גרופ פרופילים
gprof הוא כלי ליצירת פרופילים הזמין בפלטפורמות Unix רבות המשתמש סטטיסטי זְמַן-
דגימה. אתה יכול לבנות גרסה עם פרופיל של פרל על ידי קומפילציה באמצעות gcc עם הדגל
"-pg". או לערוך config.sh או להפעיל מחדש גדר. הפעלת הגרסה הפרופילית של Perl
תיצור קובץ פלט בשם gmon.out המכיל את נתוני הפרופיל שנאספו
במהלך ההוצאה להורג.

רמז מהיר:

$ sh הגדר -des -Dusedevel -Accflags='-pg' \
-Aldflags='-pg' -Alddlflags='-pg -shared' \
&& הפוך perl
$ ./perl ... # יוצר את gmon.out בספרייה הנוכחית
$ gprof ./perl > החוצה
$ פחות בחוץ

(כנראה עליך להוסיף "-shared" לשורת <-Alddlflags> עד ש-RT #118199 יהיה
נפתר)

השמיים gprof לאחר מכן הכלי יכול להציג את הנתונים שנאספו בדרכים שונות. בְּדֶרֶך כְּלַל gprof
מבין את האפשרויות הבאות:

· -א

דחק פונקציות מוגדרות סטטית מהפרופיל.

· -ב

הדחיק את התיאורים המילוליים בפרופיל.

· -ה שגרה

הסר את השגרה הנתונה ואת צאצאיה מהפרופיל.

· -f שגרה

הצג רק את השגרה הנתונה ואת צאצאיה בפרופיל.

· -ס

צור קובץ סיכום בשם gmon.sum אשר לאחר מכן ניתן לתת ל-gprof הבא
פועל לצבירת נתונים על פני מספר ריצות.

· -ז

הצג שגרות שיש בהן אפס שימוש.

להסבר מפורט יותר על הפקודות הזמינות ותבניות הפלט, ראה משלך
תיעוד מקומי של gprof.

GCC gcov פרופילים
בסיסי בלוק פרופיל זמין רשמית ב-gcc 3.0 ואילך. אתה יכול לבנות א
גרסה עם פרופיל של פרל על ידי קומפילציה באמצעות gcc עם הדגלים "-fprofile-arcs
-הכיסוי הגבוה ביותר". או ערוך config.sh או להפעיל מחדש גדר.

רמז מהיר:

$ sh הגדר -des -Dusedevel -Doptimize='-g' \
-Accflags='-fprofile-arcs -ftest-coverage' \
-Aldflags='-fprofile-arcs -ftest-coverage' \
-Alddlflags='-fprofile-arcs -ftest-coverage -shared' \
&& הפוך perl
$ rm -f regexec.c.gcov regexec.gcda
$ ./perl...
$ gcov regexec.c
$ פחות regexec.c.gcov

(כנראה עליך להוסיף "-shared" לשורת <-Alddlflags> עד ש-RT #118199 יהיה
נפתר)

הפעלת גרסת הפרופיל של Perl תגרום להפקת פלט פרופיל. לכל אחד
קובץ מקור נלווה .gcda ייווצר קובץ.

כדי להציג את התוצאות אתה משתמש ב- gcov כלי השירות (שאמור להתקין אם יש לך gcc
3.0 ואילך מותקן). gcov מופעל על קבצי קוד מקור, כמו זה

gcov sv.c

אשר יגרום sv.c.gcov להיווצר. ה .gcov קבצים מכילים את קוד המקור
עם הערות בתדרים יחסיים של ביצוע המצוינים בסמנים "#". אם אתה רוצה
ליצור .gcov קבצים עבור כל קבצי האובייקטים עם פרופיל, אתה יכול להריץ משהו כזה:

עבור קובץ ב- `find . -שם \*.gcno`
עשה sh -c "cd `dirname $file` && gcov `basename $file .gcno`"
עשה

אפשרויות שימושיות של gcov כולל "-b" אשר יסכם את הבלוק הבסיסי, ענף ו
כיסוי שיחות פונקציה, ו-"-c" שבמקום תדרים יחסיים ישתמשו בפועל
נחשב. למידע נוסף על השימוש ב gcov ופרופיל בלוק בסיסי עם gcc, ראה
המדריך העדכני ביותר של GNU CC. החל מ-gcc 4.8, זה ב-
<http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro>

שונות טריקים


PERL_DESTRUCT_LEVEL
אם ברצונך להריץ אחת מהבדיקות בעצמך באופן ידני באמצעות וולגרינד למשל, שים לב
זה כברירת מחדל perl עושה לֹא נקה במפורש את כל הזיכרון שהוקצתה (כגון
זירות זיכרון גלובליות) אלא מאפשרת את יציאה () של כל התוכנית "לדאוג" לכאלה
הקצאות, המכונה גם "השמדה גלובלית של חפצים".

יש דרך לומר ל-perl לבצע ניקוי מלא: הגדר את משתנה הסביבה
PERL_DESTRUCT_LEVEL לערך שאינו אפס. מעטפת t/TEST אכן מגדירה את זה ל-2, וזה
זה מה שאתה צריך לעשות גם, אם אתה לא רוצה לראות את "הדלפות גלובליות": לדוגמה, עבור
ריצה תחת ולגרינד

env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib t/foo/bar.t

(הערה: מודול ה-apache mod_perl משתמש גם במשתנה הסביבה הזה למטרותיו
והרחיב את הסמנטיקה שלו. עיין בתיעוד mod_perl למידע נוסף.
כמו כן, שרשורים שהורדו עושים את המקבילה להגדרת המשתנה הזה לערך 1.)

אם בסוף ריצה אתה מקבל את ההודעה N סקלרים דלף, אתה יכול לעשות קומפילציה מחדש עם
"-DDEBUG_LEAKING_SCALARS", מה שיגרום לכתובות של כל אותם SVs שדלפו להיות
נזרק יחד עם פרטים לגבי המקום שבו כל SV הוקצה במקור. המידע הזה
מוצג גם על ידי Devel::Peek. שים לב שהפרטים הנוספים שנרשמו עם כל SV
מגביר את השימוש בזיכרון, ולכן אין להשתמש בו בסביבות ייצור. זה גם
ממיר את "new_SV()" ממאקרו לפונקציה אמיתית, כך שתוכל להשתמש במועדף שלך
מאתר באגים כדי לגלות לאן הוקצו ה-SVs המציקים האלה.

אם אתה רואה שאתה מדליף זיכרון בזמן ריצה, אבל לא valgrind ולא
"-DDEBUG_LEAKING_SCALARS" ימצא הכל, אתה כנראה מדליף SVs שעדיין
נגיש וינוקה כראוי במהלך השמדת המתורגמן. בכזה
במקרים, שימוש במתג "-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" במקום זאת.

PERL_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", וב-
רמה גבוהה יותר; כל השימושים של Newx(), לְחַדֵשׁ(), ו Safefree() נרשמים אצל המתקשר
קובץ קוד מקור ומספר שורה (ושם פונקציית C, אם נתמך על ידי מהדר C).
לעומת זאת, "-Dm" נמצא ישירות בנקודה של "malloc()". רישום SV דומה.

מכיוון שהרישום אינו משתמש ב-PerlIO, כל הקצאות SV מתועדות ללא SV נוסף
הקצאות מוצגות על ידי הפעלת הרישום. אם הידור עם
"-DDEBUG_LEAKING_SCALARS", המספר הסידורי עבור כל הקצאת SV נרשם גם ביומן.

DDD יותר gdb
אלה שמגלים באגים ב-perl עם ה-DDD frontend מעל gdb עשויים למצוא את הדברים הבאים שימושיים:

אתה יכול להרחיב את תפריט קיצורי המרת הנתונים, כך למשל תוכל להציג SV's
ערך IV בלחיצה אחת, מבלי לבצע כל הקלדה. כדי לעשות זאת פשוט ערוך ~/.ddd/init
קובץ והוסף אחרי:

! הצג קיצורי דרך.
Ddd*gdbDisplayShortcuts: \
/t () // המר ל- Bin\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 level backtrace (בדומה למה שסימבולי
מאפי באגים כמו gdb עושים).

העקיבה האחורית מחזירה את עקבות המחסנית של מסגרות השיחה C, עם שמות הסמלים
(שמות פונקציות), שמות האובייקטים (כמו "perl"), ואם הוא יכול, גם קוד המקור
מיקומים (קובץ:שורה).

הפלטפורמות הנתמכות הן לינוקס ו-OS X (חלק מה-BSD עשוי לעבוד לפחות חלקית, אבל
הם עדיין לא נבדקו).

תכונה זו לא נבדקה עם שרשורים מרובים, אבל היא תציג רק את העקיבה האחורית
של החוט עושה את העקיבה לאחור.

יש להפעיל את התכונה עם "הגדר -Dusecbacktrace".

ה-"-Dusecbacktrace" מאפשר גם לשמור את מידע ניפוי הבאגים בעת הידור/קישור
(לעתים קרובות: "-g"). מהדרים/קישורים רבים אכן תומכים באופטימיזציה וגם בשמירה על
מידע על ניפוי באגים. יש צורך במידע על ניפוי הבאגים עבור שמות הסמלים והמקור
מיקומים.

ייתכן שפונקציות סטטיות לא יהיו גלויות עבור העקיבה האחורית.

מיקומי קוד המקור, גם אם הם זמינים, עלולים להיות חסרים או מטעים אם
למהדר יש למשל קוד מוטבע. כלי האופטימיזציה יכול לבצע התאמה בין קוד המקור ל-
קוד אובייקט די מאתגר.

לינוקס
אתה צריך יש להתקין את ספריית BFD (-lbfd), אחרת "perl" לא יצליח לקשר.
ה-BFD מופץ בדרך כלל כחלק מה-Binutils של GNU.

תקציר: "הגדר ... -Dusecbacktrace" ואתה צריך "-lbfd".

OS X
מיקומי קוד המקור נתמכים רק אם יש לך את כלי המפתחים
מוּתקָן. (BFD הוא לֹא נָחוּץ.)

תקציר: "הגדר ... -Dusecbacktrace" והתקנת כלי המפתחים יהיו
טוב.

לחלופין, כדי לנסות את התכונה, ייתכן שתרצה לאפשר השלכה אוטומטית של
עקבות אחורה ממש לפני שנפלטת הודעת אזהרה או קרקור (מות), על ידי הוספה
"-Accflags=-DUSE_C_BACKTRACE_ON_ERROR" עבור הגדר.

אלא אם התכונה הנוספת שלעיל מופעלת, שום דבר לגבי פונקציונליות המעקב לאחור
גלוי, למעט רמת Perl/XS.

יתר על כן, גם אם הפעלת את התכונה הזו להידור, עליך להפעיל אותה
בזמן ריצה עם משתנה סביבה: "PERL_C_BACKTRACE_ON_ERROR=10". זה חייב להיות
מספר שלם גבוה מאפס, אומר את ספירת הפריימים הרצויה.

אחזור ה-backtrace מרמת Perl (באמצעות למשל סיומת XS) יהיה הרבה
פחות מרגש ממה שאפשר לקוות: בדרך כלל תראה "רנופס", "אנטרסאב" ולא
הרבה יותר. API זה מיועד להיקרא החל מ- בתוך יישום Perl, לא
מביצוע ברמת Perl.

ה-API של C עבור המעקב האחורי הוא כדלקמן:

get_c_backtrace
free_c_backtrace
get_c_backtrace_dump
dump_c_backtrace

רעל
אם אתה רואה באיתור באגים אזור זיכרון מלא באופן מסתורי ב-0xABABABAB או 0xEFEFEFEF, אתה
אולי רואים את ההשפעה של רַעַל() פקודות מאקרו, ראה perlclib.

לקריאה בלבד אופטריות
מתחת ל-threads ה-optree נקרא לקריאה בלבד. אם אתה רוצה לאכוף את זה, כדי לבדוק אם יש כתיבה
גישה מקוד באגי, קומפלט עם "-Accflags=-DPERL_DEBUG_READONLY_OPS" כדי לאפשר
קוד שמקצה זיכרון אופ באמצעות "mmap", ומגדיר אותו לקריאה בלבד כאשר הוא מחובר ל-a
תת שגרה. כל גישת כתיבה לאופרציה גורמת ל"SIGBUS" ולביטול.

קוד זה מיועד לפיתוח בלבד, וייתכן שלא יהיה נייד אפילו לכל ה-Unix
גרסאות. כמו כן, זהו פתרון של 80%, בכך שהוא לא מסוגל להפוך את כל הפעולות לקריאה בלבד.
באופן ספציפי זה לא חל על לוחות הפעלה השייכים לבלוקים "BEGIN".

עם זאת, כפתרון של 80% הוא עדיין יעיל, מכיוון שהוא תפס באגים בעבר.

מתי is a bool לֹא 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 יעדים
אתה יכול להרחיב את פקודות המאקרו ב-a foo.c קובץ באמירה

לעשות foo.i

מה שירחיב את פקודות המאקרו באמצעות cpp. אל תפחד מהתוצאות.

השתמש ב-perlhacktips באינטרנט באמצעות שירותי onworks.net


שרתים ותחנות עבודה בחינם

הורד אפליקציות Windows & Linux

פקודות לינוקס

Ad




×
פרסומת
❤️קנו, הזמינו או קנו כאן - ללא עלות, עוזר לשמור על שירותים בחינם.