Apple-ի ինժեներիական թիմը հայտարարեց Clang կոմպիլատորին «-fbounds-safety» կարգի փորձարկման պատրաստ լինելու մասին, որն ապահովում է բուֆերի անվտանգ աշխատանքի երաշխիքներ C լեզվով կոդում: Այս կարգը ներառված է Apple-ի աջակցությամբ Swift նախագծի համար մշակված LLVM խոռոչում: Գոյություն ունի նախատեսված էլ «-fbounds-safety» ֆունկցիոնալության աստիճանական փոխանցում LLVM/Clang հիմնական կոդաբազային:
Նշվում է, որ առաջարկված անվտանգ մեխանիզմը արդեն ակտիվորեն օգտագործվում է Apple-ի արտադրանքներում, ինչպիսիք են XNU միջուկը, ֆիրմային ծրագրերը, ձայնի աշխատելու գրադարանը և պատկերների դեկոդերները: «-fbounds-safety» կարգի ակտիվացումը նվազեցնում է ծրագրերի արտադրողականությունը միջինը 5%-ով (միայն -1%-ից մինչև 29%-ը), ավելացնում է կոդի չափը 9.1%-ով (միայն -1.4%-ից մինչև 38%-ը) և էականորեն դանդաղեցնում է կոմպիլացիան 11%-ով:
Ստացվող «-fbounds-safety» կարգի կողմից հիշողության սահմաններից այն դուրս գալու ինքնաբերաբար հայտնաբերման համար պահանջում է, որպեսզի կոդում ավելացվեն հատուկ նշումներն ու ներառվի «ptrcheck.h» գլխիկը: Մետոդի պաստտական բնույթն այն է, որ ինքնաբերաբար կատարվում են սահմանների պահպանման ստուգողական մշակումներ, որոնք ավելացվում են ձեռքով տրված նշումներ կամ կոմպիլատորին հայտնի չափերի հիման վրա:
Այդ բերում «-fbounds-safety» կարգի օգտագործումը չխախտում է ABI (Application Binary Interface)-ը, փոխելով արտահանված ուղեցույցների ձևաչափը և չի պահանջում ամբողջ նախագծի վերագործարկում: «-fbounds-safety» կարգով ընդարձակեցված ուղեցույցները կիրառվում են միայն այն տարածքներում, որոնք չեն հատվում ABI-յի հետ, իսկ ABI-ին ազդեցություն ունեցող ուղեցույցների համար կիրառվում են սովորական ուղեցույցներ, որոնք ստուգումներով ֆորմավորվում են սահմանների մասին նշումների հիման վրա:
Նշումները պետք է կապվեն այն ուղեցույցներին, որոնք գտնվում են կառուցվածքային դաշտերում ու ֆունկցիաների պարամետրերում, որոնք ցույց են տալիս օբյեկտների զանգվածները, ինչպես նաև գլոբալ փոփոխականների համար, որոնք ունեն ուղեցույցներ: Նշումները անհրաժեշտ չէ ավելացնել տեղական փոփոխականների ուղեցույցների համար, քանի որ նրանք ավտոմատ կերպով մշակվում են որպես ընդարձակ ճկուն եղանակներ, որոնք արդեն ներառում են допустимые границы տեղեկատվություն: Կոմպիլատորը, «-fbounds-safety» դրոշով մեկնարկեց, կցագրումներ է նշում այն կառուցվածքներին, որոնք պահանջում են նշումների ավելացում:
Մոդելի պաշտպանությունը հիմնված է «-fbounds-safety» աստիճանաբար կարող է ներդրվել, ֆայլից ֆայլ, առանց ձեր նախագիծը ընդհատելու: Պաշտպանության ավելացումը նախագծին կապված է որոշակի ֆայլի մարկերելու, կոմպիլատորի նախազգուշացումների վերացման և ծրագրի աշխատանքի փորձարկման գործընթացին, որից հետո այդ փուլերը կրկնվում են հաջորդ ֆայլի համար: Կոդը, որի մեջ ավելացված են նշումները, մնում է համատեղելի սովորական C կոդի և կոմպիլատորների հետ, որոնք չեն աջակցում «-fbounds-safety»-ին (այլ կոմպիլատորներով հավաքելու կամ «-fbounds-safety» նշանը չունենալու դեպքում, լրացուցիչ սահմանային ստուգումներ չեն ավելացվելու).
Ծրագրի աշխատանքի ընթացքում, իսկ թե երբ սահմանները հատող դիմումները հայտնվեն, ստեղծվում է բացառություն, և ծրագիրը ավարտում է իր աշխատանքը: Անսպասելի ավարտը նույնպես կարող է տեղի ունենալ, երբ նշումները սխալ են, այնպես որ «-fbounds-safety» կիրառելիս անհրաժեշտ է լրացուցիչ փորձարկման անցկացում:
Ստորև բերված օրինակ में պարամետրի «int *p» մեջ ավելացված է նշում «__counted_by(n)», որը ավելացնում է լրացուցիչ ստուգում допустимых границ, որը գործում է 실행ի ժամանակ: Եթե փորձեք կոմպիլացնել կոդը «-fbounds-safety» ռեժիմում առանց նշված նշման, կոմպիլատորը կտա նախազգուշացում, որ քանակի մասին տեղեկատվություն չկա «p[i] = 0» արտահայտության մշակման ժամանակ. #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // «-fbounds-safety» ռեժիմում կոմպիլատորը ինքնըստինքյան ավելացնի ստուգում, նման «if (i = n) trap();» }
Շրջանավարէներ ունեցող տեղային փոփոխականների համար ստուգումները ավտոմատ կերպով կցվում են, օրինակ: void foo(int i) { char *buf = (char *)malloc(10); // buf մատիտին կպահպանվեն սահմանների մասին տեղեկություններ buf[i] = 0xff; // ավտոմատ կերպով ավելացվի ստուգում «if (buf + i = buf + 10) trap();» }
Հնարավորության դեպքում կոմպիլատորը կատարում է օպտիմիզացում և չի ավելացնում ավելորդ կոդ, եթե կոդում արդեն կան անհրաժեշտ ստուգումներ: Օրինակ: for (size_t i = 0; i < count; ++i) { buf[i] = i; // ստուգումը «if (i = count) trap()» չի ավելացվի, քանի որ վերևում արդեն կա «i < count» պայման և i չի կարող փոքր լինի 0-ից. }
Հիմնական նշումներն են:
- «__counted_by(N)» — սահմանում է բուֆերի չափը նպատակային տեսակի տարրերում:
- «__sized_by(N)» — սահմանում է բուֆերի չափը բիթերով:
- «__ended_by(P)» — սահմանում է բուֆերի վերին սահմանը:
- «__null_terminated» — հաշվի է առնում զրո նշանը բուֆերի վերջը:
- «__single» — կապված է մատիտի մեկ օբյեկտի հետ: Կիրառվում է ըստ կարգադրության ABI-ի վրա ազդող մատիտների համար, եթե մասնակի նշում չի ավելացվել:
- «__bidi_indexable» — ընդլայնված մատիտ, որտեղ նշված են վերին և ստորին սահմաններն: Կիրառվում է ըստ կարգադրության ABI-ի վրա չհասկացող մատիտների համար.
- «__indexable» — ընդլայնված մատենագրություն, տեղեկություններ վերին սահմանը:
- «__unsafe_indexable» — մատենագրություն առանց սահմանների ստուգման (ապահովված կոդով տեղաշարժվելու համար, օրինակ՝ մատենագրություններ ստանալու համար արտաքին կոդից):
Ընտանիք: opennet.ru
