From: Eugene Syromiatnikov Date: Fri, 15 Aug 2025 14:00:50 +0000 (+0200) Subject: crypto/bio/bio_print.c: make %n in line with other libc implementations X-Git-Tag: openssl-3.6.0-alpha1~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=228ef5f5472790e64c14596ef6d3d698875ffd61;p=thirdparty%2Fopenssl.git crypto/bio/bio_print.c: make %n in line with other libc implementations The standard[1] is pretty vague in its definition of the %n specifier by using "the number of bytes written to the output so far", without actually elaborating, whether only the actually written bytes, or the bytes that would be written (but discarded) are used; the consensus across implementations, however, seems to gravitate towards the latter. Track the virtual "write position" separately and use its value when %n format is occurred. That also means that we cannot finish the output early upon reach of the end of buffer (unless we made sure that no %n specifiers occur in the remainder of the format string). [1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html Signed-off-by: Eugene Syromiatnikov Reviewed-by: Saša Nedvědický Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/28177) --- diff --git a/crypto/bio/bio_print.c b/crypto/bio/bio_print.c index 82aecf82acf..186c3cdef2b 100644 --- a/crypto/bio/bio_print.c +++ b/crypto/bio/bio_print.c @@ -37,6 +37,8 @@ struct pr_desc { size_t currlen; /** Buffer size */ size_t maxlen; + /** "Write position", for proper %n support */ + long long pos; }; static int fmtstr(struct pr_desc *, const char *, int, int, int); @@ -110,7 +112,7 @@ _dopr(char **sbuffer, int state; int flags; int cflags; - struct pr_desc desc = { *sbuffer, buffer, 0, *maxlen }; + struct pr_desc desc = { *sbuffer, buffer, 0, *maxlen, 0 }; int ret = 0; state = DP_S_DEFAULT; @@ -119,7 +121,7 @@ _dopr(char **sbuffer, ch = *format++; while (state != DP_S_DONE) { - if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) + if (ch == '\0') state = DP_S_DONE; switch (state) { @@ -388,11 +390,7 @@ _dopr(char **sbuffer, goto out; break; case 'n': - { - int *num; - - num = va_arg(args, int *); - *num = (int)desc.currlen; + *num = (int)desc.pos; } break; case '%': @@ -941,6 +939,8 @@ doapr_outch(struct pr_desc *desc, int c) (*(desc->buffer))[(desc->currlen)++] = (char)c; } + desc->pos++; + return 1; }