Aceasta este comanda perlhacktips care poate fi rulată în furnizorul de găzduire gratuit OnWorks folosind una dintre multiplele noastre stații de lucru online gratuite, cum ar fi Ubuntu Online, Fedora Online, emulator online Windows sau emulator online MAC OS
PROGRAM:
NUME
perlhacktips - Sfaturi pentru piratarea codului Perl core C
DESCRIERE
Acest document vă va ajuta să învățați cel mai bun mod de a proceda la hacking pe nucleul Perl C
cod. Acoperă probleme comune, depanare, profilare și multe altele.
Dacă nu ați citit încă perlhack și perlhacktut, poate doriți să faceți asta mai întâi.
COMUNĂ PROBLEME
Sursa Perl se joacă după regulile ANSI C89: nu există extensii C99 (sau C++). În unele cazuri trebuie
luați în considerare cerințele pre-ANSI. Nu-ți pasă de ceva anume
platforma a rupt Perl? Am auzit că există încă o cerere puternică pentru programatori J2EE.
Perl mediu inconjurator probleme
· Nu se compila cu threading
Compilarea cu threading (-Duseithreads) rescrie complet prototipurile funcției
a lui Perl. Mai bine încercați modificările cu asta. Legat de aceasta este diferența
între API-urile „Perl_-less” și „Perl_-ly”, de exemplu:
Perl_sv_setiv(aTHX_ ...);
sv_setiv(...);
Primul trece explicit în context, care este necesar, de exemplu, pentru threaded
construieste. Al doilea face asta implicit; nu le amesteca. Dacă nu ești
trecând un aTHX_, va trebui să faceți un dTHX (sau un dVAR) ca primul lucru în
Funcția.
Consultați „Cum sunt acceptate mai multe interpreți și concurență” în perlguts pentru mai multe
discuție despre context.
· Nu se compila cu -DDEBUGGING
Definiția DEBUGGING expune mai mult cod compilatorului, deci mai multe moduri de lucru
a greși. Ar trebui să încerci.
· Introducerea globală (non-read-only).
Nu introduceți globaluri modificabile, cu adevărat globale sau statice de fișiere. Sunt rai
formează și complică multithreadingul și alte forme de concurență. Calea corectă este
pentru a le introduce ca noi variabile interpretor, vezi intrpvar.h (la final pt
compatibilitate binară).
Introducerea globalelor (const) numai în citire este în regulă, atâta timp cât verificați cu, de exemplu, „nm
libperl.a|egrep -v ' [TURtr] '" (dacă „nm” dumneavoastră are ieșire în stil BSD) că datele pe care le
adăugat este într-adevăr doar pentru citire. (Dacă este, nu ar trebui să apară în rezultatul acestuia
comanda.)
Dacă doriți să aveți șiruri statice, faceți-le constante:
static const char etc[] = "...";
Dacă doriți să aveți matrice de șiruri constante, notați cu atenție combinația potrivită
de „const”-uri:
static const char * const yippee[] =
{"bună", "ho", "argint"};
Există o modalitate de a ascunde complet orice globală modificabilă (toate sunt mutate în heap),
setarea de compilare „-DPERL_GLOBAL_STRUCT_PRIVATE”. Nu este folosit în mod normal, dar
poate fi folosit pentru testare, citiți mai multe despre acesta în „Background and PERL_IMPLICIT_CONTEXT”
in perlguts.
· Nu se exportă noua funcție
Unele platforme (Win32, AIX, VMS, OS/2, pentru a numi câteva) necesită orice funcție care este
parte a API-ului public (biblioteca Perl partajată) să fie marcată în mod explicit ca exportată.
Vezi discutia despre încorporare.pl in perlguts.
· Exportați noua funcție
Noul rezultat strălucitor fie al unei noi funcționalități autentice, fie al refactoririi tale grele
este acum gata și exportat corect. Deci, ce ar putea merge prost?
Poate pur și simplu că funcția dvs. nu a trebuit să fie exportată în primul rând. Perl
are o istorie lungă și nu atât de glorioasă de export de funcții pe care nu ar trebui să o aibă.
Dacă funcția este utilizată numai în interiorul unui fișier cod sursă, faceți-o statică. Vezi
discuție despre încorporare.pl in perlguts.
Dacă funcția este utilizată în mai multe fișiere, dar destinată numai pentru interiorul lui Perl
folosiți (și acesta ar trebui să fie cazul obișnuit), nu îl exportați în API-ul public. Vezi
discuție despre încorporare.pl in perlguts.
Portabilitate probleme
Următoarele sunt cauze comune ale eșecurilor de compilare și/sau execuție, care nu sunt comune
Perl ca atare. Întrebările frecvente C reprezintă o lectură bună la culcare. Vă rugăm să testați modificările cu cât mai multe C
compilatoare și platforme posibil; vom face, oricum, și e frumos să te salvezi de
jenă publică.
Dacă utilizați gcc, puteți adăuga opțiunea „-std=c89” care, sperăm, va prinde majoritatea acestora
neportabilități. (Cu toate acestea, ar putea detecta și incompatibilități în antetul sistemului dvs
fișiere.)
Utilizați indicatorul Configurare „-Dgccansipedantic” pentru a activa steagurile gcc „-ansi -pedantic” care
să aplice reguli ANSI mai stricte.
Dacă utilizați „gcc -Wall” rețineți că nu toate avertismentele posibile (cum ar fi „-Wunitialized”)
sunt date cu excepția cazului în care compilați și cu „-O”.
Rețineți că, dacă utilizați gcc, pornind de la Perl 5.9.5 fișierele de cod sursă de bază Perl (cele
la nivelul superior al distribuției codului sursă, dar nu, de exemplu, extensiile din ext/)
sunt compilate automat cu cât mai multe dintre „-std=c89”, „-ansi”,
„-pedant”, și o selecție de steaguri „-W” (vezi cflags.SH).
De asemenea, studiați cu atenție perlport pentru a evita orice presupuneri greșite despre sistemul de operare,
sisteme de fișiere, seturi de caractere și așa mai departe.
Puteți încerca din când în când un „make microperl” pentru a vedea dacă mai putem compila Perl
cu doar minimul necesar de interfețe. (Consultați README.micro.)
Nu presupuneți că un sistem de operare indică un anumit compilator.
· Turnarea de indicatori la numere întregi sau turnarea de indicatori întregi la indicatori
naufrag gol (U8* p)
{
IV i = p;
or
naufrag gol (U8* p)
{
IV i = (IV)p;
Ambele sunt rele, stricate și neportabile. Folosește PTR2IV() macro care face bine.
(La fel, există PTR2UV(), PTR2NV(), INT2PTR() și NUM2PTR().)
· Casting între indicatori de funcție și indicatori de date
Din punct de vedere tehnic, turnarea dintre pointerii de funcție și pointerii de date este neportabilă
și nedefinit, dar practic vorbind pare să funcționeze, dar ar trebui să utilizați
FPTR2DPTR() și DPTR2FPTR() macro-uri. Uneori poți juca și cu sindicatele.
· Presupunând sizeof(int) == sizeof(long)
Există platforme în care lungurile sunt de 64 de biți și platforme în care interiurile sunt de 64 de biți și
în timp ce suntem gata să vă șocăm, chiar și platformele în care pantalonii scurti sunt de 64 de biți. Asta este tot
legal conform standardului C. (Cu alte cuvinte, „mult lung” nu este un mod portabil
pentru a specifica 64 de biți, iar „long long” nici măcar nu este garantat a fi mai larg decât
"lung".)
În schimb, utilizați definițiile IV, UV, IVSIZE, I32SIZE și așa mai departe. Evită lucruri precum
I32 pentru că sunt nu garantat a fi exact 32 de biți, sunt at cel mai puțin 32 de biți,
nici nu se garantează că vor fi int or lung. Dacă într-adevăr aveți nevoie în mod explicit de 64 de biți
variabile, utilizați I64 și U64, dar numai dacă sunt protejate de HAS_QUAD.
· Presupunând că se poate dereferi orice tip de pointer pentru orice tip de date
char *p = ...;
ponei lung = *p; /* RĂU */
Multe platforme, pe bună dreptate, îți vor oferi o gură de miez în loc de un ponei dacă p
se întâmplă să nu fie aliniat corect.
· Lvalue casts
(int)*p = ...; /* RĂU */
Pur și simplu nu portabil. Obțineți valoarea l pentru a fi de tipul potrivit sau poate utilizați temporar
variabile sau trucuri murdare cu sindicatele.
· Să presupunem nimic despre structuri (în special cele pe care nu le controlezi, precum cele
provenind din anteturile sistemului)
· Că un anumit câmp există într-o struct
· Că nu există alte domenii în afară de cele pe care le cunoști
· Că un câmp are o anumită semnificație, dimensiune sau tip
· Că câmpurile sunt într-o anumită ordine
· În timp ce C garantează ordonarea specificată în definiția structurii,
între diferite platforme, definițiile pot diferi
· Că dimensiunea (structurii) sau aliniamentele sunt aceleași peste tot
· Pot exista octeți de completare între câmpuri pentru a alinia câmpurile -
octeții pot fi orice
· Structurile trebuie să fie aliniate la alinierea maximă necesară
de câmpuri - care pentru tipurile native este de obicei echivalent cu
dimensiunea () a câmpului
· Presupunând că setul de caractere este ASCIIish
Perl poate compila și rula pe platformele EBCDIC. Vezi perlebcdic. Acest lucru este transparent
în cea mai mare parte, dar pentru că seturile de caractere diferă, nu ar trebui să utilizați numerele
constante (zecimale, octale sau hexadecimale) pentru a se referi la caractere. Puteți spune în siguranță „A”,
dar nu 0x41. Puteți spune în siguranță „\n”, dar nu „\012”. Cu toate acestea, puteți utiliza macrocomenzi
definit în utf8.h pentru a specifica orice punct de cod portabil. "LATIN1_TO_NATIVE(0xDF)" este
va fi punctul de cod care înseamnă LITERA MINUSCULĂ LATINĂ SHARP S pe orice platformă
pe care rulați (pe platformele ASCII se compila fără a adăuga niciun cod suplimentar, deci
nu există nicio lovitură de performanță pe acelea). Intrările acceptabile pentru „LATIN1_TO_NATIVE”
sunt de la 0x00 la 0xFF. Dacă nu se garantează că intrarea dvs. se află în acel interval, utilizați
În schimb, „UNICODE_TO_NATIVE”. „NATIVE_TO_LATIN1” și „NATIVE_TO_UNICODE” traduc
direcție opusă.
Dacă aveți nevoie de reprezentarea în șir a unui caracter care nu are un nume mnemonic
în C, ar trebui să-l adăugați la listă în regen/unicode_constants.pl, și au Perl
creați „#define” pentru dvs., pe baza platformei curente.
Rețineți că „esteFOO" și aFOO" macrouri în la îndemână.h funcționează corect pe codul nativ
puncte și șiruri.
De asemenea, intervalul „A” - „Z” în ASCII este o secvență neîntreruptă de 26 majuscule alfabetice
personaje. Acest lucru nu este adevărat în EBCDIC. Nici pentru „a” la „z”. Dar „0” - „9” este un
interval neîntrerupt în ambele sisteme. Nu presupuneți nimic despre alte game. (Rețineți că
manipularea specială a intervalelor în modelele de expresii regulate îl face să apară codului Perl
că intervalele menționate mai sus sunt toate neîntrerupte.)
Multe dintre comentariile din codul existent ignoră posibilitatea EBCDIC și pot fi
greșit așadar, chiar dacă codul funcționează. Acesta este de fapt un tribut adus succesului
inserarea transparentă pentru a putea gestiona EBCDIC fără a fi nevoie să schimbați pre-
codul existent.
UTF-8 și UTF-EBCDIC sunt două codificări diferite utilizate pentru a reprezenta punctele de cod Unicode
ca secvenţe de octeţi. Macrocomenzi cu aceleași nume (dar definiții diferite) în
utf8.h și utfebcdic.h sunt folosite pentru a permite codului de apel să creadă că există numai
o astfel de codificare. Acesta este aproape întotdeauna denumit „utf8”, dar înseamnă
De asemenea, versiunea EBCDIC. Din nou, comentariile din cod pot fi greșite chiar dacă
codul în sine este corect. De exemplu, conceptul de „caractere invariante” UTF-8
diferă între ASCII și EBCDIC. Pe platformele ASCII, doar caractere care nu
au setați biții de ordin înalt (adică ale căror ordinale sunt ASCII stricte, 0 - 127) sunt
invariant, iar documentația și comentariile din cod pot presupune că, adesea
referindu-se la ceva de genul, să zicem, „hibit”. Situația diferă și nu este atât de simplă
pe mașinile EBCDIC, dar atâta timp cât codul în sine folosește „NATIVE_IS_INVARIANT()”
macro în mod corespunzător, funcționează, chiar dacă comentariile sunt greșite.
După cum sa menționat în „TESTARE” în perlhack, atunci când scrieți scripturi de testare, fișierul
t/charset_tools.pl conține câteva funcții utile pentru scrierea de teste valabile pentru ambele
Platforme ASCII și EBCDIC. Uneori, totuși, un test nu poate folosi o funcție și este
incomod să existe versiuni de testare diferite în funcție de platformă. Sunt 20
puncte de cod care sunt aceleași în toate cele 4 seturi de caractere recunoscute în prezent de Perl
(cele 3 pagini de coduri EBCDIC plus ISO 8859-1 (ASCII/Latin1)). Acestea pot fi folosite în astfel de cazuri
teste, deși există o mică posibilitate ca Perl să devină disponibil încă
un alt set de caractere, depășind testul. Toate aceste puncte de cod, cu excepția unuia, sunt C0
caractere de control. Cele mai semnificative controale care sunt aceleași sunt „\0”, „\r”,
și „\N{VT}” (specificabil și ca „\cK”, „\x0B”, „\N{U+0B}” sau „\013”). Singurul
necontrolul este U+00B6 PILCROW SIGN. Comenzile care sunt aceleași au același bit
model în toate cele 4 seturi de caractere, indiferent de caracterul UTF8 al șirului care îl conține
lor. Modelul de biți pentru U+B6 este același în toate cele 4 pentru șirurile non-UTF8, dar diferă
în fiecare atunci când șirul său de conținut este codificat UTF-8. Singurul alt cod indică asta
au un fel de similaritate în toate cele 4 seturi de caractere sunt perechea 0xDC și 0xFC.
Împreună acestea reprezintă SCRISOA LATINA U CU DIAERESIS majuscule și mici, dar care
este superioară și care este mai mică poate fi inversată: 0xDC este capitalul în Latin1 și 0xFC este
litera mică, în timp ce 0xFC este capitala în EBCDIC și 0xDC este cea mică. Acest
factoid poate fi exploatat în scrierea de teste care nu țin seama de majuscule și minuscule, care sunt aceleași peste tot
toate cele 4 seturi de caractere.
· Presupunând că setul de caractere este doar ASCII
ASCII este o codificare de 7 biți, dar octeții au 8 biți în ei. Cele 128 de caractere suplimentare
au semnificații diferite în funcție de locație. Lipsă o locație, momentan acestea
caracterele suplimentare sunt, în general, considerate a fi nealocate, iar acest lucru a fost prezentat
câteva probleme. Acest lucru a fost modificat începând cu 5.12, astfel încât aceste personaje să poată
fi considerat a fi Latin-1 (ISO-8859-1).
· Amestecarea #define și #ifdef
#define BURGLE(x) ... \
#ifdef BURGLE_OLD_STYLE /* RĂU */
... fă-o pe vechiul mod... \
#altfel
... fă-o în modul nou... \
#endif
Nu puteți „stiva” în mod portabil directivele cpp. De exemplu, în cele de mai sus aveți nevoie de două
distinct JEFUI() #defines, câte unul pentru fiecare ramură #ifdef.
· Adăugarea de lucruri fără comentarii după #endif sau #else
#ifdef SNOSH
...
#else !SNOSH /* RĂU */
...
#endif SNOSH /* RĂU */
#endif și #else nu pot avea portabil nimic fără comentarii după ele. daca tu
vrei să documentezi ceea ce se întâmplă (ceea ce este o idee bună mai ales dacă ramurile sunt
lung), utilizați (C) comentarii:
#ifdef SNOSH
...
#else /* !SNOSH */
...
#endif /* SNOSH */
Opțiunea gcc „-Wendif-labels” avertizează despre varianta proastă (în mod implicit la pornire
din Perl 5.9.4).
· Avand o virgula dupa ultimul element al unei liste de enumerare
culoare enumerare {
ALBASTRU CA CERUL,
CHARTREUSE,
CINNABAR, /* RĂU */
};
nu este portabil. Lăsați deoparte ultima virgulă.
De asemenea, rețineți că dacă enumerarile sunt implicit transformabile în int variază între
compilatoare, poate fi necesar să (int).
· Utilizarea //-comentariilor
// Această funcție bamfoodles zorklatorul. /* RĂU */
Adică C99 sau C++. Perl este C89. Utilizarea //-commenturilor este permisă în tăcere de mulți C
compilatoare, dar creșterea strictității ANSI C89 (ceea ce ne place să facem) provoacă
compilarea eșuează.
· Amestecarea declaraţiilor şi codului
void zorklator()
{
int n = 3;
set_zorkmids(n); /* RĂU */
int q = 4;
Adică C99 sau C++. Unele compilatoare C permit asta, dar nu ar trebui.
Opțiunea gcc „-Wdeclaration-after-statements” scanează astfel de probleme (în mod implicit, activat
începând cu Perl 5.9.4).
· Introducerea variabilelor în interior pentru()
for(int i = ...; ...; ...) { /* RĂU */
Adică C99 sau C++. Deși ar fi într-adevăr îngrozitor de frumos să ai asta și în C89,
pentru a limita domeniul de aplicare al variabilei buclei, din păcate, nu putem.
· Amestecarea indicatorilor de caracter semnat cu indicatori de caracter nesemnați
int foo(car *s) { ... }
...
caracter nesemnat *t = ...; /* Sau U8* t = ... */
picior); /* RĂU */
Deși aceasta este o practică juridică, este cu siguranță dubioasă și de-a dreptul fatală cel puțin
o platformă: de exemplu, VMS cc consideră aceasta o eroare fatală. O singură cauză pentru oameni
Făcând adesea această greșeală, este că un „naked char” și, prin urmare, dereferențează un „naked
char pointer" au o semnătură nedefinită: depinde de compilator și de steaguri
a compilatorului și a platformei de bază, indiferent dacă rezultatul este semnat sau nesemnat.
Din același motiv, folosirea unui „char” ca index de matrice este proastă.
· Macro-urile care au constante și argumentele lor ca subșiruri ale șirului
constant
#define FOO(n) printf("number = %d\n", n) /* BAD */
FOO(10);
Semantica pre-ANSI pentru asta era echivalentă cu
printf("10number = %d\10");
ceea ce probabil nu este ceea ce te așteptai. Din pacate cel putin unul rezonabil
compilatorul C obișnuit și modern face „compatibilitate inversă reală” aici, adică în AIX
ce se întâmplă încă, chiar dacă restul compilatorului AIX este foarte fericit C89.
· Utilizarea formatelor printf pentru tipuri C non-bazice
IV i = ...;
printf("i = %d\n", i); /* RĂU */
În timp ce acest lucru ar putea lucra accidental pe o anumită platformă (unde IV se întâmplă să fie un „int”),
in general nu se poate. IV ar putea fi ceva mai mare. Și mai rău este cu situația
tipuri mai specifice (definite de pasul de configurare al lui Perl în config.h):
Uid_t cine = ...;
printf("cine = %d\n", cine); /* RĂU */
Problema aici este că Uid_t ar putea fi nu numai „int”-wide, dar ar putea fi și
nesemnat, caz în care uid-urile mari vor fi tipărite ca valori negative.
Nu există o soluție simplă pentru aceasta din cauza printf()inteligența lui limitată, dar
pentru multe tipuri, formatul potrivit este disponibil ca și cu sufixul „f” sau „_f”, pentru
exemplu:
IVdf /* IV în zecimală */
UVxf /* UV este hexazecimal */
printf("i = %"IVdf"\n", i); /* IVdf este o constantă șir. */
Uid_t_f /* Uid_t în zecimală */
printf("who = %"Uid_t_f"\n", cine);
Sau puteți încerca să difuzați într-un tip „suficient de larg”:
printf("i = %"IVdf"\n", (IV)ceva_foarte_mic_si_semnat);
Amintiți-vă, de asemenea, că formatul %p chiar necesită un pointer void:
U8* p = ...;
printf("p = %p\n", (void*)p);
Opțiunea gcc „-Wformat” scanează pentru astfel de probleme.
· Folosind orbește macro-uri variadice
gcc le are de ceva vreme cu propria sa sintaxă, iar C99 le-a adus cu a
sintaxă standardizată. Nu folosiți primul și folosiți cel din urmă numai dacă
HAS_C99_VARIADIC_MACROS este definit.
· Trecând orbește va_list
Nu toate platformele acceptă trecerea va_list către funcții ulterioare varargs (stdarg). The
lucrul corect de făcut este să copiați va_list folosind Perl_va_copy() dacă NEED_VA_COPY
este definit.
· Utilizarea expresiilor de instrucțiuni gcc
val = ({...;...;...}); /* RĂU */
Deși este o extensie frumoasă, nu este portabilă. Codul Perl, desigur, le folosește dacă
disponibil pentru a câștiga ceva viteză suplimentară (în esență ca o formă funky de inline), dar tu
nu ar trebui.
· Legarea mai multor instrucțiuni într-o macrocomandă
Utilizați macrocomenzile STMT_START și STMT_END.
STMT_START {
...
} STMT_END
· Testarea sistemelor de operare sau a versiunilor când ar trebui să fie testată funcțiile
#ifdef __FOONIX__ /* RĂU */
foo = quux();
#endif
Dacă nu știi cu 100% certitudine că quux() este disponibil doar pentru
Sistemul de operare „Foonix”. și care este disponibil și lucrand corect pentru toate trecut,
prezent, și versiunile viitoare ale „Foonix”, cele de mai sus sunt foarte greșite. Aceasta este mai mult
corect (deși încă nu este perfect, deoarece mai jos este o verificare în timp de compilare):
#ifdef HAS_QUUX
foo = quux();
#endif
Cum devine HAS_QUUX definit acolo unde trebuie să fie? Ei bine, dacă Foonix se întâmplă
să fie suficient de Unixy pentru a putea rula scriptul Configurare și Configurare a fost predat
despre detectarea și testarea quux(), HAS_QUUX va fi definit corect. In alta
platforme, pasul de configurare corespunzător va face același lucru.
Pe scurt, dacă nu poți aștepta ca Configure să fie educat sau dacă ai un bun
bănuială de unde quux() ar putea fi disponibil, puteți încerca temporar următoarele:
#if (definit(__FOONIX__) || definit(__BARNIX__))
# definește HAS_QUUX
#endif
...
#ifdef HAS_QUUX
foo = quux();
#endif
Dar, în orice caz, încercați să păstrați caracteristicile și sistemele de operare separate.
· Presupunând conținutul memoriei statice indicat de valorile returnate ale lui Perl
wrapper-urile pentru funcțiile bibliotecii C nu se schimbă. Multe funcții de bibliotecă C revin
pointeri către stocarea statică care poate fi suprascrisă prin apeluri ulterioare către același sau
funcții aferente. Perl are ambalaje ușoare pentru unele dintre aceste funcții și
care nu fac copii ale memoriei statice. Un bun exemplu este interfața către
variabilele de mediu care sunt în vigoare pentru program. Perl are „PerlEnv_getenv”
pentru a obține valori din mediu. Dar revenirea este un indicator către memoria statică în
biblioteca C. Dacă utilizați valoarea pentru a testa imediat ceva, asta este
bine, dar dacă salvați valoarea și vă așteptați să fie neschimbată prin procesarea ulterioară, dvs
ar fi greșit, dar poate că nu l-ați ști din cauza unei biblioteci C diferite
implementările se comportă diferit, iar cea de pe platforma pe care testați
ar putea funcționa pentru situația dvs. Dar pe unele platforme, un apel ulterior la
„PerlEnv_getenv” sau funcția asociată VA suprascrie memoria la care ați apelat primul
arata spre. Acest lucru a dus la unele probleme greu de depanat. Faceți un „savepv” în perlapi to
faceți o copie, evitând astfel aceste probleme. Va trebui să eliberați copia când sunteți
făcut pentru a evita scurgerile de memorie. Dacă nu ai control asupra momentului în care va fi eliberat, vei avea
trebuie să faceți copia într-un scalar mortal, așa:
if ((s = PerlEnv_getenv("foo") == NULL) {
... /* se ocupă de majuscule NULL */
}
altceva {
s = SvPVX(sv_2mortal(newSVpv(s, 0)));
}
Exemplul de mai sus funcționează numai dacă „s” este terminat cu „NUL”; altfel trebuie sa treci
lungimea sa la „newSVpv”.
Problematic Sistem Interfețe
· malloc(0), realloc(0), calloc(0, 0) nu sunt portabile. Pentru a fi portabil alocă la
cel puțin un octet. (În general, rareori ar trebui să aveți nevoie să lucrați la acest nivel scăzut, dar
folosiți în schimb diferitele ambalaje de malloc.)
· snprintf() - tipul de returnare este neportabil. Utilizare my_snprintf() in schimb.
Securitate probleme
Nu în ultimul rând, iată diverse sfaturi pentru o codare mai sigură. Vezi și perlclib pentru
înlocuiri libc/stdio pe care ar trebui să le folosiți.
· Nu folosi devine()
Sau vă vom ridiculiza în mod public. Serios.
· Nu folosi tmpfile()
Utilizare mkstemp() in schimb.
· Nu folosi strcpy() or strcat() or strncpy() or strncat()
Utilizare my_strlcpy() și my_strlcat() în schimb: folosesc fie implementarea nativă,
sau implementarea proprie Perl (împrumutată din implementarea domeniului public a INN).
· Nu folosi sprintf() or vsprintf()
Dacă într-adevăr doriți doar șiruri de octeți simpli, utilizați my_snprintf() și my_vsnprintf()
în schimb, care va încerca să folosească snprintf() și vsnprintf() dacă acele API-uri mai sigure sunt
disponibil. Dacă doriți ceva mai elegant decât un șir simplu de octeți, utilizați „Perl_form”()
sau SV-uri și „Perl_sv_catpvf()”.
Rețineți că glibc „printf()”, „sprintf()”, etc. au probleme înainte de versiunea glibc 2.17.
Nu vor permite un format „%.s” cu o precizie pentru a crea un șir care nu este valid
UTF-8 dacă localitatea actuală de bază a programului este UTF-8. Ce se întâmplă este că
%s și operandul său sunt pur și simplu ignorate fără nicio notificare.
.
· Nu folosi atoi()
Utilizare grok_atoUV() in schimb. atoi() are un comportament nedefinit la debordări și nu poate fi
folosit pentru analiza incrementală. Este, de asemenea, afectat de local, ceea ce este rău.
· Nu folosi strtol() or strtoul()
Utilizare grok_atoUV() in schimb. strtol() or strtoul() (sau macroul lor prietenos cu IV/UV
deghizări, Strtol() și Strtoul(), Atol() și Atoul() sunt afectate de local, care
este rău.
DEBUGARE
Puteți compila o versiune specială de depanare a Perl, care vă permite să utilizați „-D”
opțiunea Perl pentru a spune mai multe despre ceea ce face Perl. Dar uneori nu există
alternativă decât să te scufundi cu un depanator, fie pentru a vedea urmele stivei a unui dump de miez
(foarte util într-un raport de eroare) sau încercarea de a afla ce a mers prost înainte de nucleu
s-a întâmplat descărcarea sau cum am ajuns să avem rezultate greșite sau neașteptate.
poking at Perl
Pentru a căuta cu adevărat cu Perl, probabil că veți dori să construiți Perl pentru depanare, cum ar fi
acest:
./Configurare -d -D optimize=-g
face
„-g” este un indicator pentru compilatorul C pentru ca acesta să producă informații de depanare care să permită
să parcurgem un program care rulează și să vedem în ce funcție C ne aflăm (fără
informațiile de depanare am putea vedea doar adresele numerice ale funcțiilor,
ceea ce nu este de mare ajutor).
Configurați va activa, de asemenea, simbolul de compilare „DEBUGGING” care activează toate
cod intern de depanare în Perl. Există o grămadă de lucruri cu care puteți depana
asta: perlrun le listează pe toate, iar cel mai bun mod de a afla despre ele este să te joci
cu ei. Cele mai utile opțiuni sunt probabil
l Procesarea stivei de context (buclă).
t Urmărirea execuției
o Metoda și rezoluția supraîncărcării
c Conversii șir/numerice
O parte din funcționalitatea codului de depanare poate fi realizată folosind module XS.
-Dr => folosește re „debug”
-Dx => folosește O „Debug”
Utilizarea a la nivel de sursă debugger
Dacă rezultatul de depanare a lui „-D” nu vă ajută, este timpul să treceți prin perl
execuție cu un depanator la nivel de sursă.
· Vom folosi „gdb” pentru exemplele noastre de aici; principiile se vor aplica oricărui depanator (mulți
furnizorii își numesc depanatorul „dbx”), dar verificați manualul celui pe care îl utilizați.
Pentru a porni depanatorul, tastați
gdb ./perl
Sau dacă aveți o descărcare de bază:
gdb ./perl core
Veți dori să faceți asta în arborele sursă Perl, astfel încât depanatorul să poată citi codul sursă.
Ar trebui să vedeți mesajul privind drepturile de autor, urmat de solicitarea.
(gdb)
„ajutor” vă va introduce în documentație, dar iată cele mai utile comenzi:
· rulează [args]
Rulați programul cu argumentele date.
· break function_name
· break source.c:xxx
Spune depanatorului că vom dori să întrerupem execuția atunci când ajungem la unul numit
funcția (dar vezi „Funcții interne” în perlguts!) sau linia dată în named
fișier sursă.
· Etapa
Parcurge programul pe rând.
· Următorul
Parcurge programul pe rând, fără a coborî în funcții.
· continua
Rulați până la următorul punct de întrerupere.
· finalizarea
Rulați până la sfârșitul funcției curente, apoi opriți-vă din nou.
· 'introduce'
Doar apăsarea Enter va face din nou cea mai recentă operațiune - este o binecuvântare când
pășind prin mile de cod sursă.
· tipul p
Tipărește definiția C a argumentului dat.
(gdb) ptype PL_op
tip = 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;
} *
· imprimare
Executați codul C dat și imprimați rezultatele acestuia. AVERTISMENT: Perl folosește intens
macro-uri și gDB nu acceptă neapărat macrocomenzi (vezi mai târziu „suport macro gdb”).
Va trebui să le înlocuiți singur sau să invocați cpp în fișierele codului sursă (vezi
„Țintele .i”) Deci, de exemplu, nu puteți spune
tipăriți SvPV_nolen(sv)
dar trebuie să spui
print Perl_sv_2pv_nolen(sv)
S-ar putea să vă fie util să aveți un „dicționar macro”, pe care îl puteți produce spunând „cpp
-dM perl.c | sortați". Chiar și atunci, cpp nu va aplica recursiv acele macrocomenzi pentru dvs.
gDB macro a sustine
Versiunile recente ale gDB au un suport macro destul de bun, dar pentru a-l folosi vei avea nevoie
pentru a compila perl cu definițiile macro incluse în informațiile de depanare. Folosind gcc
versiunea 3.1, aceasta înseamnă configurarea cu „-Doptimize=-g3”. Alți compilatori ar putea folosi a
comutator diferit (dacă acceptă macrocomenzi de depanare).
Dumping Perl Date Structuri
O modalitate de a ocoli acest macro iad este să folosești funcțiile de dumping în haldă.c; aceste
funcționează puțin ca un Devel::Peek intern, dar acoperă și OP-uri și alte structuri
la care nu poți ajunge de la Perl. Să luăm un exemplu. Vom folosi „$a = $b + $c” noi
folosit înainte, dar dă-i puțin context: „$b = „6XXXX”; $c = 2.3;”. Unde este un bun
loc unde să te oprești și să umbli?
Ce zici de „pp_add”, funcția pe care am examinat-o mai devreme pentru a implementa operatorul „+”:
(gdb) break Perl_pp_add
Punct de întrerupere 1 la 0x46249f: fișier pp_hot.c, linia 309.
Observați că folosim „Perl_pp_add” și nu „pp_add” - vedeți „Funcții interne” în perlguts. Cu
punctul de întrerupere în loc, putem rula programul nostru:
(gdb) run -e '$b = "6XXXX"; $c = 2.3; $a = $b + $c'
O mulțime de mesaje nedorite vor trece pe măsură ce gdb citește în fișierele și bibliotecile sursă relevante și
apoi:
Punct de întrerupere 1, Perl_pp_add () la pp_hot.c:309
309 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
(gdb) pas
311 dPOPTOPnnrl_ul;
(gdb)
Ne-am uitat la acest fragment de cod înainte și am spus că „dPOPTOPnnrl_ul” aranjează două
„NV” trebuie plasat în „stânga” și „dreapta” - să-l extindem ușor:
#define dPOPTOPnnrl_ul NV dreapta = POPn; \
SV *leftsv = TOP-uri; \
NV stânga = USE_LEFT(leftsv) ? SvNV(leftsv): 0.0
„POPn” ia SV din partea de sus a stivei și își obține NV-ul fie direct (dacă
„SvNOK” este setat) sau apelând funcția „sv_2nv”. „TOPs” ia următorul SV de la
partea de sus a stivei - da, "POPn" folosește "TOP-uri" - dar nu îl elimină. Apoi folosim „SvNV” pentru
obțineți NV de la „leftsv” în același mod ca înainte - da, „POPn” folosește „SvNV”.
Deoarece nu avem un NV pentru $b, va trebui să folosim „sv_2nv” pentru a-l converti. Dacă pășim
din nou, ne vom găsi acolo:
(gdb) pas
Perl_sv_2nv (sv=0xa0675d0) la sv.c:1669
1669 dacă (!sv)
(gdb)
Acum putem folosi „Perl_sv_dump” pentru a investiga SV:
(gdb) print Perl_sv_dump(sv)
SV = PV(0xa057cc0) at 0xa0675d0
REFCNT = 1
DRAPEURI = (POK,pPOK)
PV = 0xa06a510 „6XXXX”\0
CUR = 5
LEN = 6
$1 = nul
Știm că vom obține 6 din asta, așa că să terminăm subrutina:
(gdb) termina
Rulați până la ieșirea din #0 Perl_sv_2nv (sv=0xa0675d0) la sv.c:1671
0x462669 în Perl_pp_add () la pp_hot.c:311
311 dPOPTOPnnrl_ul;
Putem, de asemenea, descărca această operațiune: operațiunea curentă este întotdeauna stocată în „PL_op”, și putem descărca
cu „Perl_op_dump”. Acest lucru ne va oferi rezultate similare cu B::Debug.
(gdb) print Perl_op_dump(PL_op)
{
13 TIP = adaugă ===> 14
TARG = 1
DRAPEURI = (SCALAR,COPII)
{
TIP = nul ===> (12)
(a fost rv2sv)
DRAPEURI = (SCALAR,COPII)
{
11 TIP = gvsv ===> 12
DRAPEURI = (SCALAR)
GV = principal::b
}
}
# termina asta mai târziu #
Utilizarea gDB la uite at specific piese of a program
Cu exemplul de mai sus, știai să cauți „Perl_pp_add”, dar dacă ar exista
mai multe apeluri la el peste tot, sau nu știai ce operațiune erai
caut?
O modalitate de a face acest lucru este să injectați un apel rar undeva lângă ceea ce căutați. Pentru
De exemplu, puteți adăuga „studiu” înainte de metoda dvs.:
studiu;
Și în gdb faceți:
(gdb) break Perl_pp_study
Și apoi păși până când atingi ceea ce cauți. Acest lucru funcționează bine într-o buclă dacă dvs
doresc să se întrerupă numai la anumite iterații:
pentru $c-ul meu (1..100) {
studiază dacă $c == 50;
}
Utilizarea gDB la uite at ceea ce il parser/lexer sunt face
Dacă doriți să vedeți ce face perl atunci când vă analizați/lexați codul, puteți folosi „BEGIN
{}":
imprimați „Înainte de\n”;
BEGIN { studiul; }
imprimă „După\n”;
Și în gdb:
(gdb) break Perl_pp_study
Dacă doriți să vedeți ce face analizatorul/lexerul în interiorul blocurilor „dacă” și altele asemenea
trebuie să fie puțin mai complicat:
dacă ($a && $b && face { BEGIN { studiul } 1 } && $c) { ... }
SOURCE COD STATIC ANALIZĂ
Există diverse instrumente pentru analiza codului sursă C static, spre deosebire de dinamic,
adică fără a executa codul. Este posibil să se detecteze scurgeri de resurse, nedefinite
comportament, nepotriviri de tip, probleme de portabilitate, căi de cod care ar cauza ilegalitate
accese la memorie și alte probleme similare doar analizând codul C și uitându-ne la
graficul rezultat, ce spune despre execuție și fluxurile de date. Ca o chestiune de
De fapt, exact așa știu compilatorii C să dea avertismente despre codul dubios.
puf, atelă
Vechiul vechi inspector de calitate a codului C, „lint”, este disponibil pe mai multe platforme, dar
Vă rugăm să fiți conștienți de faptul că există mai multe implementări diferite ale acestuia
furnizori, ceea ce înseamnă că steagurile nu sunt identice pe diferite platforme.
Există o variantă de scame numită „splint” (Secure Programming Lint) disponibilă de la
http://www.splint.org/ care ar trebui să fie compilat pe orice platformă asemănătoare Unix.
Există „scame” și ținte în Makefile, dar este posibil să fiți nevoit să vă ocupați de
steaguri (vezi mai sus).
Acoperire
Acoperire (http://www.coverity.com/) este un produs asemănător scamelor și ca banc de testare pentru
produsul lor verifică periodic mai multe proiecte open source și dau afară
conturi către dezvoltatorii open source la bazele de date cu defecte.
cpd (tăiat și lipiți detector)
Instrumentul cpd detectează codificarea tăiere și lipire. Dacă o instanță a codului tăiat și lipit
modificări, toate celelalte puncte ar trebui probabil schimbate, de asemenea. Prin urmare, un astfel de cod ar trebui
probabil să fie transformată într-o subrutină sau într-o macro.
cpd (http://pmd.sourceforge.net/cpd.html) face parte din proiectul pmd
(http://pmd.sourceforge.net/). pmd a fost scris inițial pentru analiza statică a Java
cod, dar mai târziu partea cpd a fost extinsă pentru a analiza și C și C++.
Descărcați pmd-bin-XYzip () de pe site-ul SourceForge, extrageți pmd-XYjar din
și apoi rulați-l pe codul sursă astfel:
java -cp pmd-XYjar net.sourceforge.pmd.cpd.CPD \
--minimum-tokens 100 --files /some/where/src --language c > cpd.txt
Puteți întâlni limite de memorie, caz în care ar trebui să utilizați opțiunea -Xmx:
java -Xmx512M...
gcc avertismente
Deși se pot scrie multe despre inconsecvența și problemele de acoperire ale avertismentelor gcc
(cum ar fi „-Wall” care nu înseamnă „toate avertismentele”, sau unele probleme comune de portabilitate nu
fiind acoperit de „-Wall”, sau „-ansi” și „-pedant” ambele fiind un tip slab definit
colectare de avertismente și așa mai departe), gcc este încă un instrument util în păstrarea codificării noastre
nasul curat.
„-Wall” este activat implicit.
„-ansi” (și tovarasul său, „-pedant”) ar fi plăcut să fie mereu, dar
din păcate, nu sunt sigure pe toate platformele, pot provoca de exemplu fatale
intră în conflict cu anteturile sistemului (Solaris fiind un prim exemplu). Dacă Configurați
Se folosește „-Dgccansipedantic”, frontend-ul „cflags” selectează „-ansi -pedantic” pentru
platforme în care se știe că sunt sigure.
Începând cu Perl 5.9.4, sunt adăugate următoarele steaguri suplimentare:
· „-Wendif-labels”
· „-Wextra”
· „-Wdeclaration-after-statement”
Următoarele steaguri ar fi plăcut să aibă, dar mai întâi ar avea nevoie de propriul lor Augean
stablemaster:
· „-Wpointer-arith”
· „-Wshadow”
· „-Wstrict-prototipuri”
„-Wtraditional” este un alt exemplu al tendinței enervante a gcc de a grupa o mulțime de
avertismente sub un singur comutator (ar fi imposibil de implementat în practică, deoarece ar fi
se plâng foarte mult) dar conține unele avertismente pe care ar fi benefic să le ai
disponibile pe cont propriu, cum ar fi avertismentul despre constantele șirurilor din macrocomenzi
care conține argumentele macro: aceasta s-a comportat diferit înainte de ANSI decât în ANSI,
iar unele compilatoare C sunt încă în tranziție, AIX fiind un exemplu.
Avertismente of alte C compilatoare
Alte compilatoare C (da, acolo sunt alte compilatoare C decât gcc) au adesea „strict
Modurile ANSI” sau „ANSI strict cu unele extensii de portabilitate” activate, cum ar fi, de exemplu, Sun
Workshop-ul are modul „-Xa” activat (deși implicit), sau DEC (zile astea, HP...) are
Modul „-std1” activat.
MEMORIE DEBUGERE
NOTĂ 1: Rulează sub depanatoare de memorie mai vechi, cum ar fi Purify, valgrind sau Third Degree
încetinește foarte mult execuția: secundele devin minute, minutele devin ore. Pentru
exemplu din Perl 5.8.1, ext/Encode/t/Unicode.t durează extraordinar de mult
complet sub de exemplu Purify, Third Degree și valgrind. Sub valgrind este nevoie de mai mult de
șase ore, chiar și pe un computer rapid. Testul menționat trebuie să facă ceva care este destul
neprietenos pentru depanatorii de memorie. Dacă nu ai chef să aștepți, poți pur și simplu să ucizi
îndepărtați procesul perl. Aproximativ valgrind încetinește execuția cu un factor de 10,
Adresați Sanitizer prin factor 2.
NOTĂ 2: Pentru a minimiza numărul de alarme false cu scurgeri de memorie (consultați „PERL_DESTRUCT_LEVEL” pentru
mai multe informații), trebuie să setați variabila de mediu PERL_DESTRUCT_LEVEL la 2. Pentru
exemplu, așa:
env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib...
NOTĂ 3: Există scurgeri de memorie cunoscute atunci când există erori de compilare în eval sau
necesită, a vedea „S_doeval” în stiva de apeluri este un semn bun al acestora. Remedierea acestor scurgeri
nu este banal, din păcate, dar trebuie remediate în cele din urmă.
NOTĂ 4: DynaLoader nu va curăța complet după sine decât dacă Perl este construit cu
Configurați opțiunea „-Accflags=-DDL_UNLOAD_ALL_AT_EXIT”.
valgrind
Instrumentul valgrind poate fi folosit pentru a afla atât pierderile de memorie, cât și memoria heap ilegală
accese. Începând cu versiunea 3.3.0, Valgrind acceptă Linux numai pe x86, x86-64 și PowerPC
și Darwin (OS X) pe x86 și x86-64). Ținta specială „test.valgrind” poate fi folosită pentru
rulați testele sub valgrind. Erorile găsite și pierderile de memorie sunt înregistrate în fișierele numite
testfile.valgrind iar rezultatul implicit este afișat inline.
Exemplu de utilizare:
face test.valgrind
Deoarece valgrind adaugă o suprasarcină semnificativă, testele vor dura mult mai mult. The
Testele valgrind susțin rularea în paralel pentru a ajuta la aceasta:
TEST_JOBS=9 face test.valgrind
Rețineți că cele două invocări de mai sus vor fi foarte detaliate ca memorie accesibilă și scurgeri
verificarea este activată în mod implicit. Dacă doriți să vedeți erorile pure, încercați:
VG_OPTS='-q --leak-check=nu --show-reachable=nu' TEST_JOBS=9 \
face test.valgrind
Valgrind oferă, de asemenea, un instrument cachegrind, invocat pe perl ca:
VG_OPTS=--tool=cachegrind make test.valgrind
Deoarece bibliotecile de sistem (în special glibc) declanșează și erori, valgrind permite acest lucru
suprimați astfel de erori folosind fișiere de suprimare. Fișierul implicit de suprimare care vine
cu valgrind prinde deja multe dintre ele. Unele suprimări suplimentare sunt definite în
t/perl.supp.
Pentru a obține valgrind și pentru mai multe informații vezi
http://valgrind.org/
AdresăSanitizer
AddressSanitizer este o extensie clang și gcc, inclusă în clang începând cu v3.1 și gcc de atunci
v4.8. Verifică indicatori de heap ilegale, indicatori globale, indicatori de stivă și folosiți după gratuit
erori și este suficient de rapid încât să vă puteți compila cu ușurință depanarea sau perl optimizat
Cu acesta. Totuși, nu verifică scurgerile de memorie. AddressSanitizer este disponibil pentru Linux,
Mac OS X și în curând pe Windows.
Pentru a construi Perl cu AddressSanitizer, invocarea dvs. Configurare ar trebui să arate astfel:
sh Configurare -des -Dcc=clang \
-Accflags=-faddress-sanitizer -Aldflags=-faddress-sanitizer \
-Alddlflags=-shared\ -faddress-dezinfectant
unde aceste argumente înseamnă:
· -Dcc=clang
Aceasta ar trebui să fie înlocuită cu calea completă către executabilul dvs. clang dacă nu este în dvs
cale.
· -Accflags=-faddress-sanitizer
Compilați sursele perl și extensii cu AddressSanitizer.
· -Aldflags=-faddress-dezinfectant
Conectați executabilul perl cu AddressSanitizer.
· -Alddlflags=-shared\ -faddress-sanitizer
Conectați extensiile dinamice cu AddressSanitizer. Trebuie să specificați manual „-shared”
deoarece folosirea „-Alddlflags=-shared” va împiedica Configurarea să stabilească o valoare implicită
valoare pentru „lddlflags”, care conține de obicei „-shared” (cel puțin pe Linux).
Vezi sihttp://code.google.com/p/address-sanitizer/wiki/AddressSanitizer>.
PROFILARE
În funcție de platforma dvs., există diferite moduri de profilare Perl.
Există două tehnici frecvent utilizate de profilare a executabilelor: statistic eșantionare în timp
și bloc de bază socoteală.
Prima metodă preia periodic mostre ale contorului programului CPU, iar de la
contorul programului poate fi corelat cu codul generat pentru funcții, obținem a
vedere statistică a funcțiilor în care programul își petrece timpul. Avertismentele sunt
că funcțiile foarte mici/rapide au o probabilitate mai mică de a apărea în profil și
care întrerupe periodic programul (acest lucru se face de obicei destul de frecvent, în
scară de milisecunde) impune o suprasarcină suplimentară care poate denatura rezultatele. The
prima problemă poate fi atenuată rulând codul mai mult timp (în general, acesta este un lucru bun
idee pentru profilare), a doua problemă este de obicei ținută în pază de instrumentele de profilare
înșiși.
A doua metodă împarte codul generat în de bază blocuri. Blocurile de bază sunt
secțiuni de cod care sunt introduse doar la început și ieșite doar la sfârșit. Pentru
de exemplu, un salt condiționat începe un bloc de bază. Profilarea de bază a blocurilor funcționează de obicei prin
instrumentare codul prin adăugare introduce de bază bloca #nnnn codul de contabilitate la
codul generat. În timpul executării codului, contoarele de bloc de bază sunt atunci
actualizat corespunzător. Avertismentul este că codul suplimentar adăugat poate modifica rezultatele:
din nou, instrumentele de profilare încearcă de obicei să-și factorizeze propriile efecte din rezultate.
Gprof profilat
gprof este un instrument de profilare disponibil în multe platforme Unix care utilizează statistic timp-
prelevare de probe. Puteți crea o versiune profilată a perl prin compilare folosind gcc cu steag
„-pg”. Fie editați config.sh sau reluați Configurați. Rularea versiunii profilate de Perl
va crea un fișier de ieșire numit gmon.out care conține datele de profilare colectate
in timpul executiei.
indiciu rapid:
$ sh Configure -des -Dusedevel -Accflags='-pg' \
-Aldflags='-pg' -Alddlflags='-pg -shared' \
&& face perl
$ ./perl ... # creează gmon.out în directorul curent
$ gprof ./perl > out
$ mai puțin afară
(probabil trebuie să adăugați „-shared” la linia <-Alddlflags> până când RT #118199 este
rezolvat)
gprof instrumentul poate afișa apoi datele colectate în diferite moduri. Obișnuit gprof
înțelege următoarele opțiuni:
· -A
Suprimați funcțiile definite static din profil.
· -b
Suprimați descrierile detaliate din profil.
· -e rutină
Excludeți rutina dată și descendenții acesteia din profil.
· -f rutină
Afișați numai rutina dată și descendenții acesteia în profil.
· -s
Generați un fișier rezumat numit gmon.sum care apoi poate fi dat gprof
rulează pentru a acumula date în mai multe rulări.
· -z
Afișează rutine care nu au utilizare.
Pentru o explicație mai detaliată a comenzilor disponibile și a formatelor de ieșire, consultați-vă pe propria dvs
documentația locală a gprof.
CGC gcov profilat
de bază bloca profilare este disponibil oficial în gcc 3.0 și ulterioare. Puteți construi un
versiune profilată a perl prin compilare folosind gcc cu steagurile „-fprofile-arcs
-ftest-coverage". Fie editați config.sh sau reluați Configurați.
indiciu rapid:
$ sh Configure -des -Dusedevel -Doptimize='-g' \
-Accflags='-fprofile-arcs -ftest-coverage' \
-Aldflags='-fprofile-arcs -ftest-coverage' \
-Alddlflags='-fprofile-arcs -ftest-coverage -shared' \
&& face perl
$ rm -f regexec.c.gcov regexec.gcda
$ ./perl...
$ gcov regexec.c
$ mai puțin regexec.c.gcov
(probabil trebuie să adăugați „-shared” la linia <-Alddlflags> până când RT #118199 este
rezolvat)
Rularea versiunii profilate a Perl va genera ieșirea profilului. Pentru fiecare
fișier sursă și însoțitor .gcda fișierul va fi creat.
Pentru a afișa rezultatele utilizați gcov utilitar (care ar trebui instalat dacă aveți gcc
3.0 sau mai nou instalat). gcov este rulat pe fișiere de cod sursă, ca acesta
gcov sv.c
care va cauza sv.c.gcov a fi creat. The .gcov fișierele conțin codul sursă
adnotate cu frecvențele relative de execuție indicate prin markeri „#”. Dacă doriți să
genera .gcov fișiere pentru toate fișierele obiect profilate, puteți rula ceva de genul acesta:
pentru fișier în `find . -nume \*.gcno`
do sh -c "cd `dirname $fișier` && gcov `nume de bază $fișier .gcno`"
făcut
Opțiuni utile de gcov include „-b” care va rezuma blocul de bază, ramura și
acoperirea apelurilor de funcție și „-c” care, în loc de frecvențe relative, va folosi cea actuală
conteaza. Pentru mai multe informații despre utilizarea gcov și profilarea de bază a blocurilor cu gcc, vezi
cel mai recent manual GNU CC. Începând cu gcc 4.8, aceasta este la
<http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro>
DIVERSE TRUCURI
PERL_DESTRUCT_LEVEL
Dacă doriți să executați manual oricare dintre teste folosind, de exemplu, valgrind, vă rugăm să rețineți
că implicit perl face nu curățați în mod explicit toată memoria pe care a alocat-o (cum ar fi
arene de memorie globală) dar în schimb lasă Ieșire() a întregului program „ai grijă” de asemenea
alocările, cunoscute și sub denumirea de „distrugerea globală a obiectelor”.
Există o modalitate de a-i spune lui perl să facă o curățare completă: setați variabila de mediu
PERL_DESTRUCT_LEVEL la o valoare diferită de zero. Învelișul t/TEST setează acest lucru la 2 și acesta
este ceea ce trebuie să faci și tu, dacă nu vrei să vezi „scurgerile globale”: De exemplu, pentru
alergând sub valgrind
env PERL_DESTRUCT_LEVEL=2 valgrind ./perl -Ilib t/foo/bar.t
(Notă: modulul mod_perl apache folosește și această variabilă de mediu în scopuri proprii
și și-a extins semantica. Consultați documentația mod_perl pentru mai multe informații.
De asemenea, firele generate fac echivalentul setării acestei variabile la valoarea 1.)
Dacă, la sfârșitul unei alergări, primiți mesajul N scalari scurgeri, puteți să recompilați cu
„-DDEBUG_LEAKING_SCALARS”, care va face ca adresele tuturor acelor SV-uri scurse să fie
dumping împreună cu detalii despre locul unde a fost alocat inițial fiecare SV. Aceasta informatie
este afișat și de Devel::Peek. Rețineți că detaliile suplimentare înregistrate cu fiecare SV
crește utilizarea memoriei, deci nu ar trebui folosită în medii de producție. De asemenea
convertește „new_SV()” dintr-o macrocomandă într-o funcție reală, astfel încât să puteți folosi preferata
depanator pentru a descoperi unde au fost alocate acele SV-uri plictisitoare.
Dacă vedeți că pierdeți memorie în timpul execuției, dar nici valgrind, nici
„-DDEBUG_LEAKING_SCALARS” va găsi orice, probabil că scurgeți SV-uri care sunt încă
accesibil și va fi curățat corespunzător în timpul distrugerii interpretului. În așa
cazuri, folosind comutatorul „-Dm” vă poate indica sursa scurgerii. Dacă executabilul
a fost creat cu „-DDEBUG_LEAKING_SCALARS”, „-Dm” va scoate alocările SV în plus față de
alocările de memorie. Fiecare alocare SV are un număr de serie distinct care va fi scris
privind crearea și distrugerea SV. Deci, dacă executați codul scurs într-o buclă,
trebuie să căutați SV care sunt create, dar niciodată distruse între fiecare ciclu. Dacă
se găsește un astfel de SV, setați un punct de întrerupere condiționat în „new_SV()” și faceți-l numai întrerupere
când „PL_sv_serial” este egal cu numărul de serie al SV care are scurgeri. Atunci vei prinde
interpretul în exact starea în care este alocat SV-ul scurs, adică
suficient în multe cazuri pentru a găsi sursa scurgerii.
Deoarece „-Dm” folosește stratul PerlIO pentru ieșire, va aloca de la sine o mulțime de
SV, care sunt ascunse pentru a evita recursiunea. Puteți ocoli stratul PerlIO dacă utilizați
În schimb, înregistrarea SV este oferită de „-DPERL_MEM_LOG”.
PERL_MEM_LOG
Dacă este compilat cu „-DPERL_MEM_LOG”, atât alocările de memorie, cât și SV trec prin înregistrare
funcții, care este la îndemână pentru setarea punctului de întrerupere.
Cu excepția cazului în care „-DPERL_MEM_LOG_NOIMPL” este și compilat, funcțiile de înregistrare citesc
$ENV{PERL_MEM_LOG} pentru a determina dacă să înregistreze evenimentul și, dacă da, cum:
$ENV{PERL_MEM_LOG} =~ /m/ Înregistrează toate operațiunile de memorie
$ENV{PERL_MEM_LOG} =~ /s/ Înregistrează toate operațiunile SV
$ENV{PERL_MEM_LOG} =~ /t/ include marca temporală în jurnal
$ENV{PERL_MEM_LOG} =~ /^(\d+)/ scrieți în FD dat (implicit este 2)
Înregistrarea în memorie este oarecum similară cu „-Dm”, dar este independentă de „-DDEBUGGING”, și la o
nivel mai înalt; toate utilizările Newx(), Reînnoi() și Safefree() sunt înregistrate cu cele ale apelantului
fișierul codului sursă și numărul liniei (și numele funcției C, dacă este acceptat de compilatorul C).
În schimb, „-Dm” este direct în punctul „malloc()”. Înregistrarea SV este similară.
Deoarece înregistrarea nu utilizează PerlIO, toate alocările SV sunt înregistrate și nu există SV suplimentar
alocările sunt introduse prin activarea înregistrării. Dacă este compilat cu
„-DDEBUG_LEAKING_SCALARS”, numărul de serie pentru fiecare alocare SV este de asemenea înregistrat.
DDD peste gDB
Cei care depanează Perl cu interfața DDD peste gdb pot găsi următoarele utile:
Puteți extinde meniul de comenzi rapide pentru conversia datelor, deci, de exemplu, puteți afișa un SV
Valoarea IV cu un singur clic, fără a tasta. Pentru a face asta, pur și simplu editați ~/.ddd/init
fisier si adauga dupa:
! Afișează comenzile rapide.
Ddd*gdbDisplayShortcuts: \
/t () // Convertiți în Bin\n\
/d () // Convertiți în Dec\n\
/x () // Convertiți în Hex\n\
/o () // Convertiți în oct(\n\
următoarele două rânduri:
((XPV*) (())->sv_any )->xpv_pv // 2pvx\n\
((XPVIV*) (())->sv_any )->xiv_iv // 2ivx
deci acum puteți face căutări ivx și pvx sau puteți conecta acolo „conversia” sv_peek:
Perl_sv_peek(my_perl, (SV*)()) // sv_peek
(My_perl este pentru versiuni threaded.) Amintiți-vă că fiecare linie, dar ultima,
ar trebui să se termine cu \n\
Alternativ, editați fișierul init în mod interactiv prin: al treilea buton al mouse-ului -> Afișare nou ->
Editați meniul
Notă: puteți defini până la 20 de comenzi rapide de conversie în secțiunea gdb.
C trage înapoi
Pe unele platforme, Perl acceptă preluarea backtrace la nivel C (similar cu ceea ce este simbolic
depanatoare precum gdb fac).
Backtrace returnează următorul stivă a cadrelor de apel C, cu numele simbolurilor
(numele funcțiilor), numele obiectelor (cum ar fi „perl”) și, dacă se poate, și codul sursă
locații (file:line).
Platformele acceptate sunt Linux și OS X (unele *BSD ar putea funcționa cel puțin parțial, dar
nu au fost încă testate).
Această caracteristică nu a fost testată cu mai multe fire de execuție, dar va afișa doar urmărirea înapoi
a firului care face trasarea înapoi.
Funcția trebuie să fie activată cu „Configurare -Dusecbacktrace”.
„-Dusecbacktrace” permite, de asemenea, păstrarea informațiilor de depanare la compilare/conectare
(adesea: „-g”). Mulți compilatori/linkere acceptă atât optimizarea, cât și păstrarea
informații de depanare. Informațiile de depanare sunt necesare pentru numele simbolurilor și sursa
locații.
Este posibil ca funcțiile statice să nu fie vizibile pentru backtrace.
Locațiile codului sursă, chiar dacă sunt disponibile, pot lipsi adesea sau pot induce în eroare dacă
compilatorul are, de exemplu, cod inline. Optimizer poate face potrivirea codului sursă și
cod obiect destul de provocator.
Linux
Tu trebuie să: au biblioteca BFD (-lbfd) instalată, altfel „perl” nu se va conecta.
BFD este de obicei distribuit ca parte a binutils-ului GNU.
Rezumat: „Configurați ... -Dusecbacktrace” și aveți nevoie de „-lbfd”.
OS X
Locațiile codului sursă sunt acceptate dacă aveți instrumentele pentru dezvoltatori
instalat. (BFD este nu Necesar.)
Rezumat: „Configurați ... -Dusecbacktrace” și instalarea Instrumentelor pentru dezvoltatori ar fi
bine.
Opțional, pentru a încerca funcția, poate doriți să activați descărcarea automată a fișierului
backtrace chiar înainte ca un mesaj de avertizare sau croak (mor) să fie emis, prin adăugare
„-Accflags=-DUSE_C_BACKTRACE_ON_ERROR” pentru Configurare.
Cu excepția cazului în care funcția suplimentară de mai sus este activată, nimic despre funcționalitatea de urmărire inversă
este vizibil, cu excepția nivelului Perl/XS.
În plus, chiar dacă ați activat această caracteristică să fie compilată, trebuie să o activați
în timpul de execuție cu o variabilă de mediu: „PERL_C_BACKTRACE_ON_ERROR=10”. Trebuie să fie un
întreg mai mare decât zero, indicând numărul de cadre dorit.
Recuperarea backtrace de la nivelul Perl (folosind, de exemplu, o extensie XS) ar fi mult
mai puțin interesant decât s-ar spera: în mod normal, ați vedea „runops”, „entersub”, și nu
multe altele. Acest API este destinat să fie apelat din în implementarea Perl, nu
de la execuția la nivel Perl.
API-ul C pentru backtrace este după cum urmează:
get_c_backtrace
free_c_backtrace
get_c_backtrace_dump
dump_c_backtrace
Otravă
Dacă vedeți într-un depanator o zonă de memorie plină în mod misterios de 0xABABABAB sau 0xEFEFEFEF,
poate observa efectul Otravă() macrocomenzi, vezi perlclib.
Numai în citire optrees
Sub ithread-ul optree este numai pentru citire. Dacă doriți să aplicați acest lucru, verificați dacă scrieți
accesează din codul buggy, compilați cu „-Accflags=-DPERL_DEBUG_READONLY_OPS” pentru a activa
cod care alocă memorie operațională prin „mmap” și o setează doar pentru citire când este atașată la un
subrutină. Orice acces de scriere la o operațiune are ca rezultat un „SIGBUS” și se anulează.
Acest cod este destinat doar dezvoltării și este posibil să nu fie portabil chiar și pentru toate Unix-urile
variante. De asemenea, este o soluție de 80%, prin faptul că nu este capabil să facă toate operațiunile doar în citire.
Mai exact, nu se aplică plăcilor op care aparțin blocurilor „BEGIN”.
Cu toate acestea, ca soluție de 80%, este încă eficientă, deoarece a prins bug-uri în trecut.
Cand is a bool nu a bool?
Pe compilatoarele anterioare C99, „bool” este definit ca echivalent cu „char”. În consecință, atribuirea
de orice tip mai mare la un „bool” este nesigur și poate fi trunchiat. Macrocomanda „cBOOL” există
pentru a-l arunca corect.
Pe acele platforme și compilatoare în care „bool” este într-adevăr un boolean (C++, C99), este ușor
pentru a uita distribuția. Puteți forța „bool” să fie un „char” prin compilarea cu
„-Accflags=-DPERL_BOOL_AS_CHAR”. De asemenea, poate doriți să rulați „Configurare” cu ceva de genul
-Accflags='-Wconversion -Wno-sign-conversion -Wno-shorten-64-to-32'
sau echivalentul compilatorului dvs. pentru a facilita identificarea oricăror trunchieri nesigure care apar
în sus.
.i Obiective
Puteți extinde macrocomenzile într-un foo.c dosar spunând
face foo.i
care va extinde macrocomenzile folosind cpp. Nu vă speriați de rezultate.
Utilizați perlhacktips online folosind serviciile onworks.net