Skip to content
Permalink
Browse files

prf.c: remove arbitrary large stack buffer usage

The on-stack work buffer occupies 201 bytes by default. Now that we've
made the code able to cope with virtually unlimited width and precision
values, we can reduce stack usage to its strict minimum i.e. 25 bytes.

This allows for some additional sprintf tests exercizing wide results.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
  • Loading branch information...
Nicolas Pitre authored and nashif committed Jun 19, 2019
1 parent d28434b commit f286eda6f0c6841386faac6fb28906460d1748ef
Showing with 40 additions and 20 deletions.
  1. +7 −20 lib/libc/minimal/source/stdout/prf.c
  2. +33 −0 tests/lib/sprintf/src/main.c
@@ -16,25 +16,14 @@
#include <sys/types.h>
#include <sys/util.h>

#ifndef MAXFLD
#define MAXFLD 200
#endif

#ifndef EOF
#define EOF -1
#endif

#ifdef CONFIG_MINIMAL_LIBC_LL_PRINTF
#define VALTYPE long long
#define SIZEOF_VALTYPE __SIZEOF_LONG_LONG__
#else
#define VALTYPE long
#define SIZEOF_VALTYPE __SIZEOF_LONG__
#endif

/* this has to fit max range octal display */
#if MAXFLD < (1 + (SIZEOF_VALTYPE*8 + 2)/3)
#error buffer size MAXFLD is too small
#endif

static void _uc(char *buf)
@@ -442,12 +431,14 @@ static int _atoi(const char **sptr)
int z_prf(int (*func)(), void *dest, const char *format, va_list vargs)
{
/*
* Due the fact that buffer is passed to functions in this file,
* they assume that its size is MAXFLD + 1. In need of change
* the buffer size, either MAXFLD should be changed or the change
* has to be propagated across the file
* The work buffer has to accommodate for the largest data length.
* The max range octal length is one prefix + 3 bits per digit
* meaning 12 bytes on 32-bit and 23 bytes on 64-bit.
* The float code may extract up to 16 digits, plus a prefix,
* a leading 0, a dot, and an exponent in the form e+xxx for
* a total of 24. Add a trailing NULL so it is 25.
*/
char buf[MAXFLD + 1];
char buf[25];
char c;
int count;
char *cptr;
@@ -519,10 +510,6 @@ int z_prf(int (*func)(), void *dest, const char *format, va_list vargs)
precision = _atoi(&format);
}

if (precision > MAXFLD) {
precision = -1;
}

c = *format++;
}

@@ -216,6 +216,39 @@ void test_sprintf_double(void)
zassert_true((strcmp(buffer, "1234.567890") == 0),
"sprintf(-1.0) - incorrect output '%s'\n", buffer);

/*
* With very large precision, the output differs significantly in
* terms of string even if not in terms of actual value depending
* on the library used and FPU implementation. However the length
* and decimal position should remain identical.
*/
var.d = 0x1p800;
sprintf(buffer, "%.140f", var.d);
zassert_true((strlen(buffer) == 382),
"sprintf(<large output>) - incorrect length %d\n",
strlen(buffer));
buffer[10] = 0; /* log facility doesn't support %.10s */
zassert_true((strcmp(buffer, "6668014432") == 0),
"sprintf(<large output>) - starts with \"%s\" "
"expected \"6668014432\"\n", buffer);
zassert_true((buffer[241] == '.'),
"sprintf(<large output>) - expected '.' got '%c'\n",
buffer[241]);

var.d = 0x1p-400;
sprintf(buffer, "% .380f", var.d);
zassert_true((strlen(buffer) == 383),
"sprintf(<large output>) - incorrect length %d\n",
strlen(buffer));
buffer[10] = 0; /* log facility doesn't support %.10s */
zassert_true((strcmp(buffer, " 0.0000000") == 0),
"sprintf(<large output>) - starts with \"%s\" "
"expected \" 0.0000000\"\n", buffer);
buffer[119 + 10] = 0; /* log facility doesn't support %.10s */
zassert_true((strcmp(buffer + 119, "0000387259") == 0),
"sprintf(<large output>) - got \"%s\" "
"while expecting \"0000387259\"\n", buffer + 119);

/*******************/
var.d = 1234.0;
sprintf(buffer, "%e", var.d);

0 comments on commit f286eda

Please sign in to comment.
You can’t perform that action at this time.