py/mpprint: Fix length calculation for strings with precision-modifier.

Two issues are tackled:

1. The calculation of the correct length to print is fixed to treat the
   precision as a maximum length instead as the exact length.
   This is done for both qstr (%q) and for regular str (%s).

2. Fix the incorrect use of mp_printf("%.*s") to mp_print_strn().

   Because of the fix of above issue, some testcases that would print
   an embedded null-byte (^@ in test-output) would now fail.
   The bug here is that "%s" was used to print null-bytes. Instead,
   mp_print_strn is used to make sure all bytes are outputted and the
   exact length is respected.

Test-cases are added for both %s and %q with a combination of precision
and padding specifiers.
This commit is contained in:
Joris Peeraer 2020-10-22 10:38:03 +02:00 committed by Damien George
parent dde0735ac1
commit 5020b14d54
5 changed files with 12 additions and 11 deletions

View File

@ -186,7 +186,7 @@ STATIC mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%ld\n", 123); // long
mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex
mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex
mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision
mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision
mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision
mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools
#ifndef NDEBUG

View File

@ -484,10 +484,10 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
qstr qst = va_arg(args, qstr);
size_t len;
const char *str = (const char *)qstr_data(qst, &len);
if (prec < 0) {
prec = len;
if (prec >= 0 && (size_t)prec < len) {
len = prec;
}
chrs += mp_print_strn(print, str, prec, flags, fill, width);
chrs += mp_print_strn(print, str, len, flags, fill, width);
break;
}
case 's': {
@ -499,10 +499,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
break;
}
#endif
if (prec < 0) {
prec = strlen(str);
size_t len = strlen(str);
if (prec >= 0 && (size_t)prec < len) {
len = prec;
}
chrs += mp_print_strn(print, str, prec, flags, fill, width);
chrs += mp_print_strn(print, str, len, flags, fill, width);
break;
}
case 'd': {

View File

@ -123,10 +123,10 @@ STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
bool is_bytes = true;
#endif
if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {
mp_printf(print, "%.*s", str_len, str_data);
print->print_strn(print->data, (const char *)str_data, str_len);
} else {
if (is_bytes) {
mp_print_str(print, "b");
print->print_strn(print->data, "b", 1);
}
mp_str_print_quoted(print, str_data, str_len, is_bytes);
}

View File

@ -92,7 +92,7 @@ STATIC void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
}
#endif
if (kind == PRINT_STR) {
mp_printf(print, "%.*s", str_len, str_data);
print->print_strn(print->data, (const char *)str_data, str_len);
} else {
uni_print_quoted(print, str_data, str_len);
}

View File

@ -4,7 +4,7 @@
123
123
1ABCDEF
ab abc
ab abc ' abc' ' True' 'Tru'
false true
(null)