From 0240baa42de554a7eb103020c2d53373d3468b31 Mon Sep 17 00:00:00 2001 From: Ben Wiederhake Date: Sun, 16 Aug 2020 01:37:32 +0200 Subject: [PATCH] AK+Kernel: Support snprintf In contrast to sprintf, which might overflow the given buffer. I feel bad about the code duplication, but that is a pre-existing issue. --- AK/kstdio.h | 1 + Kernel/kprintf.cpp | 28 ++++++++++++++++++++++++++++ Kernel/kstdio.h | 1 + 3 files changed, 30 insertions(+) diff --git a/AK/kstdio.h b/AK/kstdio.h index 78ca52bc9a6374..98f69caeb2a8a7 100644 --- a/AK/kstdio.h +++ b/AK/kstdio.h @@ -37,6 +37,7 @@ int vdbgprintf(const char* fmt, va_list); int dbgprintf(const char* fmt, ...); ssize_t dbgputstr(const char*, ssize_t); int sprintf(char* buf, const char* fmt, ...); +int snprintf(char* buffer, size_t, const char* fmt, ...); } # endif #else diff --git a/Kernel/kprintf.cpp b/Kernel/kprintf.cpp index 3e2eff5b04c41b..6834ce00bd0fe0 100644 --- a/Kernel/kprintf.cpp +++ b/Kernel/kprintf.cpp @@ -144,6 +144,34 @@ int sprintf(char* buffer, const char* fmt, ...) return ret; } +static size_t __vsnprintf_space_remaining; +ALWAYS_INLINE void sized_buffer_putch(char*& bufptr, char ch) +{ + if (__vsnprintf_space_remaining) { + *bufptr++ = ch; + --__vsnprintf_space_remaining; + } +} + +int snprintf(char* buffer, size_t size, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (size) { + __vsnprintf_space_remaining = size - 1; + } else { + __vsnprintf_space_remaining = 0; + } + int ret = printf_internal(sized_buffer_putch, buffer, fmt, ap); + if (__vsnprintf_space_remaining) { + buffer[ret] = '\0'; + } else if (size > 0) { + buffer[size - 1] = '\0'; + } + va_end(ap); + return ret; +} + static void debugger_out(char ch) { if (serial_debug) diff --git a/Kernel/kstdio.h b/Kernel/kstdio.h index b6f3d17cf96328..32f3b1adda32b1 100644 --- a/Kernel/kstdio.h +++ b/Kernel/kstdio.h @@ -34,6 +34,7 @@ int dbgputstr(const char*, int); int kernelputstr(const char*, int); int kprintf(const char* fmt, ...); int sprintf(char* buf, const char* fmt, ...); +int snprintf(char* buf, size_t, const char* fmt, ...); void set_serial_debug(bool on_or_off); int get_serial_debug(); }