C89 and C99 are pretty clear that specifying a precision on a %s directive to printf prevents reading more than that many bytes from the argument and that in that case no null terminator is required:
s If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.237) 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. But running valgrind on test-vasnprintf when USE_SNPRINTF is not selected, when the appended patch to test-vasnprintf.c is applied, makes it clear that vasnprintf() will read beyond the specified precision: ==3968== Conditional jump or move depends on uninitialised value(s) ==3968== at 0x40239D7: strlen (mc_replace_strmem.c:242) ==3968== by 0x8049065: vasnprintf (vasnprintf.c:4044) ==3968== by 0x8048655: my_asnprintf (test-vasnprintf.c:47) ==3968== by 0x80488F6: main (test-vasnprintf.c:131) The culprit is pretty clearly this code in lib/vasnprintf.c: case 's': [...] tmp_length = strlen (a.arg[dp->arg_index].a.a_string); break; The obvious solution would be to use strnlen in place of strlen here, but I don't know whether you would object to the additional dependency. Maybe you want to introduce a "local_strnlen" function instead. Something similar would be needed for the wide-character case (presumably a "local_wcsnlen"). diff --git a/tests/test-vasnprintf.c b/tests/test-vasnprintf.c index 2f3f890..50c6956 100644 --- a/tests/test-vasnprintf.c +++ b/tests/test-vasnprintf.c @@ -119,10 +119,24 @@ test_asnprintf () } } +static void +test_precision (void) +{ + size_t length = 0; + char *p, *s; + + p = malloc (2); + ASSERT (p != NULL); + *p = 'x'; + s = my_asnprintf (NULL, &length, "%.1s", p); + ASSERT (!strcmp (s, "x")); +} + int main (int argc, char *argv[]) { test_vasnprintf (); test_asnprintf (); + test_precision (); return 0; } -- Ben Pfaff http://benpfaff.org