From f533c3b2a4f5b0c71c3c432ef5c5d133be8acb20 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 26 Nov 2015 15:21:46 +0100 Subject: sprintf considered safer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- include/stdio.h | 30 ++++++++++++++++++++++++++++++ src/stdio/printf.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/include/stdio.h b/include/stdio.h index c1b4a09..5c2f6ca 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -184,6 +184,36 @@ int sockprintf(int, int, const char* restrict, ...) * This is identical to `snprintf` with * `SIZE_MAX` as the second argument. * + * `sprintf` is(!) safe to use. As long as you allocate + * the a large enough buffer. One way to do this is + * by measuring the length of the result first. + * + * ssize_t n; + * char* buffer = NULL; + * snprintf(NULL, 0, "%zu%zn", your_value, &n); + * buffer = malloc((size_t)n * sizeof(char)); + * if (buffer == NULL) goto fail; + * sprintf(buffer, "%zu", your_value); + * + * If you don't care about portability, you can use + * `asprintf`, `asprintfa` or `bprintf`. However, you + * often do not need to measure the result with `snprintf`. + * A maximum possible length can often be determined + * at compile-time or only using `strlen'. + * + * char buffer[3 * sizeof(ssize_t) + 2]; // A very poor, but still safe, + * // approximation to log₁₀. + * spritnf(buffer, "%zi", your_signed_value); + * + * These techniques guarantees that all of the string is + * written, and is therefore preferable over replacing + * `sprintf` with `snprintf`. Because of this, slibc + * does not consider `sprintf` unsafe like some of the + * more hokey C standard library implementations. This + * is C damn it! + * + * “Almost anything can be unsafe if you don't use it properly.” + * * @param buffer The output buffer. * @param format The formatting-string. * @param ... The formatting-arguments. diff --git a/src/stdio/printf.c b/src/stdio/printf.c index 4c5bae9..53be281 100644 --- a/src/stdio/printf.c +++ b/src/stdio/printf.c @@ -495,6 +495,36 @@ int sockprintf(int fd, int flags, const char* format restrict, ...) * This is identical to `snprintf` with * `SIZE_MAX` as the second argument. * + * `sprintf` is(!) safe to use. As long as you allocate + * the a large enough buffer. One way to do this is + * by measuring the length of the result first. + * + * ssize_t n; + * char* buffer = NULL; + * snprintf(NULL, 0, "%zu%zn", your_value, &n); + * buffer = malloc((size_t)n * sizeof(char)); + * if (buffer == NULL) goto fail; + * sprintf(buffer, "%zu", your_value); + * + * If you don't care about portability, you can use + * `asprintf`, `asprintfa` or `bprintf`. However, you + * often do not need to measure the result with `snprintf`. + * A maximum possible length can often be determined + * at compile-time or only using `strlen'. + * + * char buffer[3 * sizeof(ssize_t) + 2]; // A very poor, but still safe, + * // approximation to log₁₀. + * spritnf(buffer, "%zi", your_signed_value); + * + * These techniques guarantees that all of the string is + * written, and is therefore preferable over replacing + * `sprintf` with `snprintf`. Because of this, slibc + * does not consider `sprintf` unsafe like some of the + * more hokey C standard library implementations. This + * is C damn it! + * + * “Almost anything can be unsafe if you don't use it properly.” + * * @param buffer The output buffer. * @param format The formatting-string. * @param ... The formatting-arguments. -- cgit v1.2.3-70-g09d2