Inxhinierët e kompanisë Apple shpallën gatishmërinë për testimin e modit «-fbounds-safety» për kompilatorin Clang, i cili ofron garanci për sigurinë e punës me bufra në kodin e gjuhës C. Mënyra është e përfshirë në forkin e LLVM, të mbështetur nga Apple për projektin Swift. Më vonë është planifikuar një transferim gradual i funksionalitetit «-fbounds-safety» në bazën e kodit kryesor të LLVM/Clang.
Vërehet se mekanizmi i propozuar i mbrojtjes është përdorur aktivisht në produktet Apple, si bërthama XNU, firmware, bibliotekat për punën me tinguj dhe dekoduesit e imazheve. Aktivizimi i modit «-fbounds-safety» zvogëlon performancën e aplikacioneve mesatarisht me 5% (shtrirja nga -1% deri në 29%), rrit madhësinë e kodit me 9.1% (shtrirja nga -1.4% deri në 38%) dhe ngadalëson kompilimin me 11%.
Përdorimi i modit «-fbounds-safety» për zbuluar automatikisht në daljet jashtë kufijve të hapësirës së memories, të lidhur me treguesit, kërkon shtimin e anotimeve speciale në kod dhe përfshirjen e skedës «ptrcheck.h». Qëllimi i metodës së propozuar të mbrojtjes është bashkangjitja automatike e verifikimeve të përputhshmërisë me kufijtë e lejuar, që shtohen në bazë të anotimeve të vendosura me dorë ose madhësive të njohura nga kompilatori.
Në ndryshim nga përdorimi i treguesve të zgjeruar në kod (wide pointer), të cilët përveç adresës kanë informacione mbi kufirin e sipërm dhe atë të poshtëm të bufrit, përdorimi i modit «-fbounds-safety» nuk shkel ABI (Application Binary Interface), nuk ndryshon formatin e treguesve të eksportuar dhe nuk kërkon ripërpunimin e të gjithë projektit menjëherë. Në modin «-fbounds-safety» treguesit e zgjeruar aplikohen vetëm në fusha që nuk ndërthuren me ABI, ndërsa për treguesit që ndikojnë në ABI, përdoren treguesit normalë me zëvendësimin e kontrollit të kufijve, të formuar në bazë të anotimeve me informacion mbi kufijtë.
Anotimet duhet të bashkangjiten treguesve në fushat e strukturave dhe parametrat e funksioneve që tregojnë për një array objektesh, si dhe në variablat globale me tregues. Për treguesit në variablat lokale nuk është e nevojshme shtimi i anotimeve, pasi ato trajtohen automatikisht si tregues të zgjeruar, të cilët tashmë përmbajnë informacion mbi kufijtë e lejuar. Të dhënat e ndihmës për konstrukcionet në kod, për të cilat kërkohet shtimi i anotimeve, jepen nga kompilatori kur ekzekutohet me flamurin «-fbounds-safety».
Modeli i mbrojtjes bazuar në «-fbounds-safety» mund të integrohet gradualisht, skedë pas skede, pa ndërprerë zhvillimin e tërë projektit. Shtimi i mbrojtjes në projekt përfshin përcaktimin e anotimeve në një dosje të caktuar me kod, eliminimin e paralajmërimeve të kompilatorit dhe kryerjen e testimeve të funksionimit të programit, pas së cilës këto etapa përsëriten për skedën e ardhshme. Kodi me anotimet e shtuar mbetet i përputhshëm me kodin normal të C dhe me kompilatorët që nuk mbështesin «-fbounds-safety» (në ndërtimin nga kompilatorë të tjerë ose në ndërtimin pa flamurin «-fbounds-safety» thjesht nuk do të shtohen kontrollet shtesë të kufijve).
Gjatë punës së programit, në rast se identifikohet një qasje përtej kufijve të lejuar, gjenerohet një përjashtim dhe programi përfundon ekzekutimin e tij. Një përfundim aksidental mund të ndodhi gjithashtu nëse janë specifikuar anotime të pavlefshme, prandaj përdorimi i «-fbounds-safety» kërkon kryerjen e testimeve shtesë të funksionimit të programit.
Në shembullin më poshtë në parametrin «int *p» është vendosur anotimi «__counted_by(n)», duke shtuar një kontroll të shtuara mbi kufijtë e lejuar, që vepron gjatë ekzekutimit. Nëse përpiqeni të kompiloni kodin në modin «-fbounds-safety» pa specifikimin e kësaj anotimi, kompilatori do të nxjerrë një paralajmërim për mungesën e informacionit mbi kufijtë e array-it gjatë trajtimit të shprehjes «p[i] = 0». #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // në modin «-fbounds-safety» kompilatori vetë do të shtojë kontroll, të ngjashëm me kodin «if (i = n) trap();» }
Për variablat lokale me treguesit, verifikimet bashkangjiten automatikisht, për shembull: void foo(int i){ char *buf = (char *)malloc(10); // për treguesin buf do të ruhen informacione mbi kufijtë buf[i] = 0xff; // do të shtohet automatikisht kontrolli «if (buf + i = buf + 10) trap();» }
Sa të jetë e mundur, kompilatori kryen optimizimin dhe përjashton shtimin e kodit të tepruar, nëse në kodin e ndodhur tashmë ka kontrollet e nevojshme. Për shembull: for (size_t i = 0; i < count; ++i) { buf[i] = i; // kontrolli «if (i = count) trap()» nuk do të shtohet, sepse më lart tashmë ka kushti «i < count» dhe i nuk mund të jetë më i vogël se 0. }
Anotimet kryesore:
- «__counted_by(N)» â pĂ«rcakton madhĂ«sinĂ« e bufrit nĂ« elemente tĂ« tipit tĂ« synuar.
- «__sized_by(N)» â pĂ«rcakton madhĂ«sinĂ« e bufrit nĂ« byte.
- » __ended_by(P)» â pĂ«rcakton kufirin e sipĂ«rm tĂ« tamponit.
- «__null_terminated» â merr parasysh simbolin e zeros si fund tĂ« tamponit.
- «__single» â lidh treguesin me njĂ« objekt tĂ« vetĂ«m. PĂ«rdoret si rregull pĂ«r treguesit qĂ« ndikojnĂ« nĂ« ABI, nĂ«se nuk Ă«shtĂ« eksplicitisht vendosur annotations.
- «__bidi_indexable» â tregues i avancuar me informacion mbi kufijtĂ« e sipĂ«rm dhe tĂ« poshtĂ«m. PĂ«rdoret si rregull pĂ«r treguesit qĂ« nuk ndikojnĂ« nĂ« ABI.
- «__indexable» â tregues i avancuar me informacion mbi kufirin e sipĂ«rm.
- «__unsafe_indexable» â tregues pa kontroll kufijsh (pĂ«r portabilitet me kodin e pa sigurt, si pĂ«r shembull marrjen e treguesve nga kodi i jashtĂ«m).
Burimi: opennet.ru
