printf:这样安全吗?

时间:2014-10-09 15:12:55

标签: c 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 ? */
}

3 个答案:

答案 0 :(得分:6)

是的,你将打印出256个字符,仅此而已。

来自C11-Standard 7.21.6。 p4:

  

提供最小位数的可选精度   出现在d,i,o,u,x和X转换中,数字位数   出现在a,a,e,E,f和F的小数点字符之后   转换次数,g和G的最大有效位数   转换,或要为s写入的最大字节数   转换。精度采用句点(。)的形式   通过星号*(稍后描述)或可选的小数   整数;如果仅指定了句点,则精度为   零。如果精度与任何其他转换说明符一起出现,则   行为未定义。

7.21.6.1。 P8:

  

s:   如果不存在l length修饰符,则参数应为指向initial的指针   字符数组的元素。数组中的字符是   写入(但不包括)终止空字符。如果   指定精度,不超过写入的多个字节。如果   精度未指定或大于数组的大小,数组应   包含空字符。

答案 1 :(得分: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.

/lib/vsprintf.c 中的函数 vsnprintf 调用 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;
}

答案 2 :(得分: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]如果未指定精度或大于数组的大小,则数组应包含空字符。