Mineru-si schimba jobul, dar naravul ba

Posted in Codare cu premeditare on July 18th, 2011 by Mihnea

Mi s-a facut observatie ca n-am analizat obiectiv codul minerului din articolul mentionat anterior. Cind i-am corectat lucrarea i-am dat direct doi pentru copiat, n-am gasit de cuviinta sa ma uit cu atentie la partea originala, ca oricum nu prea mai aveam de unde sa-i scad din nota. Gresit! Iar pierdeam una din ocaziile (deloc rare, ce-i drept) in care 4 linii de cod contin mai multe greseli decit litere.

Sa  privim, deci, ce solutie propune Silviu pentru spinoasa problema a buffer overflow-ului:

#ifdef _WIN32
   #define usprintf(x, ...) _snwprintf(x, _countof(x) - 1, ##__VA_ARGS__); x[_countof(x)-1] = 0
#else
   #define usprintf(x, ...) snwprintf(x, _countof(x) - 1, ##__VA_ARGS__); x[_countof(x)-1] = 0
#endif

Ce ne izbeste din prima e o mare surpriza: Silviu stie ca _snprintf() din VC++ nu pune 0 la sfirsitul buffer-ului daca n-are loc! Nu v-ati fi asteptat, nu? Valea Jiului, always surprising! Ei bine, nu va grabiti cu laudele. Eu nu cred minerul a dezvoltat aceasta solutie cu de la sine putere.

In primul rind, problema pe care incearca el s-o rezolve nu exista. Pentru wide char ai swprintf(), care ia si capacitatea buffer-ului, exista pe toate compilatoarele din era noastra si pune si 0 la sfirsit tot timpul. VC++ are mici dubii legate de prototipul ei in C, dar nu si in C++, deci abatajul nu ar fi afectat. Orice om normal ar fi folosit functia aia si gata. In schimb, Capitanul Copypaste a vazut pe undeva pe net sau in proiectul la care lucreaza urmatorul fragment care “rezolva” problema lipsei varului snprintf() din VC++:

#ifdef _WIN32
   #define cevaprintf(x, ...) _snprintf(x, sizeof(x) - 1, ##__VA_ARGS__); x[sizeof(x)-1] = 0
#else
   #define cevaprintf(x, ...) snprintf(x, sizeof(x) - 1, ##__VA_ARGS__); x[sizeof(x)-1] = 0
#endif

Nici ala care a facut chestia asta nu e foarte breaz, dar n-ar fi prima data cind minerul se inspira de la un alt bou. Oricum, ce e important e ca Silviu a luat codul asta, a pus “w” acolo ca sa fie Unicode si a schimbat sizeof() cu _countof() ca i-am zis noi mai demult de chestia asta. Doar ca:

  • snwprintf() nu prea exista (cica ar fi prin Borland, daca intereseaza pe cineva asemenea relicve). Ca si data trecuta cind a scris cod “cross-platform”, ortacul nu s-a ostenit sa vada daca ce a debitat in a doua ramura a #ifdef-ului chiar se compileaza.
  • _countof() nu exista decit in VC++. Da, se poate copia printr-un header si folosi si-n alte compilatoare, dar minerul nu stie asta.
  • nu asa se fac macro-uri compuse din mai multe instructiuni. Astept cu interes sa scrie un coleg de-al lui if(cacat) usprintf(ceva); else usprintf(altceva); si sa se intrebe de ce nu se compileaza.
  • snprintf() pune singur 0 la sfirsit tot timpul, nu-i nevoie de lucru manual. Ipoteticul snwprintf(), numit in realitate swprintf(), face si el acelasi lucru. Dar ma rog, cum am stabilit deja, daca stii de swprintf() nu mai faci deloc cacaturile astea.
  • daca ar fi sa fim pedantici, ne-am lega de faptul ca # trebuie sa fie tot timpul pe prima coloana, nu ai voie sa pui tab-uri in fata lui. Din nefericire compilatoarele sint indulgente in problema asta.
  • nu vad de ce ai vrea sa chemi tu sizeof() sau _countof() pentru utilizatorul macro-ului. Poate ca sa te asiguri ca respectivul utilizator nu poate folosi ce-ai facut daca are un pointer chior, chiar daca stie capacitatea array-ului la care pointeaza.
  • nu vad de ce ai face chestia asta ca macro, in loc sa faci o functie ordinara, care ar merge si cind nu folosesti ultimul racnet de compilator cu suport pentru macro-uri variadice, n-ar avea probleme fara acolade etc.; evident, asta presupunind ca n-ar exista deja functia aia.

Misto e ca de data asta Silviu nu poate baga scuza aia imbecila cu “e cod didactic, nu trebuie sa mearga”. Conform spuselor lui, asta e cod pe care l-a scris in aplicatia pe care o distruge pe bani la Saguaro. Muie Silviu!

PS: Bonus story.

 

Tags: , , , , , , ,

Cele doua fete ale tirnacopului

Posted in Regula 0 on July 16th, 2011 by Mihnea

As vrea sa facem un exercitiu de imaginatie: inchipuiti-va Liceul de Informatica din Hunedoara intr-o dimineata de vara tirzie, la sfirsitul lui August 1999. E vacanta si liceul ar trebui sa fie pustiu, dar azi nu e, pentru ca a inceput a doua sesiune de bacalaureat. Alegeti o materie la intimplare – sa spunem informatica (merge si romana). Intrati cu ochiul mintii intr-una din salile de clasa si umpleti-va plaminii cu atmosfera de examen: susoteli, fituici, profesori care scriu rezolvarile pe tabla, elevi care se duc la celelalte sali sa vada daca acolo “s-a rezolvat subiectul 2”. Un singur om sta aplecat asupra foii sale, concentrat, superior, sclipitor, dar vizibil deranjat de forfota din jurul sau. Toti incearca sa copieze de la el, iar lui ii este din ce in ce mai greu sa ignore aceste agresiuni. Acest om este Silviu Ardelean.

Silviu se jura ca asa a fost. Saptamina trecuta a fost Sarbatoarea Bacalaureatului in Calendarul Datatorilor Cu Parerea si nu putea sa lipseasca tocmai el de la festivitati, asa ca a tinut sa-si proclame admiratia fata de camerele lui Funeriu si “adevarul, normalitatea, lucrurile frumoase, realitatea” pe care acestea le-au adus in viata romanilor. Noi am avea totusi niste obiectii…

La doar patru zile dupa ce l-a batut incurajator pe spate pe Funeriu, Silviu a decis ca a sosit timpul pentru a pune inca o data umarul la progresul programarologiei, asa ca a publicat un tratat despre functia _chkstk(). Articolul incepe in felul urmator:

A process starts with a fixed stack space. The top of a stack is pointed to by the ESP register (Extended Stack Pointer) and this is a decrementing pointer.

E ceva dubios aici, nu? Exprimarea curata, informatiile corecte, mentionarea cuvintului “registru” – toate acestea ii dau cititorului fidel un sentiment de alienare si-l fac sa verifice textul din address bar. Am intrat cumva din greseala pe o alta pagina? Nu, adresa e corecta, deci citim mai departe:

This is in contrast with the heap that can theoretically grow to a limit of 4 GB.

This is in contrast with“? Pe bune, dupa “electric power manufacture base on water“, “I’m acting into a C++ Romanian programming community” si “it depends on your’s algorithmic intellection, cleverness“? Ajuns aici am simtit nevoia sa-l intreb pe Google ce parere are despre alfabetizarea subita a lui Silviu, iar el mi-a raspuns fara sa pregete cu acest link de la codeguru. Pai ce facem Silviu? Iar copiem? Iar ne inspiram? Ce-ar fi sa punem niste camere d-alea de supraveghere si la calculatorul tau, pentru ca “rigoarea inpusă în această sesiune de examene să fie un nou început”? (“Inpusa”, mai gunoiule?)

Sigur, articolul nu e copy/paste in intregime. Putem determina unde incep contributiile originale ale minerului urmarind momentele in care fata gramaticii se intuneca brusc:

If you have an infinite recursion then you will gate same stack overflow error

I have started the study of _chkstk() function in the moment when I got few bugs with crashes with some similarly details.

I stopped to some trace function calls and I studied deeply.

Observam ca lucrarea minerului se incheie cu o lista de referinte, din care lipseste insa tocmai thread-ul de pe codeguru din care s-a inspirat. Deci:

Incheiem cu cuvintele directoarei liceului unde zice Silviu ca au copiat altii dupa el (si nu ne putem abtine sa ne intrebam cit de prosti erau aia):

Un mare filosof spunea că numai prin educaţie se poate asigura dominaţia minţii peste întuneric. Educaţia de care au avut parte atâtea generaţii care au trecut pragul acestei şcoli a însemnat colaborare, comunicare şi dialog, a asigurat elevilor libertatea să se întrebe şi să ne întrebe.

Sau, mai direct, cum cintau rapsozii aventurile lui Silviu in Piata Universitatii:

Minerul isi construieste singur cerul.
Minerul din mici lampase lucitoare isi face luna, stele, soare la fel ca si un vrajitor.
Minerul c-o mana poate s-atinga cerul
Si poate-n noapte-ntotdeauna s-aprinda stelele si luna.

Tags: , , , , , , , , , , , , , , ,