From 0060a6de5493aeb4af457511e9b9ab532a6930a5 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 23 May 2022 10:08:18 +0200 Subject: [PATCH] stdio-common: Add tst-memstream-string for open_memstream overflow This code path is exercised indirectly by some of the DNS stub resolver tests, via their own use of xopen_memstream for constructing strings describing result data. The relative lack of test suite coverage became apparent when these tests starting failing after a printf changes uncovered bug 28949. Reviewed-by: Adhemerval Zanella --- stdio-common/Makefile | 3 ++ stdio-common/tst-memstream-string.c | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 stdio-common/tst-memstream-string.c diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 2750334..b1e9144 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -175,6 +175,7 @@ tests := \ tst-gets \ tst-grouping \ tst-long-dbl-fphex \ + tst-memstream-string \ tst-obprintf \ tst-perror \ tst-popen \ @@ -390,6 +391,8 @@ CFLAGS-tst-gets.c += -Wno-deprecated-declarations # the fortified version had the same bug. CFLAGS-tst-bz11319-fortify2.c += -D_FORTIFY_SOURCE=2 +CFLAGS-tst-memstream-string.c += -fno-builtin-fprintf + CPPFLAGS += $(libio-mtsafe) $(objpfx)tst-setvbuf1.out: /dev/null $(objpfx)tst-setvbuf1 diff --git a/stdio-common/tst-memstream-string.c b/stdio-common/tst-memstream-string.c new file mode 100644 index 0000000..0a31e0c --- /dev/null +++ b/stdio-common/tst-memstream-string.c @@ -0,0 +1,77 @@ +/* Test writing differently sized strings to a memstream. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Returns a printable ASCII character based on INDEX. */ +static inline char +char_from_index (unsigned int index) +{ + return ' ' + (index % 95); +} + +enum { result_size = 25000 }; + +static void +run_one_size (unsigned int chunk_size) +{ + char *chunk = xmalloc (chunk_size + 1); + + struct xmemstream mem; + xopen_memstream (&mem); + unsigned int written = 0; + for (unsigned int i = 0; i < result_size; ) + { + unsigned int to_print = result_size - i; + if (to_print > chunk_size) + to_print = chunk_size; + for (unsigned int j = 0; j < to_print; ++j) + chunk[j] = char_from_index(i + j); + chunk[to_print] = '\0'; + fprintf (mem.out, "%s", chunk); /* Needs -fno-builtin-fprintf. */ + i += to_print; + written += strlen(chunk); + } + xfclose_memstream (&mem); + + TEST_COMPARE (written, result_size); + TEST_COMPARE (mem.length, result_size); + TEST_COMPARE (strlen (mem.buffer), result_size); + + for (unsigned int i = 0; i < result_size; ++i) + TEST_COMPARE (mem.buffer[i], char_from_index (i)); + + free (mem.buffer); + free (chunk); +} + +static int +do_test (void) +{ + for (unsigned int chunk_size = 1; chunk_size <= 30; ++ chunk_size) + run_one_size (chunk_size); + + return 0; +} + +#include -- 2.7.4