<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 指針、結構體、聯(lián)合體的安全規范

指針、結構體、聯(lián)合體的安全規范

作者: 時(shí)間:2007-02-06 來(lái)源:網(wǎng)絡(luò ) 收藏
賦予了C編程最大的靈活性;體使得C程序整齊而緊湊;在某些要求注重效率的場(chǎng)合有精彩的表現,這三個(gè)要素是C語(yǔ)言的精華。


然而,精華并不意味著(zhù)完美,
C語(yǔ)言在賦予程序員足夠靈活性的同時(shí),也給了程序員很多犯錯誤的機會(huì )。所以有必要關(guān)注、體和的實(shí)現細節,從而保障程序的性。


在此.第一部分介紹《
MISRAC2004》中與相關(guān)的部分規則,第二部分講解體和的操作。下文中凡是未加特殊說(shuō)明的都是強制(required)規則,個(gè)別推薦(advisory)規則加了“推薦”標示。


1
指針的

MISRAC2004》關(guān)于指針的主要分為三個(gè)部分:指針的類(lèi)型轉換規則、指針運算的規則和指針的有效性規則。


1.1
指針的類(lèi)型轉換

指針類(lèi)型轉換是個(gè)高風(fēng)險的操作,所以應該盡量避免進(jìn)行這個(gè)操作。MISRAC對其中可能造成嚴重錯誤的情況作了嚴格的限定,選擇其中兩條作簡(jiǎn)要分析。


規則
11.4(推薦):指向不同數據類(lèi)型的指針之間不能相互轉換。

思考如下程序:

uint8_t*pl;

uint32)_t*p2;

p2=(uint32_t*)pl;

*注:uint8_t表示8位無(wú)符號整型,uint3_t表示32位無(wú)符號整型。*


程序員希望將從
p1單元開(kāi)始的4個(gè)字節組成一個(gè)32付的整型來(lái)參與運算。


如果
CPU允許各種數據對象存放在任意的存儲單元,則以上轉換沒(méi)有問(wèn)題。但某些CPU對某種()數據類(lèi)型加強了對齊限制,要求這些數據對象占用一定的地址空間,比如某些字節尋址的CPU會(huì )要求32(4字節)整型存放在4的整倍數地址上。在這個(gè)前提下.思考程序中的指針轉換:假設pl一開(kāi)始指向的是0x00O3單元(uint8_t型的整型沒(méi)有對齊要求),則執行最后一行強制轉換后,p2到底指向哪個(gè)單元就無(wú)法預料了。


規則
1 1.5:指針轉換過(guò)程中不允許丟失指針的const、volatile屬性。按如下定義指針:

uIntl6t x;

uint16_t*const cpi=x; *const指針*

uintl6_t*const *pcpi; *指向const指針的指針*

const uintl6_t* *ppci; *指向const整型指針的指針*

uIntl6_t* *ppi ;

const uint16_t *pci; *指向const整型的指針*

volatik uint16_t *pvi; *指向volatile整型的指針*

uintl6_t *pi;


則以下指針轉換是允許的:

pl=cpi;

以下指針轉換是不允許的:

pi=(umtl6_t*)pci;

pi=(uintl6_t*)pvil

ppi=(uintl6_t* *)pcpi;

ppi=(uintl6_I**)ppci+


以上非法指針類(lèi)型轉換將會(huì )丟失
const或者volatile類(lèi)型。丟失const屬性,將有可能導致在對只讀內容進(jìn)行寫(xiě)操作時(shí),編譯器不會(huì )發(fā)出警告,編譯器將不對具有volatile屬性的變量作優(yōu)化;丟失volatile屬性,編譯器的優(yōu)化可能導致程序員預先設計的硬件時(shí)序操作失效,這樣的錯誤很難發(fā)現。關(guān)于constvolatile關(guān)鍵字的詳細作用,讀者可參考ISOC獲取更多信息。


1
2 指針的運算

ISOC標準中,對指向數組成員的指針運算(包括算術(shù)運算、比較等)做了規范定義,除此以外的指針運算屬于未定義(undefined)范圍,具體實(shí)現有賴(lài)于具體編譯器,其性無(wú)法得到保障,MISRAC中對指針運算的合法范圍做了如下限定。


規則
17.1:只有指向數組的指針才允許進(jìn)行算術(shù)運算①。

規則17 2:只有指向同一個(gè)數組的兩個(gè)指針才允許相減 ②。

規則17 3:只有指向同一個(gè)數組的兩個(gè)指針才允許用>,>=,,=等關(guān)系運算符進(jìn)行比較。


為了盡最大可能減少直接進(jìn)行指針運算帶來(lái)的隱患,尤其是程序動(dòng)態(tài)運行時(shí)可能發(fā)生的數組越界等問(wèn)題,
MISRAC對指針運算作了更為嚴格的規定。規則17 4:只允許用數組索引做指針運算。按如下方式定義數組和指針:

uint8_t a[10];

uint8_t *p;


*(p+5)=O是不允許的.而p[5]=O則是允許的,盡管就這段程序而言,二者等價(jià)。


以下給出一段程序,讀者可參照相應程序行的注釋?zhuān)毤毱肺渡鲜鲆巹t的含義。

void my_fn(uInt*_t*p1uint8_t p2[]){


①其實(shí)此處的算術(shù)運算僅限定于指針加減某個(gè)整數.比如
ppoint=point5ppoint++等。0兩個(gè)指針可指向不同的散組成員。

uint8_t index=0;

uint8_t *p3

uint8_t *p4;

*pl=O;

p1++; *不允許,pl不是指向數組的指針*

p1=p1+5;*不允許,pl不是指向數組的指針*

pl[5]=O; *不允許,p1不是指向數組的指針*

p3=p1[5];*不允許,pl不是指向數組的指針*

p2[0]=O;

index++;

index=index+5

p2[index]=0; *允許*

*(p2+index)=O; *不允許*

p4=p2[5]; *允許*

}


1
3
指針的有效性

下面介紹《MISRAC2004》中關(guān)于指針有效性的規則。


規則
17 6:動(dòng)態(tài)分配對象的地址不允許在本對象消亡后傳給另外一個(gè)對象。


這條規則的實(shí)際意義是不允許將棧對象的地址傳給外部作用域的對象。

請看以下這段程序:

#includestdi0h

char*getm(void){

char p[]=hello world″;

return p;

intmain(){

char* str=NULL;

str=getm();

printf(str);


程序員希望最后的輸出結果是″
hello world″這個(gè)字符串,然而實(shí)際運行時(shí),卻出現亂碼(具體內容依賴(lài)于編譯環(huán)境)。


簡(jiǎn)單分析一下,由于chat p[]=hell0 world″這條語(yǔ)句是在棧中分配空間存儲″hell0 world″這個(gè)字符串,當函數getm()返回的時(shí)候,已分配的空間將會(huì )被釋放(但內容并不會(huì )被銷(xiāo)毀),而priM(str)涉及系統調用,有數據壓棧,會(huì )修改從前分配給數組p[]存儲空間的內容,導致程序無(wú)法得到預期的效果。


倘若將
getm()函數體中的char p[]=hell0 world″程序行改成char*q=hello world″,則執行main( )的時(shí)候可以正確輸出″hello world″,這是由于q指向的是靜態(tài)數據區,而非棧中的某個(gè)單元。


所以,數組名是指針不假,但在實(shí)現細節上還是有很大的差異,程序員在使用指針的時(shí)候必須慎之又慎。

 

2 結構體、聯(lián)合體的安全規范

規則18 4:不允許使用聯(lián)合體。這是一個(gè)不太近情理的規定,在具體闡述為何《MISRAC2004》如此“痛恨”聯(lián)合體之前,首先需要明確與聯(lián)合體相關(guān)的細節:

①聯(lián)合體的末尾有多少個(gè)填充單元?

②聯(lián)合體中的各個(gè)成員如何對齊?

③多字節的數據類(lèi)型高低字節如何排放順序?

④如果包含位字段(bitfield),各位如何排放順序?


針對細節3舉個(gè)例子。

程序段21

typedef union{

uilat32_t word;

uint8_t bytes[4];

}word_msg_t;

unit32_t read_nasg(void){

word_rnsg_t tmp;

*注:tmn bvte[O]對府干tmpword的高8位,tmp byter[l]對應于

tmp.WOfO的次高8位,依次類(lèi)推。*

tmpbytes[O]=read_byte();

tmpbytes[1]=read_byte();

tmpbytes[2]=read_byte();

tmpbytes[3]=read_byte();

retlarn(trapword);

}

以上代碼格式在各種通信協(xié)議中使用的頻率很高,接收端接收到的數據一般都以字節為單位存放,主控程序需要根據相應的協(xié)議將接收到的多個(gè)字節進(jìn)行組合。為了實(shí)現相同的功能,《MISRA-C2004》推薦了read_msg()函數的另外一種寫(xiě)法。

程序段22

uint32_trcad_msg(void){

uint32_t word;

Word=((unit32_t)read_byte())24;

word=word(((unit32_t)read_byte())16);

word=word(((unit32_t)read_byted_byte8);

word=word(((unit32_t)read_byte());

return(word)

}


無(wú)論從程序的清晰程度還是執行效率來(lái)講,程序段
21都優(yōu)于程序段22。然而,程序段21Intel 80x86Pentlurn體系(1ittleendian,存儲多字節整數的時(shí)候低字節存放在低地址,高字節存放在高地址)CPU中和在Motorola 68K體系(bigendian,存儲多字節整數的時(shí)候高字節存放在低地址,低字節存放在高地址)cPu中的執行結果完全不一樣。假設read_byte()函數返回的數據依次是0x01、0x02、0x030x04,則在Intel體系中,程序段21

read_msg()函數的返回值是0x432l;在Motorola體系中,read_msg()的返回值是0x1234。


無(wú)論在
Intel體系還是Motorola體系中,程序段22read_msg()的返回值都是0x1 234。


以上是聯(lián)合體中多字節整型字節排放順序不定導致漏洞的一個(gè)例子。倘若不明確聯(lián)合體末尾填充的細節,或者不清楚聯(lián)合體成員的對齊方式,或者不注意聯(lián)合體中位字段成員的位排列次序,都有可能導致錯誤。作為將安全性放在第一位的
C標準,MlSRAC禁止使用聯(lián)合體并非不可理喻。


然而,聯(lián)合體畢竟是C語(yǔ)言的一個(gè)重要元素,所以MISRAC主張禁止使用聯(lián)合體的同時(shí),也為效率和資源要求比較苛刻的情況開(kāi)了一扇門(mén),程序員在明確聯(lián)合體各個(gè)實(shí)現細節的前提下,在萬(wàn)不得已的時(shí)候,仍可謹慎使用聯(lián)合體,在不同體系的CPU間移植程序的時(shí)候要注意做相應的修改。


此外,《
MISRAC2004》中也對結構體和聯(lián)合體的編程風(fēng)格作了限定。


規則
18 1:所有結構體和聯(lián)合體的定義必須保證完整性。


由于涉及
ISOC中類(lèi)型定義完整性等概念,礙于篇幅的原因,此處就不再贅述,讀者可以參閱《MISRA-C2004》一書(shū)和ISOC標準以了解更多信息,完善自己的編程風(fēng)格。

 

3

總而言之,對于C程序中最為靈活的指針、結構體和聯(lián)合體,程序員不僅僅要關(guān)注其定義和操作的一般方法,更要注重實(shí)現的細節。由于指針、聯(lián)合體等的功能性錯誤一般都可以逃過(guò)編譯器的檢查,所以稍有疏忽,就可能導致程序在運行的時(shí)候出現嚴重錯誤,程序員必須以嚴謹甚至苛刻的態(tài)度對待指針、結構體和聯(lián)合體。



評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>