官术网_书友最值得收藏!

2.4.3 動(dòng)態(tài)分配函數(shù)

第二種內(nèi)存管理模型(由被調(diào)用者分配,由調(diào)用者釋放)是由ISO/IEC TR 24731-2定義的動(dòng)態(tài)分配函數(shù)實(shí)現(xiàn)。ISO/IEC TR 24731-2定義了許多標(biāo)準(zhǔn)C字符串處理函數(shù)的替代品,這些替代品使用動(dòng)態(tài)分配的內(nèi)存,以確保不會(huì)發(fā)生緩沖區(qū)溢出。因?yàn)槭褂眠@樣的函數(shù)需要引入隨后的釋放緩沖區(qū)的額外調(diào)用,所以這些函數(shù)更適用于新的開(kāi)發(fā),而不是改造現(xiàn)有代碼。

在一般情況下,因?yàn)樵贗SO/IEC TR 24731-2中描述的函數(shù),總是自動(dòng)調(diào)整緩沖區(qū)大小以容納所需的數(shù)據(jù),所以這些函數(shù)更好地確保了不會(huì)發(fā)生緩沖區(qū)溢出問(wèn)題。但是,使用動(dòng)態(tài)內(nèi)存分配的應(yīng)用程序,可能會(huì)遭受拒絕服務(wù)攻擊,因?yàn)槠渲械臄?shù)據(jù)會(huì)一直存在,直到內(nèi)存耗盡。它們也更容易出現(xiàn)動(dòng)態(tài)內(nèi)存管理錯(cuò)誤,這也可能導(dǎo)致安全漏洞。

例2.1可以使用動(dòng)態(tài)分配函數(shù)實(shí)現(xiàn),如例2.7中所示。

例2.7 使用函數(shù)getline()從stdin中讀入數(shù)據(jù)


01  #define __STDC_WANT_LIB_EXT2__ 1
02  #include <stdio.h>
03  #include <stdlib.h>
04  
05  void get_y_or_n(void) {
06    char *response = NULL;
07    size_t len;
08  
09    puts("Continue? [y] n: ");
10    if ((getline(&response, &len, stdin) < 0) ||
11        (len && response[0] == 'n')) {
12      free(response);
13      exit(0);
14    }
15    free(response);
16  }

此程序?qū)τ谌魏屋斎攵季哂幸讯x的行為,包括一個(gè)假定,即假定一個(gè)非常長(zhǎng)的、需要耗盡所有可用內(nèi)存才能容納的行,應(yīng)被視為一個(gè)“no”回應(yīng)。因?yàn)閷?duì)getline()函數(shù)動(dòng)態(tài)地分配response緩沖區(qū),所以程序必須調(diào)用free()來(lái)釋放已分配的內(nèi)存。

ISO/IEC TR 24731-2允許在不相應(yīng)地打開(kāi)文件的情況下定義流。這種類(lèi)型的流從內(nèi)存緩沖區(qū)取得輸入或把輸出寫(xiě)入到內(nèi)存緩沖區(qū)。例如,GNU C庫(kù)使用這些流來(lái)實(shí)現(xiàn)sprintf()和sscanf()函數(shù)。

與內(nèi)存緩沖區(qū)相關(guān)的流和與外部文件關(guān)聯(lián)的文本文件流,具有相同的操作。此外,數(shù)據(jù)流的方向也是用完全相同的方式確定的。

你可以明確地使用fmemopen()、open_memstream()或open_wmemstream()函數(shù)創(chuàng)建一個(gè)字符串流。這些函數(shù)允許你對(duì)字符串或內(nèi)存緩沖區(qū)執(zhí)行I/O操作。fmemopen()和open_memstream()函數(shù)在<stdio.h>中被聲明,如下所示。


1  FILE *fmemopen(
2    void * restrict buf, size_t size, const char * restrict mode
3  );
4  FILE *open_memstream(
5    char ** restrict bufp, size_t * restrict sizep
6  );

open_wmemstream()函數(shù)是在<wchar.h>中定義的,并具有以下簽名:


FILE *open_wmemstream(wchar_t **bufp, size_t *sizep); 

fmemopen()函數(shù)打開(kāi)一個(gè)流,使你可以讀取或?qū)懭胫付ǖ木彌_區(qū)。open_memstream()函數(shù)打開(kāi)一個(gè)面向字節(jié)的流來(lái)寫(xiě)入一個(gè)緩沖區(qū),而open_wmemstream()函數(shù)創(chuàng)建一個(gè)面向?qū)捵址牧鳌.?dāng)用fclose()關(guān)閉流或用fflush()刷新流時(shí),bufp和sizep被更新,以包含緩沖區(qū)的指針及其大小。只要沒(méi)有進(jìn)一步的輸出流發(fā)生,這些值仍然有效。如果執(zhí)行額外的輸出,必須再次刷新流來(lái)存儲(chǔ)新的值,才能再次使用它們。一個(gè)空字符被寫(xiě)入緩沖區(qū)的末尾,但它存儲(chǔ)在sizep中的size值中不包括它。

通過(guò)調(diào)用fmemopen()、open_memstream()或open_wmemstream()創(chuàng)建的一個(gè)與內(nèi)存緩沖區(qū)相關(guān)聯(lián)的流的輸入和輸出操作,發(fā)生在內(nèi)存緩沖區(qū)的范圍內(nèi),受限于實(shí)現(xiàn)。對(duì)于用open_memstream()或open_wmemstream()打開(kāi)的流的情況,內(nèi)存區(qū)域動(dòng)態(tài)增長(zhǎng),以適應(yīng)必要的寫(xiě)操作。對(duì)于輸出,在刷新或關(guān)閉操作期間,數(shù)據(jù)從函數(shù)setvbuf()提供的緩沖區(qū)移動(dòng)到內(nèi)存流。如果沒(méi)有足夠的內(nèi)存來(lái)增長(zhǎng)內(nèi)存區(qū)域,或者操作需要訪問(wèn)相關(guān)內(nèi)存區(qū)域以外的地方,相關(guān)的操作失敗。

例2.8中的程序在第6行打開(kāi)一個(gè)流來(lái)寫(xiě)入到內(nèi)存。

例2.8 打開(kāi)一個(gè)流來(lái)寫(xiě)入內(nèi)存


01  #include <stdio.h>
02  
03  int main(void) {
04    char *buf;
05    size_t size;
06    FILE *stream;
07  
08    stream = open_memstream(&buf, &size);
09    if (stream == NULL) { /* handle error */ };
10    fprintf(stream, "hello");
11    fflush(stream);
12    printf("buf = '%s', size = %zu\n", buf, size);
13    fprintf(stream, ", world");
14    fclose(stream);
15    printf("buf = '%s', size = %zu\n", buf, size);
16    free(buf);
17    return 0;
18  }

在第10行把字符串“hello”寫(xiě)入到流,并且在第11行刷新該流。fflush()的調(diào)用更新buf和size,以便第12行的printf()函數(shù)輸出:


buf = 'hello', size = 5

在第13行把字符串".world"寫(xiě)入流后,在第14行關(guān)閉流。關(guān)閉流的同時(shí)也更新buf和size,以便第15行的printf()函數(shù)輸出:


buf = 'hello, world', size = 12

size是緩沖區(qū)的累計(jì)(總數(shù))大小。open_memstream()函數(shù)提供了一個(gè)更安全的寫(xiě)入內(nèi)存機(jī)制,因?yàn)樗捎昧烁鶕?jù)需要?jiǎng)討B(tài)分配內(nèi)存的方法。但是,它確實(shí)要求調(diào)用者來(lái)釋放分配的內(nèi)存,如例子的第16行所示。

在安全關(guān)鍵的系統(tǒng)中,往往是不允許動(dòng)態(tài)分配的。例如,MISRA標(biāo)準(zhǔn)要求,“不得使用動(dòng)態(tài)堆內(nèi)存分配”[MISRA 2005]。一些安全關(guān)鍵系統(tǒng)在初始化過(guò)程中可以利用動(dòng)態(tài)內(nèi)存分配,但在操作過(guò)程中不允許。例如,航空電子軟件在初始化飛機(jī)時(shí)可以動(dòng)態(tài)地分配內(nèi)存,但在飛行過(guò)程中不允許。

動(dòng)態(tài)分配函數(shù)從廣泛應(yīng)用的現(xiàn)有實(shí)現(xiàn)中取得,許多這類(lèi)函數(shù)都包含在POSIX中。

主站蜘蛛池模板: 乡城县| 泸西县| 康平县| 仪陇县| 尼木县| 观塘区| 上思县| 德清县| 玉溪市| 玉田县| 全南县| 科技| 社旗县| 宝鸡市| 专栏| 浦城县| 丹巴县| 佛坪县| 化德县| 天台县| 华蓥市| 丁青县| 治多县| 石景山区| 济宁市| 邹城市| 常德市| 日土县| 仁布县| 邵阳市| 长治县| 西宁市| 札达县| 海原县| 伊通| 托克托县| SHOW| 庆阳市| 万山特区| 区。| 久治县|