Mineru-si schimba jobul, dar naravul ba

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: , , , , , , ,

12 Responses to “Mineru-si schimba jobul, dar naravul ba”

  1. bullshit Says:

    “# trebuie sa fie tot timpul pe prima coloana” – aici ai doar partial dreptate. Asa era in standardele vehci. Standardele noi sunt mai permisive, poti sa ai whitespace in afara de newline inainte de #. Citat din standardul C si/sau C++:

    “The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either
    the first character in the source file (optionally after white space containing no new-line characters) or that
    follows white space containing at least one new-line character.”

    Anyway… daca numai atata ar fi fost problema in cod… :-)

  2. Tomis Says:

    Vizavi de bonus story…

  3. Mihnea Says:

    Ah, nu stiam ca s-a relaxat restrictia cu # la inceputul liniei. Academia Romana cu “nicio”, Comitetul cu diezul… fiecare cu ale lui. Mersi de pont.

  4. yo Says:

    Modifică şi şterge-i comentariul. Nimeni n-o văzut nimic!

  5. Mihnea Says:

    Nu, astept sa scrie Silviu ca si eu gresesc, dupa care sterg comentariul lui bullshit, corectez la mine si zic ca Silviu minte.

  6. Codoiu Says:

    Intrucat nu suntem calculatoare, nu putem avea pretentia unei vorbiri corecte a limbii lui CPU. La-la!

  7. mifty Says:

    … dacă tot ești un grade esperto, dă și tu dovadă de ”aciuitate vizuală”, și modifică naibii culorile, că gri pe negru cu font de 5 nu e cea mai bună soluție.
    până și mironul cozma pe care-l iubești atâta pricepe asta… ups, stai, a lăsat tema default de phpbb :D

  8. Mihnea Says:

    Ultima data cind a trebuit sa umblu prin css-ul site-ului ca sa fac coloana din mijloc mai lata era sa mor de plictiseala. Ultima data cind am schimbat tema cu totul s-a futut tot site-ul. In concluzie, nu. Pentru cei ce nu suporta culorile de site de warez exista Readability.

  9. Tomis Says:

    Cine se scoala de dimineata departe ajunge, mai ales cand vine la serviciu cu intentia de a simplifica un File.cpp (nota bene – sursa, nu header), si sfarseste prin a mai adauga un FileUtilities.cpp in care da cut/paste din primul. FileUtilities.cpp este adaugat in version control dar -evident- nu si in proiectul propriu-zis pentru ca ce naiba haz ar mai avea daca nu ti-ai bate joc de timpul celorlalti.

    Intr-un viitor mai mult sau mai putin apropiat un ghinionist face update si se uita crusis cand incepe sa incaseze erori fiindca linkerul nu gaseste niste functii desi ele apar in header bine mersi iar IDE-ul habar n-are unde sa se duca la un apel de go to definition. Dupa ce cauti prin fisiere cu Total Commander-ul sa vezi unde s-au ascuns functiile ai un facepalm-moment cand devine evidenta realizarea artistica a unuia care se preface ca este programator.

    /defulare

  10. WTF Says:

    @Tomis: Sa inteleg ca noul tau coleg de munca este silviu? :P

  11. Tomis Says:

    O ruda mai indepartata, cu siguranta.

  12. Mihnea Says:

    Incredibil, puroiul si-a publicat gunoiul pe codeguru: http://www.codeguru.com/cpp/v-s/debug/memoryissues/article.php/c19241/Adventures-with-chkstk.htm. Observam ca a operat “few cosmetics” asupra codului, care s-au propagat si la el pe blog.

Leave a Reply

Optionally add an image (JPEG only)