2014-10-09 122 views
4

我只是想知道,如果這個表達式是安全的:printf:這安全嗎?

int main (void) 
{ 
    char my_tab[256]; 

    memset(my_tab,0x61,sizeof(my_tab)); 

    printf("Is it safe ? : %.256s",my_tab); /* is it safe ? */ 
} 
+1

如果'0x61'對應於「安全」字符(我建議使用''a''代替),它是安全的 - 不是每個計算機在那裏使用ASCII :) – pmg 2014-10-09 15:20:42

+0

你說得對,我用0x61只是爲了得到與'\ 0'不同的東西 – Joze 2014-10-09 15:21:29

+2

爲了更加安全起見,您需要'#include '和'#include ' – pmg 2014-10-09 15:23:27

回答

6

是的,你會打印出256個字符,僅此而已。

從C11-標準7.21.6。 P4:

可選的精度給出的最小位數,以 出現爲d,I,O,U,X,和X轉換,數字 數到小數點字符之後出現對於a,e,E,f和F 轉換,g和G轉換的最大有效數字位數,或要寫入的最大字節數,用於s 轉換。精度採用句點(。)後跟 ,可以用星號*(稍後說明)或用可選小數 整數表示。如果僅指定週期,則精度爲 零。如果精度與任何其他轉換說明符一起出現,那麼 行爲是未定義的。

7.21.6.1。 P8:

S: 如果沒有升長度改性劑的存在,該參數將是指向字符類型的數組的初始 元件。寫入(但不包括)終止空字符的數組中的字符爲 。如果指定了 精度,則不會寫入超過這麼多的字節。如果 精度未指定或大於數組的大小,則數組應包含空字符 。

+0

我並不完全相信。假設執行'strlen()'來查明字符串有多長?所以它應該是安全的,但可能不是。 – JeremyP 2014-10-09 15:23:44

+4

@JeremyP如果我的實現這樣做,那麼我會想要我的錢回來! – ams 2014-10-09 15:24:58

+0

@JeremyP:問題是'printf()'不是'strlen()',不是嗎? – alk 2014-10-09 15:25:21

1

是的,這應該是安全的。嘗試訪問超過緩衝區末尾的字符的實現應被視爲無效。

僞處理%.Ns,其中N是一個數字,應該如下:

size_t count = 0; 
size_t N = ...; 
char *ptr = <next-arg>; 
while (count < N && *ptr != '\0') { 
    putchar(*ptr++); 
    count++; 
} 

注意上面的代碼將永遠不會引用字符過去N

可以想象一個實現,它將反轉while循環的條件,該循環將訪問超過緩衝區末尾的字節。但是,這樣的實現將是無效的,因爲根據標準,只有在未指定大小或者已經通過的字符數量大於要通過的字符數時,才需要空終止符是合法的:

[7.19.6.1.8]如果未指定精度或大於數組大小,則數組應包含空字符。

+0

「output_to_buffer」有一個很好的標準名稱:'putchar'。 :-) – 2014-10-09 15:30:11

+0

@R ..謝謝!我想我應該替換我的''。它不再是一個僞代碼,但:-) – dasblinkenlight 2014-10-09 15:32:43

2

它很安全。

從的printf(3) - Linux的手冊頁http://man7.org/linux/man-pages/man3/printf.3.html

s  If no l modifier is present: The const char * argument is 
      expected to be a pointer to an array of character type 
      (pointer to a string). Characters from the array are written 
      up to (but not including) a terminating null byte ('\0'); if a 
      precision is specified, no more than the number specified are 
      written. If a precision is given, no null byte need be 
      present; if the precision is not specified, or is greater than 
      the size of the array, the array must contain a terminating 
      null byte. 

功能vsnprintf/lib/vsprintf.c呼叫strnlen(S,spec.precision)以獲得要格式化的字符串的長度:

/** 
* strnlen - Find the length of a length-limited string 
* @s: The string to be sized 
* @count: The maximum number of bytes to search 
*/ 
size_t strnlen(const char *s, size_t count) 
{ 
    const char *sc; 

    for (sc = s; count-- && *sc != '\0'; ++sc) 
     /* nothing */; 
    return sc - s; 
} 

只有有效的char字節將被訪問。

static noinline_for_stack 
char *string(char *buf, char *end, const char *s, struct printf_spec spec) 
{ 
    int len, i; 

    if ((unsigned long)s < PAGE_SIZE) 
     s = "(null)"; 

    len = strnlen(s, spec.precision); 

    if (!(spec.flags & LEFT)) { 
     while (len < spec.field_width--) { 
      if (buf < end) 
       *buf = ' '; 
      ++buf; 
     } 
    } 
    for (i = 0; i < len; ++i) { 
     if (buf < end) 
      *buf = *s; 
     ++buf; ++s; 
    } 
    while (len < spec.field_width--) { 
     if (buf < end) 
      *buf = ' '; 
     ++buf; 
    } 

    return buf; 
} 
+0

「printf」,「vsnprintf」或「strnlen」的特定實現發生的事實不會阻塞一個不指向null的參數終止字符串僅與該特定實現相關。重要的一點是C標準要求它是安全的。一個特殊的'strlen'實現可能在給定一個空指針參數時表現良好,但是'strlen(NULL)'仍然有未定義的行爲。 – 2014-10-09 17:16:53