aboutsummaryrefslogtreecommitdiffstats
path: root/man3/printf.3
diff options
context:
space:
mode:
authorTobias Stoeckmann <tobias@stoeckmann.org>2020-05-21 14:15:06 +0200
committerMichael Kerrisk <mtk.manpages@gmail.com>2020-05-25 15:59:42 +0200
commit7577e4074b375acb55fb95d799adb800807933e3 (patch)
tree161f63d185349d53cda41fcb6e099c2cd2351af1 /man3/printf.3
parent9a766452249b3a9e2e1252bd563e3a04186df68c (diff)
downloadman-pages-7577e4074b375acb55fb95d799adb800807933e3.tar.gz
printf.3: Prevent signed integer overflow in example
The function make_message illustrates how to use vsnprintf to determine the required amount of memory for a specific format and its arguments. If make_message is called with a format which will use exactly INT_MAX characters (excluding '\0'), then the size++ calculation will overflow the signed integer "size", which is an undefined behaviour in C. Since malloc and vsnprintf rightfully take a size_t argument, I decided to use a size_t variable for size calculation. Therefore, this patched code uses variables of the same data types as expected by function arguments. Proof of concept (tested on Linux/glibc amd64): int main() { make_message("%647s%2147483000s", "", ""); } If the code is compiled with address sanitizer (gcc -fsanitize=address) you can see the following line, assuming that a signed integer overflow simply leads to INT_MIN: ==3094==WARNING: AddressSanitizer failed to allocate 0xffffffff80000000 bytes Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
Diffstat (limited to 'man3/printf.3')
-rw-r--r--man3/printf.315
1 files changed, 9 insertions, 6 deletions
diff --git a/man3/printf.3 b/man3/printf.3
index 50e136ba60..827d9cbae6 100644
--- a/man3/printf.3
+++ b/man3/printf.3
@@ -1132,29 +1132,32 @@ To allocate a sufficiently large string and print into it
char *
make_message(const char *fmt, ...)
{
- int size = 0;
+ int n = 0;
+ size_t size = 0;
char *p = NULL;
va_list ap;
/* Determine required size */
va_start(ap, fmt);
- size = vsnprintf(p, size, fmt, ap);
+ n = vsnprintf(p, size, fmt, ap);
va_end(ap);
- if (size < 0)
+ if (n < 0)
return NULL;
- size++; /* For '\e0' */
+ /* One extra byte for '\e0' */
+
+ size = (size_t) n + 1;
p = malloc(size);
if (p == NULL)
return NULL;
va_start(ap, fmt);
- size = vsnprintf(p, size, fmt, ap);
+ n = vsnprintf(p, size, fmt, ap);
va_end(ap);
- if (size < 0) {
+ if (n < 0) {
free(p);
return NULL;
}