Message ID | d25f0a580fde5721d594492cbb8a37d38b53c702.1707491940.git.fweimer@redhat.com |
---|---|
State | New |
Headers | show |
Series | Build getdomainname, gethostname, syslog with fortification | expand |
On 09/02/24 12:25, Florian Weimer wrote: > Use of Xprintf_buffer_done is unnecessary because it performs > overflow detection against int and sets errno. > --- > stdio-common/Makefile | 1 + > stdio-common/tst-printf-large-n.c | 81 +++++++++++++++++++++++++++++ > stdio-common/vfprintf-process-arg.c | 2 +- > 3 files changed, 83 insertions(+), 1 deletion(-) > create mode 100644 stdio-common/tst-printf-large-n.c > > diff --git a/stdio-common/Makefile b/stdio-common/Makefile > index d610ed67e6..482d841f96 100644 > --- a/stdio-common/Makefile > +++ b/stdio-common/Makefile > @@ -234,6 +234,7 @@ tests := \ > tst-printf-fp-free \ > tst-printf-fp-leak \ > tst-printf-intn \ > + tst-printf-large-n \ > tst-printf-oct \ > tst-printf-round \ > tst-printfsz \ > diff --git a/stdio-common/tst-printf-large-n.c b/stdio-common/tst-printf-large-n.c > new file mode 100644 > index 0000000000..4504a693d2 > --- /dev/null > +++ b/stdio-common/tst-printf-large-n.c > @@ -0,0 +1,81 @@ > +/* Test that %n can report values larger than INT_MAX. > + Copyright (C) 2024 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 > + <https://www.gnu.org/licenses/>. */ > + > +#include <errno.h> > +#include <limits.h> > +#include <stdio.h> > +#include <wchar.h> > + > +#include <support/blob_repeat.h> > +#include <support/check.h> > +#include <support/xstdio.h> > + > +static int > +do_test (void) > +{ > + enum { string_length = 1 << 28 }; > + > + FILE *fp = xfopen ("/dev/null", "w"); > + > + /* Byte-oriented streams. */ > + { > + struct support_blob_repeat repeat > + = support_blob_repeat_allocate ("a", 1, string_length + 1); > + char *string = repeat.start; > + if (string == NULL) > + FAIL_UNSUPPORTED ("cannot allocate large string"); > + string[string_length] = '\0'; > + > + long long int n; Indentation seems off here. > + TEST_COMPARE (fprintf (fp, "%s %s %s %s %s %s %s %s %lln", > + string, string, string, string, string, string, > + string, string, &n), -1); > + TEST_COMPARE (errno, EOVERFLOW); > + TEST_COMPARE (n, 8 * (string_length + 1LL)); > + TEST_VERIFY (n > INT_MAX); > + > + support_blob_repeat_free (&repeat); Here as well. > + } > + > + /* Wide-oriented streams. */ > + { > + struct support_blob_repeat repeat > + = support_blob_repeat_allocate (L"a", sizeof (wchar_t), > + string_length + 1); > + wchar_t *string = repeat.start; > + if (string == NULL) > + FAIL_UNSUPPORTED ("cannot allocate large wide string"); > + string[string_length] = '\0'; It should not matter, but maybe L'\0' here? > + > + long long int n; > + TEST_COMPARE (fwprintf (fp, L"%Ls %Ls %Ls %Ls %Ls %Ls %Ls %Ls %lln", > + string, string, string, string, string, string, > + string, string, &n), -1); > + TEST_COMPARE (errno, EOVERFLOW); > + TEST_COMPARE (n, 8 * (string_length + 1LL)); > + TEST_VERIFY (n > INT_MAX); > + > + support_blob_repeat_free (&repeat); > + } > + > + xfclose (fp); > + > + return 0; > +} > + > +#include <support/test-driver.c> > diff --git a/stdio-common/vfprintf-process-arg.c b/stdio-common/vfprintf-process-arg.c > index af6b570ea9..dbc78d4942 100644 > --- a/stdio-common/vfprintf-process-arg.c > +++ b/stdio-common/vfprintf-process-arg.c > @@ -337,7 +337,7 @@ LABEL (form_number): > } > /* Answer the count of characters written. */ > void *ptrptr = process_arg_pointer (); > - unsigned int written = Xprintf_buffer_done (buf); > + uint64_t written = buf->written + (buf->write_ptr - buf->write_base); > if (is_longlong) > *(long long int *) ptrptr = written; > else if (is_long_num) This is strictly an alias violation, but the rest of the code follow this pattern so it should be ok.
diff --git a/stdio-common/Makefile b/stdio-common/Makefile index d610ed67e6..482d841f96 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -234,6 +234,7 @@ tests := \ tst-printf-fp-free \ tst-printf-fp-leak \ tst-printf-intn \ + tst-printf-large-n \ tst-printf-oct \ tst-printf-round \ tst-printfsz \ diff --git a/stdio-common/tst-printf-large-n.c b/stdio-common/tst-printf-large-n.c new file mode 100644 index 0000000000..4504a693d2 --- /dev/null +++ b/stdio-common/tst-printf-large-n.c @@ -0,0 +1,81 @@ +/* Test that %n can report values larger than INT_MAX. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <wchar.h> + +#include <support/blob_repeat.h> +#include <support/check.h> +#include <support/xstdio.h> + +static int +do_test (void) +{ + enum { string_length = 1 << 28 }; + + FILE *fp = xfopen ("/dev/null", "w"); + + /* Byte-oriented streams. */ + { + struct support_blob_repeat repeat + = support_blob_repeat_allocate ("a", 1, string_length + 1); + char *string = repeat.start; + if (string == NULL) + FAIL_UNSUPPORTED ("cannot allocate large string"); + string[string_length] = '\0'; + + long long int n; + TEST_COMPARE (fprintf (fp, "%s %s %s %s %s %s %s %s %lln", + string, string, string, string, string, string, + string, string, &n), -1); + TEST_COMPARE (errno, EOVERFLOW); + TEST_COMPARE (n, 8 * (string_length + 1LL)); + TEST_VERIFY (n > INT_MAX); + + support_blob_repeat_free (&repeat); + } + + /* Wide-oriented streams. */ + { + struct support_blob_repeat repeat + = support_blob_repeat_allocate (L"a", sizeof (wchar_t), + string_length + 1); + wchar_t *string = repeat.start; + if (string == NULL) + FAIL_UNSUPPORTED ("cannot allocate large wide string"); + string[string_length] = '\0'; + + long long int n; + TEST_COMPARE (fwprintf (fp, L"%Ls %Ls %Ls %Ls %Ls %Ls %Ls %Ls %lln", + string, string, string, string, string, string, + string, string, &n), -1); + TEST_COMPARE (errno, EOVERFLOW); + TEST_COMPARE (n, 8 * (string_length + 1LL)); + TEST_VERIFY (n > INT_MAX); + + support_blob_repeat_free (&repeat); + } + + xfclose (fp); + + return 0; +} + +#include <support/test-driver.c> diff --git a/stdio-common/vfprintf-process-arg.c b/stdio-common/vfprintf-process-arg.c index af6b570ea9..dbc78d4942 100644 --- a/stdio-common/vfprintf-process-arg.c +++ b/stdio-common/vfprintf-process-arg.c @@ -337,7 +337,7 @@ LABEL (form_number): } /* Answer the count of characters written. */ void *ptrptr = process_arg_pointer (); - unsigned int written = Xprintf_buffer_done (buf); + uint64_t written = buf->written + (buf->write_ptr - buf->write_base); if (is_longlong) *(long long int *) ptrptr = written; else if (is_long_num)