I am just wondering if this expression is safe :
int main (void)
{
char my_tab[256];
memset(my_tab,0x61,sizeof(my_tab));
printf(\"Is it safe ? : %.2
Yes, this should be safe. Implementations that try accessing the character past the end of the buffer should be considered invalid.
Pseudocode for processing %.Ns
, where N
is a number, should look as follows:
size_t count = 0;
size_t N = ...;
char *ptr = <next-arg>;
while (count < N && *ptr != '\0') {
putchar(*ptr++);
count++;
}
Note that the above code will never reference the character past N
.
One could imagine an implementation which inverts the condition of the while
loop, which would access the byte past the end of the buffer. However, such implementation would be invalid, because according to the standard it is legal for an implementation to require a null terminator only if the size is not specified, or it is greater than the number of characters that you have passed:
[7.19.6.1.8] If the precision is not specified or is greater than the size of the array, the array shall contain a null character.
It's safe.
From printf(3) - Linux manual page 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.
Function vsnprintf in /lib/vsprintf.c call strnlen(s, spec.precision) to get the lenth of the string to be formatted:
/**
* 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;
}
Only the valid char bytes will be accessed.
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;
}
Yes, you will print out 256 characters, and nothing more.
From the C11-Standard 7.21.6. p4:
An optional precision that gives the minimum number of digits to appear for the d, i, o, u, x, and X conversions, the number of digits to appear after the decimal-point character for a, A, e, E, f, and F conversions, the maximum number of significant digits for the g and G conversions, or the maximum number of bytes to be written for s conversions. The precision takes the form of a period (.) followed either by an asterisk * (described later) or by an optional decimal integer; if only the period is specified, the precision is taken as zero. If a precision appears with any other conversion specifier, the behavior is undefined.
7.21.6.1. p8:
s : If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type. Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more than that many bytes are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.