diff options
Diffstat (limited to 'libio')
-rw-r--r-- | libio/Makefile | 2 | ||||
-rw-r--r-- | libio/stdio.h | 64 | ||||
-rw-r--r-- | libio/tst-freopen.c | 37 | ||||
-rw-r--r-- | libio/tst-popen1.c | 4 | ||||
-rw-r--r-- | libio/tst-wmemstream1.c | 35 | ||||
-rw-r--r-- | libio/tst-wmemstream5.c | 57 |
6 files changed, 174 insertions, 25 deletions
diff --git a/libio/Makefile b/libio/Makefile index ed0ce4ee81..73f731e064 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -61,7 +61,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \ tst-memstream1 tst-memstream2 tst-memstream3 tst-memstream4 \ tst-wmemstream1 tst-wmemstream2 tst-wmemstream3 tst-wmemstream4 \ - bug-memstream1 bug-wmemstream1 \ + tst-wmemstream5 bug-memstream1 bug-wmemstream1 \ tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \ diff --git a/libio/stdio.h b/libio/stdio.h index 76bda3728e..497da016ff 100644 --- a/libio/stdio.h +++ b/libio/stdio.h @@ -165,22 +165,34 @@ extern int renameat2 (int __oldfd, const char *__old, int __newfd, const char *__new, unsigned int __flags) __THROW; #endif +/* Close STREAM. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern int fclose (FILE *__stream); + +#undef __attr_dealloc_fclose +#define __attr_dealloc_fclose __attr_dealloc (fclose, 1) + /* Create a temporary file and open it read/write. This function is a possible cancellation point and therefore not marked with __THROW. */ #ifndef __USE_FILE_OFFSET64 -extern FILE *tmpfile (void) __wur; +extern FILE *tmpfile (void) + __attribute_malloc__ __attr_dealloc_fclose __wur; #else # ifdef __REDIRECT -extern FILE *__REDIRECT (tmpfile, (void), tmpfile64) __wur; +extern FILE *__REDIRECT (tmpfile, (void), tmpfile64) + __attribute_malloc__ __attr_dealloc_fclose __wur; # else # define tmpfile tmpfile64 # endif #endif #ifdef __USE_LARGEFILE64 -extern FILE *tmpfile64 (void) __wur; +extern FILE *tmpfile64 (void) + __attribute_malloc__ __attr_dealloc_fclose __wur; #endif /* Generate a temporary filename. */ @@ -202,15 +214,9 @@ extern char *tmpnam_r (char __s[L_tmpnam]) __THROW __wur; P_tmpdir is tried and finally "/tmp". The storage for the filename is allocated by `malloc'. */ extern char *tempnam (const char *__dir, const char *__pfx) - __THROW __attribute_malloc__ __wur; + __THROW __attribute_malloc__ __wur __attr_dealloc_free; #endif - -/* Close STREAM. - - This function is a possible cancellation point and therefore not - marked with __THROW. */ -extern int fclose (FILE *__stream); /* Flush STREAM, or all streams if STREAM is NULL. This function is a possible cancellation point and therefore not @@ -244,7 +250,8 @@ extern int fcloseall (void); This function is a possible cancellation point and therefore not marked with __THROW. */ extern FILE *fopen (const char *__restrict __filename, - const char *__restrict __modes) __wur; + const char *__restrict __modes) + __attribute_malloc__ __attr_dealloc_fclose __wur; /* Open a file, replacing an existing stream with it. This function is a possible cancellation point and therefore not @@ -256,7 +263,7 @@ extern FILE *freopen (const char *__restrict __filename, # ifdef __REDIRECT extern FILE *__REDIRECT (fopen, (const char *__restrict __filename, const char *__restrict __modes), fopen64) - __wur; + __attribute_malloc__ __attr_dealloc_fclose __wur; extern FILE *__REDIRECT (freopen, (const char *__restrict __filename, const char *__restrict __modes, FILE *__restrict __stream), freopen64) @@ -268,7 +275,8 @@ extern FILE *__REDIRECT (freopen, (const char *__restrict __filename, #endif #ifdef __USE_LARGEFILE64 extern FILE *fopen64 (const char *__restrict __filename, - const char *__restrict __modes) __wur; + const char *__restrict __modes) + __attribute_malloc__ __attr_dealloc_fclose __wur; extern FILE *freopen64 (const char *__restrict __filename, const char *__restrict __modes, FILE *__restrict __stream) __wur; @@ -276,7 +284,8 @@ extern FILE *freopen64 (const char *__restrict __filename, #ifdef __USE_POSIX /* Create a new stream that refers to an existing system file descriptor. */ -extern FILE *fdopen (int __fd, const char *__modes) __THROW __wur; +extern FILE *fdopen (int __fd, const char *__modes) __THROW + __attribute_malloc__ __attr_dealloc_fclose __wur; #endif #ifdef __USE_GNU @@ -284,21 +293,30 @@ extern FILE *fdopen (int __fd, const char *__modes) __THROW __wur; and uses the given functions for input and output. */ extern FILE *fopencookie (void *__restrict __magic_cookie, const char *__restrict __modes, - cookie_io_functions_t __io_funcs) __THROW __wur; + cookie_io_functions_t __io_funcs) __THROW + __attribute_malloc__ __attr_dealloc_fclose __wur; #endif #if defined __USE_XOPEN2K8 || __GLIBC_USE (LIB_EXT2) /* Create a new stream that refers to a memory buffer. */ extern FILE *fmemopen (void *__s, size_t __len, const char *__modes) - __THROW __wur; + __THROW __attribute_malloc__ __attr_dealloc_fclose __wur; /* Open a stream that writes into a malloc'd buffer that is expanded as necessary. *BUFLOC and *SIZELOC are updated with the buffer's location and the number of characters written on fflush or fclose. */ -extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __THROW __wur; +extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __THROW + __attribute_malloc__ __attr_dealloc_fclose __wur; + +#ifdef _WCHAR_H +/* Like OPEN_MEMSTREAM, but the stream is wide oriented and produces + a wide character string. Declared here only to add attribute malloc + and only if <wchar.h> has been previously #included. */ +extern __FILE *open_wmemstream (wchar_t **__bufloc, size_t *__sizeloc) __THROW + __attribute_malloc__ __attr_dealloc_fclose; +# endif #endif - /* If BUF is NULL, make STREAM unbuffered. Else make it use buffer BUF, of size BUFSIZ. */ extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __THROW; @@ -792,17 +810,19 @@ extern int fileno_unlocked (FILE *__stream) __THROW __wur; #ifdef __USE_POSIX2 -/* Create a new stream connected to a pipe running the given command. +/* Close a stream opened by popen and return the status of its child. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern FILE *popen (const char *__command, const char *__modes) __wur; +extern int pclose (FILE *__stream); -/* Close a stream opened by popen and return the status of its child. +/* Create a new stream connected to a pipe running the given command. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int pclose (FILE *__stream); +extern FILE *popen (const char *__command, const char *__modes) + __attribute_malloc__ __attr_dealloc (pclose, 1) __wur; + #endif diff --git a/libio/tst-freopen.c b/libio/tst-freopen.c index 660882a28a..c8bc0a3d07 100644 --- a/libio/tst-freopen.c +++ b/libio/tst-freopen.c @@ -81,6 +81,42 @@ do_test_basic (void) fclose (f); } +#if defined __GNUC__ && __GNUC__ >= 11 +/* Force an error to detect incorrectly making freopen a deallocator + for its last argument via attribute malloc. The function closes + the stream without deallocating it so either the argument or + the pointer returned from the function (but not both) can be passed + to fclose. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic error "-Wmismatched-dealloc" +#endif + +/* Verify that freopen returns stream. */ +static void +do_test_return_stream (void) +{ + FILE *f1 = fopen (name, "r"); + if (f1 == NULL) + FAIL_EXIT1 ("fopen: %m"); + + FILE *f2 = freopen (name, "r+", f1); + if (f2 == NULL) + FAIL_EXIT1 ("freopen: %m"); + + /* Verify that freopen isn't declared with the no-argument attribute + malloc (which could let GCC fold the inequality to false). */ + if (f1 != f2) + FAIL_EXIT1 ("freopen returned a different stream"); + + /* This shouldn't trigger -Wmismatched-dealloc. */ + fclose (f1); +} + +#if defined __GNUC__ && __GNUC__ >= 11 +/* Pop -Wmismatched-dealloc set to error above. */ +# pragma GCC diagnostic pop +#endif + /* Test for BZ#21398, where it tries to freopen stdio after the close of its file descriptor. */ static void @@ -105,6 +141,7 @@ do_test (void) { do_test_basic (); do_test_bz21398 (); + do_test_return_stream (); return 0; } diff --git a/libio/tst-popen1.c b/libio/tst-popen1.c index bae6615b9b..9f36b20090 100644 --- a/libio/tst-popen1.c +++ b/libio/tst-popen1.c @@ -21,7 +21,7 @@ do_test (void) res = 1; } - fclose (fp); + pclose (fp); } fp = popen ("echo hello", "re"); @@ -39,7 +39,7 @@ do_test (void) res = 1; } - fclose (fp); + pclose (fp); } return res; diff --git a/libio/tst-wmemstream1.c b/libio/tst-wmemstream1.c index f8b308bc6c..f80655b2a4 100644 --- a/libio/tst-wmemstream1.c +++ b/libio/tst-wmemstream1.c @@ -1,5 +1,40 @@ #include <wchar.h> +extern int fclose (FILE*); + +#if defined __GNUC__ && __GNUC__ >= 11 +/* Verify that calling fclose on the result of open_wmemstream doesn't + trigger GCC -Wmismatched-dealloc with fclose forward-declared and + without <stdio.h> included first (it is included later, in. + "tst-memstream1.c"). */ +#pragma GCC diagnostic push +#pragma GCC diagnostic error "-Wmismatched-dealloc" +#endif + +int test_open_wmemstream_no_stdio (void) +{ + { + wchar_t *buf; + size_t size; + FILE *f = open_wmemstream (&buf, &size); + fclose (f); + } + + { + FILE* (*pf)(wchar_t**, size_t*) = open_wmemstream; + wchar_t *buf; + size_t size; + FILE *f = pf (&buf, &size); + fclose (f); + } + return 0; +} + +#if defined __GNUC__ && __GNUC__ >= 11 +/* Restore -Wmismatched-dealloc setting. */ +# pragma GCC diagnostic pop +#endif + #define CHAR_T wchar_t #define W(o) L##o #define OPEN_MEMSTREAM open_wmemstream diff --git a/libio/tst-wmemstream5.c b/libio/tst-wmemstream5.c new file mode 100644 index 0000000000..47f5e63603 --- /dev/null +++ b/libio/tst-wmemstream5.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2021 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 <wchar.h> + +extern int fclose (FILE*); + +#if defined __GNUC__ && __GNUC__ >= 11 +/* Verify that calling fclose on the result of open_wmemstream doesn't + trigger GCC -Wmismatched-dealloc with fclose forward-declared and + without <stdio.h> included in the same translation unit. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic error "-Wmismatched-dealloc" +#endif + +static int +do_test (void) +{ + { + wchar_t *buf; + size_t size; + FILE *f = open_wmemstream (&buf, &size); + fclose (f); + } + + { + FILE* (*pf)(wchar_t**, size_t*) = open_wmemstream; + wchar_t *buf; + size_t size; + FILE *f = pf (&buf, &size); + fclose (f); + } + + return 0; +} + +#if defined __GNUC__ && __GNUC__ >= 11 +/* Restore -Wmismatched-dealloc setting. */ +# pragma GCC diagnostic pop +#endif + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |