* [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h @ 2023-05-18 17:25 Xi Ruoyao 2023-05-18 18:06 ` Alex Colomar 0 siblings, 1 reply; 9+ messages in thread From: Xi Ruoyao @ 2023-05-18 17:25 UTC (permalink / raw) To: libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell, Xi Ruoyao During the review of a GCC analyzer test case, we found most stdio functions accepting a FILE * argument expect it to be nonnull and just segfault when the argument is NULL. Add nonnull attribute for them. setbuf is well defined when __stream is NULL so it's not touched. For fputs, fgets, fread, fwrite, fprintf, vfprintf, and their unlocked version, if __stream is empty but there is nothing to read or write, they don't segfault and I'm not sure if the standard allows such a use so I left them out. --- libio/stdio.h | 119 ++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/libio/stdio.h b/libio/stdio.h index 4cf9f1c012..ae3d7295d4 100644 --- a/libio/stdio.h +++ b/libio/stdio.h @@ -232,7 +232,7 @@ extern char *tempnam (const char *__dir, const char *__pfx) This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int fflush (FILE *__stream); +extern int fflush (FILE *__stream) __nonnull ((1)); #ifdef __USE_MISC /* Faster versions when locking is not required. @@ -241,7 +241,7 @@ extern int fflush (FILE *__stream); cancellation point. But due to similarity with an POSIX interface or due to the implementation it is a cancellation point and therefore not marked with __THROW. */ -extern int fflush_unlocked (FILE *__stream); +extern int fflush_unlocked (FILE *__stream) __nonnull ((1)); #endif #ifdef __USE_GNU @@ -278,7 +278,7 @@ extern FILE *__REDIRECT (fopen, (const char *__restrict __filename, extern FILE *__REDIRECT (freopen, (const char *__restrict __filename, const char *__restrict __modes, FILE *__restrict __stream), freopen64) - __wur; + __wur __nonnull ((3)); # else # define fopen fopen64 # define freopen freopen64 @@ -335,16 +335,16 @@ extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __THROW; If BUF is not NULL, use N bytes of it for buffering; else allocate an internal buffer N bytes long. */ extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, - int __modes, size_t __n) __THROW; + int __modes, size_t __n) __THROW __nonnull ((1)); #ifdef __USE_MISC /* If BUF is NULL, make STREAM unbuffered. Else make it use SIZE bytes of BUF for buffering. */ extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf, - size_t __size) __THROW; + size_t __size) __THROW __nonnull ((1)); /* Make STREAM line-buffered. */ -extern void setlinebuf (FILE *__stream) __THROW; +extern void setlinebuf (FILE *__stream) __THROW __nonnull ((1)); #endif @@ -418,7 +418,7 @@ extern int dprintf (int __fd, const char *__restrict __fmt, ...) This function is a possible cancellation point and therefore not marked with __THROW. */ extern int fscanf (FILE *__restrict __stream, - const char *__restrict __format, ...) __wur; + const char *__restrict __format, ...) __wur __nonnull ((1)); /* Read formatted input from stdin. This function is a possible cancellation point and therefore not @@ -439,7 +439,7 @@ extern int sscanf (const char *__restrict __s, # ifdef __REDIRECT extern int __REDIRECT (fscanf, (FILE *__restrict __stream, const char *__restrict __format, ...), - __isoc23_fscanf) __wur; + __isoc23_fscanf) __wur __nonnull ((1)); extern int __REDIRECT (scanf, (const char *__restrict __format, ...), __isoc23_scanf) __wur; extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, @@ -447,7 +447,7 @@ extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, __isoc23_sscanf); # else extern int __isoc23_fscanf (FILE *__restrict __stream, - const char *__restrict __format, ...) __wur; + const char *__restrict __format, ...) __wur __nonnull ((1)); extern int __isoc23_scanf (const char *__restrict __format, ...) __wur; extern int __isoc23_sscanf (const char *__restrict __s, const char *__restrict __format, ...) __THROW; @@ -459,7 +459,7 @@ extern int __isoc23_sscanf (const char *__restrict __s, # ifdef __REDIRECT extern int __REDIRECT (fscanf, (FILE *__restrict __stream, const char *__restrict __format, ...), - __isoc99_fscanf) __wur; + __isoc99_fscanf) __wur __nonnull ((1)); extern int __REDIRECT (scanf, (const char *__restrict __format, ...), __isoc99_scanf) __wur; extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, @@ -467,7 +467,7 @@ extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, __isoc99_sscanf); # else extern int __isoc99_fscanf (FILE *__restrict __stream, - const char *__restrict __format, ...) __wur; + const char *__restrict __format, ...) __wur __nonnull ((1)); extern int __isoc99_scanf (const char *__restrict __format, ...) __wur; extern int __isoc99_sscanf (const char *__restrict __s, const char *__restrict __format, ...) __THROW; @@ -485,7 +485,7 @@ extern int __isoc99_sscanf (const char *__restrict __s, marked with __THROW. */ extern int vfscanf (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); /* Read formatted input from stdin into argument list ARG. @@ -508,7 +508,7 @@ extern int __REDIRECT (vfscanf, (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg), __isoc23_vfscanf) - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); extern int __REDIRECT (vscanf, (const char *__restrict __format, __gnuc_va_list __arg), __isoc23_vscanf) __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; @@ -520,7 +520,7 @@ extern int __REDIRECT_NTH (vsscanf, # elif !defined __REDIRECT extern int __isoc23_vfscanf (FILE *__restrict __s, const char *__restrict __format, - __gnuc_va_list __arg) __wur; + __gnuc_va_list __arg) __wur __nonnull ((1)); extern int __isoc23_vscanf (const char *__restrict __format, __gnuc_va_list __arg) __wur; extern int __isoc23_vsscanf (const char *__restrict __s, @@ -537,7 +537,7 @@ extern int __REDIRECT (vfscanf, (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg), __isoc99_vfscanf) - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); extern int __REDIRECT (vscanf, (const char *__restrict __format, __gnuc_va_list __arg), __isoc99_vscanf) __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; @@ -549,7 +549,7 @@ extern int __REDIRECT_NTH (vsscanf, # elif !defined __REDIRECT extern int __isoc99_vfscanf (FILE *__restrict __s, const char *__restrict __format, - __gnuc_va_list __arg) __wur; + __gnuc_va_list __arg) __wur __nonnull ((1)); extern int __isoc99_vscanf (const char *__restrict __format, __gnuc_va_list __arg) __wur; extern int __isoc99_vsscanf (const char *__restrict __s, @@ -568,8 +568,8 @@ extern int __isoc99_vsscanf (const char *__restrict __s, These functions are possible cancellation points and therefore not marked with __THROW. */ -extern int fgetc (FILE *__stream); -extern int getc (FILE *__stream); +extern int fgetc (FILE *__stream) __nonnull ((1)); +extern int getc (FILE *__stream) __nonnull ((1)); /* Read a character from stdin. @@ -582,7 +582,7 @@ extern int getchar (void); These functions are possible cancellation points and therefore not marked with __THROW. */ -extern int getc_unlocked (FILE *__stream); +extern int getc_unlocked (FILE *__stream) __nonnull ((1)); extern int getchar_unlocked (void); #endif /* Use POSIX. */ @@ -593,7 +593,7 @@ extern int getchar_unlocked (void); cancellation point. But due to similarity with an POSIX interface or due to the implementation it is a cancellation point and therefore not marked with __THROW. */ -extern int fgetc_unlocked (FILE *__stream); +extern int fgetc_unlocked (FILE *__stream) __nonnull ((1)); #endif /* Use MISC. */ @@ -604,8 +604,8 @@ extern int fgetc_unlocked (FILE *__stream); These functions is a possible cancellation point and therefore not marked with __THROW. */ -extern int fputc (int __c, FILE *__stream); -extern int putc (int __c, FILE *__stream); +extern int fputc (int __c, FILE *__stream) __nonnull ((2)); +extern int putc (int __c, FILE *__stream) __nonnull ((2)); /* Write a character to stdout. @@ -620,7 +620,7 @@ extern int putchar (int __c); cancellation point. But due to similarity with an POSIX interface or due to the implementation it is a cancellation point and therefore not marked with __THROW. */ -extern int fputc_unlocked (int __c, FILE *__stream); +extern int fputc_unlocked (int __c, FILE *__stream) __nonnull ((2)); #endif /* Use MISC. */ #ifdef __USE_POSIX199506 @@ -628,7 +628,7 @@ extern int fputc_unlocked (int __c, FILE *__stream); These functions are possible cancellation points and therefore not marked with __THROW. */ -extern int putc_unlocked (int __c, FILE *__stream); +extern int putc_unlocked (int __c, FILE *__stream) __nonnull ((2)); extern int putchar_unlocked (int __c); #endif /* Use POSIX. */ @@ -636,10 +636,10 @@ extern int putchar_unlocked (int __c); #if defined __USE_MISC \ || (defined __USE_XOPEN && !defined __USE_XOPEN2K) /* Get a word (int) from STREAM. */ -extern int getw (FILE *__stream); +extern int getw (FILE *__stream) __nonnull ((1)); /* Write a word (int) to STREAM. */ -extern int putw (int __w, FILE *__stream); +extern int putw (int __w, FILE *__stream) __nonnull ((2)); #endif @@ -689,10 +689,10 @@ extern char *fgets_unlocked (char *__restrict __s, int __n, therefore not marked with __THROW. */ extern __ssize_t __getdelim (char **__restrict __lineptr, size_t *__restrict __n, int __delimiter, - FILE *__restrict __stream) __wur; + FILE *__restrict __stream) __wur __nonnull ((4)); extern __ssize_t getdelim (char **__restrict __lineptr, size_t *__restrict __n, int __delimiter, - FILE *__restrict __stream) __wur; + FILE *__restrict __stream) __wur __nonnull ((4)); /* Like `getdelim', but reads up to a newline. @@ -702,7 +702,7 @@ extern __ssize_t getdelim (char **__restrict __lineptr, therefore not marked with __THROW. */ extern __ssize_t getline (char **__restrict __lineptr, size_t *__restrict __n, - FILE *__restrict __stream) __wur; + FILE *__restrict __stream) __wur __nonnull ((3)); #endif @@ -723,7 +723,7 @@ extern int puts (const char *__s); This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int ungetc (int __c, FILE *__stream); +extern int ungetc (int __c, FILE *__stream) __nonnull ((2)); /* Read chunks of generic data from STREAM. @@ -768,17 +768,17 @@ extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size, This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int fseek (FILE *__stream, long int __off, int __whence); +extern int fseek (FILE *__stream, long int __off, int __whence) __nonnull ((1)); /* Return the current position of STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern long int ftell (FILE *__stream) __wur; +extern long int ftell (FILE *__stream) __wur __nonnull ((1)); /* Rewind to the beginning of STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern void rewind (FILE *__stream); +extern void rewind (FILE *__stream) __nonnull ((1)); /* The Single Unix Specification, Version 2, specifies an alternative, more adequate interface for the two functions above which deal with @@ -791,18 +791,19 @@ extern void rewind (FILE *__stream); This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int fseeko (FILE *__stream, __off_t __off, int __whence); +extern int fseeko (FILE *__stream, __off_t __off, int __whence) __nonnull ((1)); /* Return the current position of STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern __off_t ftello (FILE *__stream) __wur; +extern __off_t ftello (FILE *__stream) __wur __nonnull ((1)); # else # ifdef __REDIRECT extern int __REDIRECT (fseeko, (FILE *__stream, __off64_t __off, int __whence), - fseeko64); -extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); + fseeko64) __nonnull ((1)); +extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64) + __nonnull ((1)); # else # define fseeko fseeko64 # define ftello ftello64 @@ -815,18 +816,20 @@ extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos); +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos) + __nonnull ((1)); /* Set STREAM's position. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int fsetpos (FILE *__stream, const fpos_t *__pos); +extern int fsetpos (FILE *__stream, const fpos_t *__pos) __nonnull ((1)); #else # ifdef __REDIRECT extern int __REDIRECT (fgetpos, (FILE *__restrict __stream, - fpos_t *__restrict __pos), fgetpos64); + fpos_t *__restrict __pos), fgetpos64) __nonnull ((1)); extern int __REDIRECT (fsetpos, - (FILE *__stream, const fpos_t *__pos), fsetpos64); + (FILE *__stream, const fpos_t *__pos), fsetpos64) + __nonnull ((1)); # else # define fgetpos fgetpos64 # define fsetpos fsetpos64 @@ -834,24 +837,26 @@ extern int __REDIRECT (fsetpos, #endif #ifdef __USE_LARGEFILE64 -extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence); -extern __off64_t ftello64 (FILE *__stream) __wur; -extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict __pos); -extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos); +extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence) + __nonnull ((1)); +extern __off64_t ftello64 (FILE *__stream) __wur __nonnull ((1)); +extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict __pos) + __nonnull ((1)); +extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos) __nonnull ((1)); #endif /* Clear the error and EOF indicators for STREAM. */ -extern void clearerr (FILE *__stream) __THROW; +extern void clearerr (FILE *__stream) __THROW __nonnull ((1)); /* Return the EOF indicator for STREAM. */ -extern int feof (FILE *__stream) __THROW __wur; +extern int feof (FILE *__stream) __THROW __wur __nonnull ((1)); /* Return the error indicator for STREAM. */ -extern int ferror (FILE *__stream) __THROW __wur; +extern int ferror (FILE *__stream) __THROW __wur __nonnull ((1)); #ifdef __USE_MISC /* Faster versions when locking is not required. */ -extern void clearerr_unlocked (FILE *__stream) __THROW; -extern int feof_unlocked (FILE *__stream) __THROW __wur; -extern int ferror_unlocked (FILE *__stream) __THROW __wur; +extern void clearerr_unlocked (FILE *__stream) __THROW __nonnull ((1)); +extern int feof_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); +extern int ferror_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); #endif @@ -864,12 +869,12 @@ extern void perror (const char *__s) __COLD; #ifdef __USE_POSIX /* Return the system file descriptor for STREAM. */ -extern int fileno (FILE *__stream) __THROW __wur; +extern int fileno (FILE *__stream) __THROW __wur __nonnull ((1)); #endif /* Use POSIX. */ #ifdef __USE_MISC /* Faster version when locking is not required. */ -extern int fileno_unlocked (FILE *__stream) __THROW __wur; +extern int fileno_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); #endif @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) __THROW __wur; This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int pclose (FILE *__stream); +extern int pclose (FILE *__stream) __nonnull ((1)); /* Create a new stream connected to a pipe running the given command. @@ -922,14 +927,14 @@ extern int obstack_vprintf (struct obstack *__restrict __obstack, /* These are defined in POSIX.1:1996. */ /* Acquire ownership of STREAM. */ -extern void flockfile (FILE *__stream) __THROW; +extern void flockfile (FILE *__stream) __THROW __nonnull ((1)); /* Try to acquire ownership of STREAM but do not block if it is not possible. */ -extern int ftrylockfile (FILE *__stream) __THROW __wur; +extern int ftrylockfile (FILE *__stream) __THROW __wur __nonnull ((1)); /* Relinquish the ownership granted for STREAM. */ -extern void funlockfile (FILE *__stream) __THROW; +extern void funlockfile (FILE *__stream) __THROW __nonnull ((1)); #endif /* POSIX */ #if defined __USE_XOPEN && !defined __USE_XOPEN2K && !defined __USE_GNU -- 2.40.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-18 17:25 [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h Xi Ruoyao @ 2023-05-18 18:06 ` Alex Colomar 2023-05-18 18:29 ` Alex Colomar 2023-05-18 18:56 ` Alejandro Colomar 0 siblings, 2 replies; 9+ messages in thread From: Alex Colomar @ 2023-05-18 18:06 UTC (permalink / raw) To: Xi Ruoyao, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell [-- Attachment #1.1: Type: text/plain, Size: 19819 bytes --] Hi Xi! On 5/18/23 19:25, Xi Ruoyao via Libc-alpha wrote: > During the review of a GCC analyzer test case, we found most stdio > functions accepting a FILE * argument expect it to be nonnull and just > segfault when the argument is NULL. Add nonnull attribute for them. > > setbuf is well defined when __stream is NULL so it's not touched. > > For fputs, fgets, fread, fwrite, fprintf, vfprintf, and their unlocked > version, if __stream is empty but there is nothing to read or write, > they don't segfault and I'm not sure if the standard allows such a use > so I left them out. > --- > libio/stdio.h | 119 ++++++++++++++++++++++++++------------------------ > 1 file changed, 62 insertions(+), 57 deletions(-) > > diff --git a/libio/stdio.h b/libio/stdio.h > index 4cf9f1c012..ae3d7295d4 100644 > --- a/libio/stdio.h > +++ b/libio/stdio.h > @@ -232,7 +232,7 @@ extern char *tempnam (const char *__dir, const char *__pfx) > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int fflush (FILE *__stream); > +extern int fflush (FILE *__stream) __nonnull ((1)); flush(NULL) is well defined. It flushes all streams that can be flushed. This reminds me that I should document that in the SYNOPSIS section of the manual page; an oversight on my side. > > #ifdef __USE_MISC > /* Faster versions when locking is not required. > @@ -241,7 +241,7 @@ extern int fflush (FILE *__stream); > cancellation point. But due to similarity with an POSIX interface > or due to the implementation it is a cancellation point and > therefore not marked with __THROW. */ > -extern int fflush_unlocked (FILE *__stream); > +extern int fflush_unlocked (FILE *__stream) __nonnull ((1)); Without checking, I'll guess that fflush_unlocked(NULL) is also well defined. I didn't see any other similar cases, but I may have missed some; I didn't revise them all thoroughly; please check. > #endif > > #ifdef __USE_GNU > @@ -278,7 +278,7 @@ extern FILE *__REDIRECT (fopen, (const char *__restrict __filename, > extern FILE *__REDIRECT (freopen, (const char *__restrict __filename, > const char *__restrict __modes, > FILE *__restrict __stream), freopen64) > - __wur; > + __wur __nonnull ((3)); > # else > # define fopen fopen64 > # define freopen freopen64 > @@ -335,16 +335,16 @@ extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __THROW; > If BUF is not NULL, use N bytes of it for buffering; > else allocate an internal buffer N bytes long. */ > extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, > - int __modes, size_t __n) __THROW; > + int __modes, size_t __n) __THROW __nonnull ((1)); > > #ifdef __USE_MISC > /* If BUF is NULL, make STREAM unbuffered. > Else make it use SIZE bytes of BUF for buffering. */ > extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf, > - size_t __size) __THROW; > + size_t __size) __THROW __nonnull ((1)); > > /* Make STREAM line-buffered. */ > -extern void setlinebuf (FILE *__stream) __THROW; > +extern void setlinebuf (FILE *__stream) __THROW __nonnull ((1)); > #endif > > > @@ -418,7 +418,7 @@ extern int dprintf (int __fd, const char *__restrict __fmt, ...) > This function is a possible cancellation point and therefore not > marked with __THROW. */ > extern int fscanf (FILE *__restrict __stream, > - const char *__restrict __format, ...) __wur; > + const char *__restrict __format, ...) __wur __nonnull ((1)); > /* Read formatted input from stdin. > > This function is a possible cancellation point and therefore not > @@ -439,7 +439,7 @@ extern int sscanf (const char *__restrict __s, > # ifdef __REDIRECT > extern int __REDIRECT (fscanf, (FILE *__restrict __stream, > const char *__restrict __format, ...), > - __isoc23_fscanf) __wur; > + __isoc23_fscanf) __wur __nonnull ((1)); > extern int __REDIRECT (scanf, (const char *__restrict __format, ...), > __isoc23_scanf) __wur; > extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > @@ -447,7 +447,7 @@ extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > __isoc23_sscanf); > # else > extern int __isoc23_fscanf (FILE *__restrict __stream, > - const char *__restrict __format, ...) __wur; > + const char *__restrict __format, ...) __wur __nonnull ((1)); > extern int __isoc23_scanf (const char *__restrict __format, ...) __wur; > extern int __isoc23_sscanf (const char *__restrict __s, > const char *__restrict __format, ...) __THROW; > @@ -459,7 +459,7 @@ extern int __isoc23_sscanf (const char *__restrict __s, > # ifdef __REDIRECT > extern int __REDIRECT (fscanf, (FILE *__restrict __stream, > const char *__restrict __format, ...), > - __isoc99_fscanf) __wur; > + __isoc99_fscanf) __wur __nonnull ((1)); > extern int __REDIRECT (scanf, (const char *__restrict __format, ...), > __isoc99_scanf) __wur; > extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > @@ -467,7 +467,7 @@ extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > __isoc99_sscanf); > # else > extern int __isoc99_fscanf (FILE *__restrict __stream, > - const char *__restrict __format, ...) __wur; > + const char *__restrict __format, ...) __wur __nonnull ((1)); > extern int __isoc99_scanf (const char *__restrict __format, ...) __wur; > extern int __isoc99_sscanf (const char *__restrict __s, > const char *__restrict __format, ...) __THROW; > @@ -485,7 +485,7 @@ extern int __isoc99_sscanf (const char *__restrict __s, > marked with __THROW. */ > extern int vfscanf (FILE *__restrict __s, const char *__restrict __format, > __gnuc_va_list __arg) > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); > > /* Read formatted input from stdin into argument list ARG. > > @@ -508,7 +508,7 @@ extern int __REDIRECT (vfscanf, > (FILE *__restrict __s, > const char *__restrict __format, __gnuc_va_list __arg), > __isoc23_vfscanf) > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); > extern int __REDIRECT (vscanf, (const char *__restrict __format, > __gnuc_va_list __arg), __isoc23_vscanf) > __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; > @@ -520,7 +520,7 @@ extern int __REDIRECT_NTH (vsscanf, > # elif !defined __REDIRECT > extern int __isoc23_vfscanf (FILE *__restrict __s, > const char *__restrict __format, > - __gnuc_va_list __arg) __wur; > + __gnuc_va_list __arg) __wur __nonnull ((1)); > extern int __isoc23_vscanf (const char *__restrict __format, > __gnuc_va_list __arg) __wur; > extern int __isoc23_vsscanf (const char *__restrict __s, > @@ -537,7 +537,7 @@ extern int __REDIRECT (vfscanf, > (FILE *__restrict __s, > const char *__restrict __format, __gnuc_va_list __arg), > __isoc99_vfscanf) > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull ((1)); > extern int __REDIRECT (vscanf, (const char *__restrict __format, > __gnuc_va_list __arg), __isoc99_vscanf) > __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; > @@ -549,7 +549,7 @@ extern int __REDIRECT_NTH (vsscanf, > # elif !defined __REDIRECT > extern int __isoc99_vfscanf (FILE *__restrict __s, > const char *__restrict __format, > - __gnuc_va_list __arg) __wur; > + __gnuc_va_list __arg) __wur __nonnull ((1)); > extern int __isoc99_vscanf (const char *__restrict __format, > __gnuc_va_list __arg) __wur; > extern int __isoc99_vsscanf (const char *__restrict __s, > @@ -568,8 +568,8 @@ extern int __isoc99_vsscanf (const char *__restrict __s, > > These functions are possible cancellation points and therefore not > marked with __THROW. */ > -extern int fgetc (FILE *__stream); > -extern int getc (FILE *__stream); > +extern int fgetc (FILE *__stream) __nonnull ((1)); > +extern int getc (FILE *__stream) __nonnull ((1)); > > /* Read a character from stdin. > > @@ -582,7 +582,7 @@ extern int getchar (void); > > These functions are possible cancellation points and therefore not > marked with __THROW. */ > -extern int getc_unlocked (FILE *__stream); > +extern int getc_unlocked (FILE *__stream) __nonnull ((1)); > extern int getchar_unlocked (void); > #endif /* Use POSIX. */ > > @@ -593,7 +593,7 @@ extern int getchar_unlocked (void); > cancellation point. But due to similarity with an POSIX interface > or due to the implementation it is a cancellation point and > therefore not marked with __THROW. */ > -extern int fgetc_unlocked (FILE *__stream); > +extern int fgetc_unlocked (FILE *__stream) __nonnull ((1)); > #endif /* Use MISC. */ > > > @@ -604,8 +604,8 @@ extern int fgetc_unlocked (FILE *__stream); > > These functions is a possible cancellation point and therefore not Aside: here's a typo mixing plural and singular in the sentence (not part of your commit). I'll prepare a patch for it. > marked with __THROW. */ > -extern int fputc (int __c, FILE *__stream); > -extern int putc (int __c, FILE *__stream); > +extern int fputc (int __c, FILE *__stream) __nonnull ((2)); > +extern int putc (int __c, FILE *__stream) __nonnull ((2)); > > /* Write a character to stdout. > > @@ -620,7 +620,7 @@ extern int putchar (int __c); > cancellation point. But due to similarity with an POSIX interface > or due to the implementation it is a cancellation point and > therefore not marked with __THROW. */ > -extern int fputc_unlocked (int __c, FILE *__stream); > +extern int fputc_unlocked (int __c, FILE *__stream) __nonnull ((2)); > #endif /* Use MISC. */ > > #ifdef __USE_POSIX199506 > @@ -628,7 +628,7 @@ extern int fputc_unlocked (int __c, FILE *__stream); > > These functions are possible cancellation points and therefore not > marked with __THROW. */ > -extern int putc_unlocked (int __c, FILE *__stream); > +extern int putc_unlocked (int __c, FILE *__stream) __nonnull ((2)); > extern int putchar_unlocked (int __c); > #endif /* Use POSIX. */ > > @@ -636,10 +636,10 @@ extern int putchar_unlocked (int __c); > #if defined __USE_MISC \ > || (defined __USE_XOPEN && !defined __USE_XOPEN2K) > /* Get a word (int) from STREAM. */ > -extern int getw (FILE *__stream); > +extern int getw (FILE *__stream) __nonnull ((1)); > > /* Write a word (int) to STREAM. */ > -extern int putw (int __w, FILE *__stream); > +extern int putw (int __w, FILE *__stream) __nonnull ((2)); > #endif > > > @@ -689,10 +689,10 @@ extern char *fgets_unlocked (char *__restrict __s, int __n, > therefore not marked with __THROW. */ > extern __ssize_t __getdelim (char **__restrict __lineptr, > size_t *__restrict __n, int __delimiter, > - FILE *__restrict __stream) __wur; > + FILE *__restrict __stream) __wur __nonnull ((4)); > extern __ssize_t getdelim (char **__restrict __lineptr, > size_t *__restrict __n, int __delimiter, > - FILE *__restrict __stream) __wur; > + FILE *__restrict __stream) __wur __nonnull ((4)); > > /* Like `getdelim', but reads up to a newline. > > @@ -702,7 +702,7 @@ extern __ssize_t getdelim (char **__restrict __lineptr, > therefore not marked with __THROW. */ > extern __ssize_t getline (char **__restrict __lineptr, > size_t *__restrict __n, > - FILE *__restrict __stream) __wur; > + FILE *__restrict __stream) __wur __nonnull ((3)); > #endif > > > @@ -723,7 +723,7 @@ extern int puts (const char *__s); > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int ungetc (int __c, FILE *__stream); > +extern int ungetc (int __c, FILE *__stream) __nonnull ((2)); > > > /* Read chunks of generic data from STREAM. > @@ -768,17 +768,17 @@ extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size, > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int fseek (FILE *__stream, long int __off, int __whence); > +extern int fseek (FILE *__stream, long int __off, int __whence) __nonnull ((1)); > /* Return the current position of STREAM. > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern long int ftell (FILE *__stream) __wur; > +extern long int ftell (FILE *__stream) __wur __nonnull ((1)); > /* Rewind to the beginning of STREAM. > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern void rewind (FILE *__stream); > +extern void rewind (FILE *__stream) __nonnull ((1)); > > /* The Single Unix Specification, Version 2, specifies an alternative, > more adequate interface for the two functions above which deal with > @@ -791,18 +791,19 @@ extern void rewind (FILE *__stream); > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int fseeko (FILE *__stream, __off_t __off, int __whence); > +extern int fseeko (FILE *__stream, __off_t __off, int __whence) __nonnull ((1)); > /* Return the current position of STREAM. > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern __off_t ftello (FILE *__stream) __wur; > +extern __off_t ftello (FILE *__stream) __wur __nonnull ((1)); > # else > # ifdef __REDIRECT > extern int __REDIRECT (fseeko, > (FILE *__stream, __off64_t __off, int __whence), > - fseeko64); > -extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); > + fseeko64) __nonnull ((1)); > +extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64) > + __nonnull ((1)); > # else > # define fseeko fseeko64 > # define ftello ftello64 > @@ -815,18 +816,20 @@ extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos); > +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos) > + __nonnull ((1)); > /* Set STREAM's position. > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int fsetpos (FILE *__stream, const fpos_t *__pos); > +extern int fsetpos (FILE *__stream, const fpos_t *__pos) __nonnull ((1)); > #else > # ifdef __REDIRECT > extern int __REDIRECT (fgetpos, (FILE *__restrict __stream, > - fpos_t *__restrict __pos), fgetpos64); > + fpos_t *__restrict __pos), fgetpos64) __nonnull ((1)); > extern int __REDIRECT (fsetpos, > - (FILE *__stream, const fpos_t *__pos), fsetpos64); > + (FILE *__stream, const fpos_t *__pos), fsetpos64) > + __nonnull ((1)); > # else > # define fgetpos fgetpos64 > # define fsetpos fsetpos64 > @@ -834,24 +837,26 @@ extern int __REDIRECT (fsetpos, > #endif > > #ifdef __USE_LARGEFILE64 > -extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence); > -extern __off64_t ftello64 (FILE *__stream) __wur; > -extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict __pos); > -extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos); > +extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence) > + __nonnull ((1)); > +extern __off64_t ftello64 (FILE *__stream) __wur __nonnull ((1)); > +extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict __pos) > + __nonnull ((1)); > +extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos) __nonnull ((1)); > #endif > > /* Clear the error and EOF indicators for STREAM. */ > -extern void clearerr (FILE *__stream) __THROW; > +extern void clearerr (FILE *__stream) __THROW __nonnull ((1)); > /* Return the EOF indicator for STREAM. */ > -extern int feof (FILE *__stream) __THROW __wur; > +extern int feof (FILE *__stream) __THROW __wur __nonnull ((1)); > /* Return the error indicator for STREAM. */ > -extern int ferror (FILE *__stream) __THROW __wur; > +extern int ferror (FILE *__stream) __THROW __wur __nonnull ((1)); > > #ifdef __USE_MISC > /* Faster versions when locking is not required. */ > -extern void clearerr_unlocked (FILE *__stream) __THROW; > -extern int feof_unlocked (FILE *__stream) __THROW __wur; > -extern int ferror_unlocked (FILE *__stream) __THROW __wur; > +extern void clearerr_unlocked (FILE *__stream) __THROW __nonnull ((1)); > +extern int feof_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); > +extern int ferror_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); > #endif > > > @@ -864,12 +869,12 @@ extern void perror (const char *__s) __COLD; > > #ifdef __USE_POSIX > /* Return the system file descriptor for STREAM. */ > -extern int fileno (FILE *__stream) __THROW __wur; > +extern int fileno (FILE *__stream) __THROW __wur __nonnull ((1)); > #endif /* Use POSIX. */ > > #ifdef __USE_MISC > /* Faster version when locking is not required. */ > -extern int fileno_unlocked (FILE *__stream) __THROW __wur; > +extern int fileno_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); > #endif > > > @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) __THROW __wur; > > This function is a possible cancellation point and therefore not > marked with __THROW. */ > -extern int pclose (FILE *__stream); > +extern int pclose (FILE *__stream) __nonnull ((1)); You didn't patch fclose(3). Any reason? I guess it's similarly UB to call fclose(NULL). Cheers, Alex > > /* Create a new stream connected to a pipe running the given command. > > @@ -922,14 +927,14 @@ extern int obstack_vprintf (struct obstack *__restrict __obstack, > /* These are defined in POSIX.1:1996. */ > > /* Acquire ownership of STREAM. */ > -extern void flockfile (FILE *__stream) __THROW; > +extern void flockfile (FILE *__stream) __THROW __nonnull ((1)); > > /* Try to acquire ownership of STREAM but do not block if it is not > possible. */ > -extern int ftrylockfile (FILE *__stream) __THROW __wur; > +extern int ftrylockfile (FILE *__stream) __THROW __wur __nonnull ((1)); > > /* Relinquish the ownership granted for STREAM. */ > -extern void funlockfile (FILE *__stream) __THROW; > +extern void funlockfile (FILE *__stream) __THROW __nonnull ((1)); > #endif /* POSIX */ > > #if defined __USE_XOPEN && !defined __USE_XOPEN2K && !defined __USE_GNU -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-18 18:06 ` Alex Colomar @ 2023-05-18 18:29 ` Alex Colomar 2023-05-19 4:13 ` Xi Ruoyao 2023-05-18 18:56 ` Alejandro Colomar 1 sibling, 1 reply; 9+ messages in thread From: Alex Colomar @ 2023-05-18 18:29 UTC (permalink / raw) To: Xi Ruoyao, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell [-- Attachment #1.1: Type: text/plain, Size: 22028 bytes --] On 5/18/23 20:06, Alex Colomar wrote: > Hi Xi! > > On 5/18/23 19:25, Xi Ruoyao via Libc-alpha wrote: >> During the review of a GCC analyzer test case, we found most stdio >> functions accepting a FILE * argument expect it to be nonnull and just >> segfault when the argument is NULL. Add nonnull attribute for them. >> >> setbuf is well defined when __stream is NULL so it's not touched. Is this true? I couldn't find anything about it in either setbuf(3), setbuf(3POSIX), or info libc. The buffer can be NULL, but the stream? >> >> For fputs, fgets, fread, fwrite, fprintf, vfprintf, and their unlocked >> version, if __stream is empty but there is nothing to read or write, >> they don't segfault and I'm not sure if the standard allows such a use >> so I left them out. >> --- >> libio/stdio.h | 119 ++++++++++++++++++++++++++------------------------ >> 1 file changed, 62 insertions(+), 57 deletions(-) >> >> diff --git a/libio/stdio.h b/libio/stdio.h >> index 4cf9f1c012..ae3d7295d4 100644 >> --- a/libio/stdio.h >> +++ b/libio/stdio.h >> @@ -232,7 +232,7 @@ extern char *tempnam (const char *__dir, const >> char *__pfx) >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fflush (FILE *__stream); >> +extern int fflush (FILE *__stream) __nonnull ((1)); > > flush(NULL) is well defined. It flushes all streams that can be > flushed. This reminds me that I should document that in the SYNOPSIS > section of the manual page; an oversight on my side. > >> #ifdef __USE_MISC >> /* Faster versions when locking is not required. >> @@ -241,7 +241,7 @@ extern int fflush (FILE *__stream); >> cancellation point. But due to similarity with an POSIX interface >> or due to the implementation it is a cancellation point and >> therefore not marked with __THROW. */ >> -extern int fflush_unlocked (FILE *__stream); >> +extern int fflush_unlocked (FILE *__stream) __nonnull ((1)); > > Without checking, I'll guess that fflush_unlocked(NULL) is also well > defined. > > I didn't see any other similar cases, but I may have missed some; I > didn't revise them all thoroughly; please check. > >> #endif >> #ifdef __USE_GNU >> @@ -278,7 +278,7 @@ extern FILE *__REDIRECT (fopen, (const char >> *__restrict __filename, >> extern FILE *__REDIRECT (freopen, (const char *__restrict __filename, >> const char *__restrict __modes, >> FILE *__restrict __stream), freopen64) >> - __wur; >> + __wur __nonnull ((3)); >> # else >> # define fopen fopen64 >> # define freopen freopen64 >> @@ -335,16 +335,16 @@ extern void setbuf (FILE *__restrict __stream, >> char *__restrict __buf) __THROW; >> If BUF is not NULL, use N bytes of it for buffering; >> else allocate an internal buffer N bytes long. */ >> extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf, >> - int __modes, size_t __n) __THROW; >> + int __modes, size_t __n) __THROW __nonnull ((1)); >> #ifdef __USE_MISC >> /* If BUF is NULL, make STREAM unbuffered. >> Else make it use SIZE bytes of BUF for buffering. */ >> extern void setbuffer (FILE *__restrict __stream, char *__restrict >> __buf, >> - size_t __size) __THROW; >> + size_t __size) __THROW __nonnull ((1)); >> /* Make STREAM line-buffered. */ >> -extern void setlinebuf (FILE *__stream) __THROW; >> +extern void setlinebuf (FILE *__stream) __THROW __nonnull ((1)); >> #endif >> @@ -418,7 +418,7 @@ extern int dprintf (int __fd, const char >> *__restrict __fmt, ...) >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> extern int fscanf (FILE *__restrict __stream, >> - const char *__restrict __format, ...) __wur; >> + const char *__restrict __format, ...) __wur __nonnull ((1)); >> /* Read formatted input from stdin. >> This function is a possible cancellation point and therefore not >> @@ -439,7 +439,7 @@ extern int sscanf (const char *__restrict __s, >> # ifdef __REDIRECT >> extern int __REDIRECT (fscanf, (FILE *__restrict __stream, >> const char *__restrict __format, ...), >> - __isoc23_fscanf) __wur; >> + __isoc23_fscanf) __wur __nonnull ((1)); >> extern int __REDIRECT (scanf, (const char *__restrict __format, ...), >> __isoc23_scanf) __wur; >> extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, >> @@ -447,7 +447,7 @@ extern int __REDIRECT_NTH (sscanf, (const char >> *__restrict __s, >> __isoc23_sscanf); >> # else >> extern int __isoc23_fscanf (FILE *__restrict __stream, >> - const char *__restrict __format, ...) __wur; >> + const char *__restrict __format, ...) __wur __nonnull >> ((1)); >> extern int __isoc23_scanf (const char *__restrict __format, ...) __wur; >> extern int __isoc23_sscanf (const char *__restrict __s, >> const char *__restrict __format, ...) __THROW; >> @@ -459,7 +459,7 @@ extern int __isoc23_sscanf (const char *__restrict >> __s, >> # ifdef __REDIRECT >> extern int __REDIRECT (fscanf, (FILE *__restrict __stream, >> const char *__restrict __format, ...), >> - __isoc99_fscanf) __wur; >> + __isoc99_fscanf) __wur __nonnull ((1)); >> extern int __REDIRECT (scanf, (const char *__restrict __format, ...), >> __isoc99_scanf) __wur; >> extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, >> @@ -467,7 +467,7 @@ extern int __REDIRECT_NTH (sscanf, (const char >> *__restrict __s, >> __isoc99_sscanf); >> # else >> extern int __isoc99_fscanf (FILE *__restrict __stream, >> - const char *__restrict __format, ...) __wur; >> + const char *__restrict __format, ...) __wur __nonnull >> ((1)); >> extern int __isoc99_scanf (const char *__restrict __format, ...) __wur; >> extern int __isoc99_sscanf (const char *__restrict __s, >> const char *__restrict __format, ...) __THROW; >> @@ -485,7 +485,7 @@ extern int __isoc99_sscanf (const char *__restrict >> __s, >> marked with __THROW. */ >> extern int vfscanf (FILE *__restrict __s, const char *__restrict >> __format, >> __gnuc_va_list __arg) >> - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; >> + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull >> ((1)); >> /* Read formatted input from stdin into argument list ARG. >> @@ -508,7 +508,7 @@ extern int __REDIRECT (vfscanf, >> (FILE *__restrict __s, >> const char *__restrict __format, __gnuc_va_list __arg), >> __isoc23_vfscanf) >> - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; >> + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull >> ((1)); >> extern int __REDIRECT (vscanf, (const char *__restrict __format, >> __gnuc_va_list __arg), __isoc23_vscanf) >> __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; >> @@ -520,7 +520,7 @@ extern int __REDIRECT_NTH (vsscanf, >> # elif !defined __REDIRECT >> extern int __isoc23_vfscanf (FILE *__restrict __s, >> const char *__restrict __format, >> - __gnuc_va_list __arg) __wur; >> + __gnuc_va_list __arg) __wur __nonnull ((1)); >> extern int __isoc23_vscanf (const char *__restrict __format, >> __gnuc_va_list __arg) __wur; >> extern int __isoc23_vsscanf (const char *__restrict __s, >> @@ -537,7 +537,7 @@ extern int __REDIRECT (vfscanf, >> (FILE *__restrict __s, >> const char *__restrict __format, __gnuc_va_list __arg), >> __isoc99_vfscanf) >> - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; >> + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur __nonnull >> ((1)); >> extern int __REDIRECT (vscanf, (const char *__restrict __format, >> __gnuc_va_list __arg), __isoc99_vscanf) >> __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; >> @@ -549,7 +549,7 @@ extern int __REDIRECT_NTH (vsscanf, >> # elif !defined __REDIRECT >> extern int __isoc99_vfscanf (FILE *__restrict __s, >> const char *__restrict __format, >> - __gnuc_va_list __arg) __wur; >> + __gnuc_va_list __arg) __wur __nonnull ((1)); >> extern int __isoc99_vscanf (const char *__restrict __format, >> __gnuc_va_list __arg) __wur; >> extern int __isoc99_vsscanf (const char *__restrict __s, >> @@ -568,8 +568,8 @@ extern int __isoc99_vsscanf (const char >> *__restrict __s, >> These functions are possible cancellation points and therefore not >> marked with __THROW. */ >> -extern int fgetc (FILE *__stream); >> -extern int getc (FILE *__stream); >> +extern int fgetc (FILE *__stream) __nonnull ((1)); >> +extern int getc (FILE *__stream) __nonnull ((1)); >> /* Read a character from stdin. >> @@ -582,7 +582,7 @@ extern int getchar (void); >> These functions are possible cancellation points and therefore not >> marked with __THROW. */ >> -extern int getc_unlocked (FILE *__stream); >> +extern int getc_unlocked (FILE *__stream) __nonnull ((1)); >> extern int getchar_unlocked (void); >> #endif /* Use POSIX. */ >> @@ -593,7 +593,7 @@ extern int getchar_unlocked (void); >> cancellation point. But due to similarity with an POSIX interface >> or due to the implementation it is a cancellation point and >> therefore not marked with __THROW. */ >> -extern int fgetc_unlocked (FILE *__stream); >> +extern int fgetc_unlocked (FILE *__stream) __nonnull ((1)); >> #endif /* Use MISC. */ >> @@ -604,8 +604,8 @@ extern int fgetc_unlocked (FILE *__stream); >> These functions is a possible cancellation point and therefore not > > Aside: here's a typo mixing plural and singular in the sentence (not > part of your commit). I'll prepare a patch for it. > >> marked with __THROW. */ >> -extern int fputc (int __c, FILE *__stream); >> -extern int putc (int __c, FILE *__stream); >> +extern int fputc (int __c, FILE *__stream) __nonnull ((2)); >> +extern int putc (int __c, FILE *__stream) __nonnull ((2)); >> /* Write a character to stdout. >> @@ -620,7 +620,7 @@ extern int putchar (int __c); >> cancellation point. But due to similarity with an POSIX interface >> or due to the implementation it is a cancellation point and >> therefore not marked with __THROW. */ >> -extern int fputc_unlocked (int __c, FILE *__stream); >> +extern int fputc_unlocked (int __c, FILE *__stream) __nonnull ((2)); >> #endif /* Use MISC. */ >> #ifdef __USE_POSIX199506 >> @@ -628,7 +628,7 @@ extern int fputc_unlocked (int __c, FILE *__stream); >> These functions are possible cancellation points and therefore not >> marked with __THROW. */ >> -extern int putc_unlocked (int __c, FILE *__stream); >> +extern int putc_unlocked (int __c, FILE *__stream) __nonnull ((2)); >> extern int putchar_unlocked (int __c); >> #endif /* Use POSIX. */ >> @@ -636,10 +636,10 @@ extern int putchar_unlocked (int __c); >> #if defined __USE_MISC \ >> || (defined __USE_XOPEN && !defined __USE_XOPEN2K) >> /* Get a word (int) from STREAM. */ >> -extern int getw (FILE *__stream); >> +extern int getw (FILE *__stream) __nonnull ((1)); >> /* Write a word (int) to STREAM. */ >> -extern int putw (int __w, FILE *__stream); >> +extern int putw (int __w, FILE *__stream) __nonnull ((2)); >> #endif >> @@ -689,10 +689,10 @@ extern char *fgets_unlocked (char *__restrict >> __s, int __n, >> therefore not marked with __THROW. */ >> extern __ssize_t __getdelim (char **__restrict __lineptr, >> size_t *__restrict __n, int __delimiter, >> - FILE *__restrict __stream) __wur; >> + FILE *__restrict __stream) __wur >> __nonnull ((4)); >> extern __ssize_t getdelim (char **__restrict __lineptr, >> size_t *__restrict __n, int __delimiter, >> - FILE *__restrict __stream) __wur; >> + FILE *__restrict __stream) __wur __nonnull >> ((4)); >> /* Like `getdelim', but reads up to a newline. >> @@ -702,7 +702,7 @@ extern __ssize_t getdelim (char **__restrict >> __lineptr, >> therefore not marked with __THROW. */ >> extern __ssize_t getline (char **__restrict __lineptr, >> size_t *__restrict __n, >> - FILE *__restrict __stream) __wur; >> + FILE *__restrict __stream) __wur __nonnull >> ((3)); >> #endif >> @@ -723,7 +723,7 @@ extern int puts (const char *__s); >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int ungetc (int __c, FILE *__stream); >> +extern int ungetc (int __c, FILE *__stream) __nonnull ((2)); >> /* Read chunks of generic data from STREAM. >> @@ -768,17 +768,17 @@ extern size_t fwrite_unlocked (const void >> *__restrict __ptr, size_t __size, >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fseek (FILE *__stream, long int __off, int __whence); >> +extern int fseek (FILE *__stream, long int __off, int __whence) >> __nonnull ((1)); >> /* Return the current position of STREAM. >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern long int ftell (FILE *__stream) __wur; >> +extern long int ftell (FILE *__stream) __wur __nonnull ((1)); >> /* Rewind to the beginning of STREAM. >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern void rewind (FILE *__stream); >> +extern void rewind (FILE *__stream) __nonnull ((1)); >> /* The Single Unix Specification, Version 2, specifies an alternative, >> more adequate interface for the two functions above which deal with >> @@ -791,18 +791,19 @@ extern void rewind (FILE *__stream); >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fseeko (FILE *__stream, __off_t __off, int __whence); >> +extern int fseeko (FILE *__stream, __off_t __off, int __whence) >> __nonnull ((1)); >> /* Return the current position of STREAM. >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern __off_t ftello (FILE *__stream) __wur; >> +extern __off_t ftello (FILE *__stream) __wur __nonnull ((1)); >> # else >> # ifdef __REDIRECT >> extern int __REDIRECT (fseeko, >> (FILE *__stream, __off64_t __off, int __whence), >> - fseeko64); >> -extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); >> + fseeko64) __nonnull ((1)); >> +extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64) >> + __nonnull ((1)); >> # else >> # define fseeko fseeko64 >> # define ftello ftello64 >> @@ -815,18 +816,20 @@ extern __off64_t __REDIRECT (ftello, (FILE >> *__stream), ftello64); >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict >> __pos); >> +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos) >> + __nonnull ((1)); >> /* Set STREAM's position. >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fsetpos (FILE *__stream, const fpos_t *__pos); >> +extern int fsetpos (FILE *__stream, const fpos_t *__pos) __nonnull >> ((1)); >> #else >> # ifdef __REDIRECT >> extern int __REDIRECT (fgetpos, (FILE *__restrict __stream, >> - fpos_t *__restrict __pos), fgetpos64); >> + fpos_t *__restrict __pos), fgetpos64) __nonnull ((1)); >> extern int __REDIRECT (fsetpos, >> - (FILE *__stream, const fpos_t *__pos), fsetpos64); >> + (FILE *__stream, const fpos_t *__pos), fsetpos64) >> + __nonnull ((1)); >> # else >> # define fgetpos fgetpos64 >> # define fsetpos fsetpos64 >> @@ -834,24 +837,26 @@ extern int __REDIRECT (fsetpos, >> #endif >> #ifdef __USE_LARGEFILE64 >> -extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence); >> -extern __off64_t ftello64 (FILE *__stream) __wur; >> -extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict >> __pos); >> -extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos); >> +extern int fseeko64 (FILE *__stream, __off64_t __off, int __whence) >> + __nonnull ((1)); >> +extern __off64_t ftello64 (FILE *__stream) __wur __nonnull ((1)); >> +extern int fgetpos64 (FILE *__restrict __stream, fpos64_t *__restrict >> __pos) >> + __nonnull ((1)); >> +extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos) >> __nonnull ((1)); >> #endif >> /* Clear the error and EOF indicators for STREAM. */ >> -extern void clearerr (FILE *__stream) __THROW; >> +extern void clearerr (FILE *__stream) __THROW __nonnull ((1)); >> /* Return the EOF indicator for STREAM. */ >> -extern int feof (FILE *__stream) __THROW __wur; >> +extern int feof (FILE *__stream) __THROW __wur __nonnull ((1)); >> /* Return the error indicator for STREAM. */ >> -extern int ferror (FILE *__stream) __THROW __wur; >> +extern int ferror (FILE *__stream) __THROW __wur __nonnull ((1)); >> #ifdef __USE_MISC >> /* Faster versions when locking is not required. */ >> -extern void clearerr_unlocked (FILE *__stream) __THROW; >> -extern int feof_unlocked (FILE *__stream) __THROW __wur; >> -extern int ferror_unlocked (FILE *__stream) __THROW __wur; >> +extern void clearerr_unlocked (FILE *__stream) __THROW __nonnull ((1)); >> +extern int feof_unlocked (FILE *__stream) __THROW __wur __nonnull ((1)); >> +extern int ferror_unlocked (FILE *__stream) __THROW __wur __nonnull >> ((1)); >> #endif >> @@ -864,12 +869,12 @@ extern void perror (const char *__s) __COLD; >> #ifdef __USE_POSIX >> /* Return the system file descriptor for STREAM. */ >> -extern int fileno (FILE *__stream) __THROW __wur; >> +extern int fileno (FILE *__stream) __THROW __wur __nonnull ((1)); >> #endif /* Use POSIX. */ >> #ifdef __USE_MISC >> /* Faster version when locking is not required. */ >> -extern int fileno_unlocked (FILE *__stream) __THROW __wur; >> +extern int fileno_unlocked (FILE *__stream) __THROW __wur __nonnull >> ((1)); >> #endif >> @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) >> __THROW __wur; >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int pclose (FILE *__stream); >> +extern int pclose (FILE *__stream) __nonnull ((1)); > > You didn't patch fclose(3). Any reason? I guess it's similarly UB to > call fclose(NULL). > > Cheers, > Alex > >> /* Create a new stream connected to a pipe running the given command. >> @@ -922,14 +927,14 @@ extern int obstack_vprintf (struct obstack >> *__restrict __obstack, >> /* These are defined in POSIX.1:1996. */ >> /* Acquire ownership of STREAM. */ >> -extern void flockfile (FILE *__stream) __THROW; >> +extern void flockfile (FILE *__stream) __THROW __nonnull ((1)); >> /* Try to acquire ownership of STREAM but do not block if it is not >> possible. */ >> -extern int ftrylockfile (FILE *__stream) __THROW __wur; >> +extern int ftrylockfile (FILE *__stream) __THROW __wur __nonnull ((1)); >> /* Relinquish the ownership granted for STREAM. */ >> -extern void funlockfile (FILE *__stream) __THROW; >> +extern void funlockfile (FILE *__stream) __THROW __nonnull ((1)); >> #endif /* POSIX */ >> #if defined __USE_XOPEN && !defined __USE_XOPEN2K && !defined __USE_GNU > -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-18 18:29 ` Alex Colomar @ 2023-05-19 4:13 ` Xi Ruoyao 2023-05-19 5:21 ` Xi Ruoyao 0 siblings, 1 reply; 9+ messages in thread From: Xi Ruoyao @ 2023-05-19 4:13 UTC (permalink / raw) To: Alex Colomar, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell On Thu, 2023-05-18 at 20:29 +0200, Alex Colomar wrote: > On 5/18/23 20:06, Alex Colomar wrote: > > Hi Xi! > > > > On 5/18/23 19:25, Xi Ruoyao via Libc-alpha wrote: > > > During the review of a GCC analyzer test case, we found most stdio > > > functions accepting a FILE * argument expect it to be nonnull and > > > just > > > segfault when the argument is NULL. Add nonnull attribute for > > > them. > > > > > > setbuf is well defined when __stream is NULL so it's not touched. > > Is this true? I couldn't find anything about it in either setbuf(3), > setbuf(3POSIX), or info libc. > > The buffer can be NULL, but the stream? I guess when I took the note on the paper I misspelled "fflush" as "setbuf" for some reason (maybe lack of coffee :( ). I'll retest all the changes in one hour or two hours. > > > > > > > For fputs, fgets, fread, fwrite, fprintf, vfprintf, and their > > > unlocked > > > version, if __stream is empty but there is nothing to read or > > > write, > > > they don't segfault and I'm not sure if the standard allows such a > > > use > > > so I left them out. > > > --- > > > libio/stdio.h | 119 ++++++++++++++++++++++++++------------------ > > > ------ > > > 1 file changed, 62 insertions(+), 57 deletions(-) > > > > > > diff --git a/libio/stdio.h b/libio/stdio.h > > > index 4cf9f1c012..ae3d7295d4 100644 > > > --- a/libio/stdio.h > > > +++ b/libio/stdio.h > > > @@ -232,7 +232,7 @@ extern char *tempnam (const char *__dir, const > > > char *__pfx) > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int fflush (FILE *__stream); > > > +extern int fflush (FILE *__stream) __nonnull ((1)); > > > > flush(NULL) is well defined. It flushes all streams that can be > > flushed. This reminds me that I should document that in the > > SYNOPSIS > > section of the manual page; an oversight on my side. > > > > > #ifdef __USE_MISC > > > /* Faster versions when locking is not required. > > > @@ -241,7 +241,7 @@ extern int fflush (FILE *__stream); > > > cancellation point. But due to similarity with an POSIX > > > interface > > > or due to the implementation it is a cancellation point and > > > therefore not marked with __THROW. */ > > > -extern int fflush_unlocked (FILE *__stream); > > > +extern int fflush_unlocked (FILE *__stream) __nonnull ((1)); > > > > Without checking, I'll guess that fflush_unlocked(NULL) is also well > > defined. > > > > I didn't see any other similar cases, but I may have missed some; I > > didn't revise them all thoroughly; please check. > > > > > #endif > > > #ifdef __USE_GNU > > > @@ -278,7 +278,7 @@ extern FILE *__REDIRECT (fopen, (const char > > > *__restrict __filename, > > > extern FILE *__REDIRECT (freopen, (const char *__restrict > > > __filename, > > > const char *__restrict __modes, > > > FILE *__restrict __stream), freopen64) > > > - __wur; > > > + __wur __nonnull ((3)); > > > # else > > > # define fopen fopen64 > > > # define freopen freopen64 > > > @@ -335,16 +335,16 @@ extern void setbuf (FILE *__restrict > > > __stream, > > > char *__restrict __buf) __THROW; > > > If BUF is not NULL, use N bytes of it for buffering; > > > else allocate an internal buffer N bytes long. */ > > > extern int setvbuf (FILE *__restrict __stream, char *__restrict > > > __buf, > > > - int __modes, size_t __n) __THROW; > > > + int __modes, size_t __n) __THROW __nonnull ((1)); > > > #ifdef __USE_MISC > > > /* If BUF is NULL, make STREAM unbuffered. > > > Else make it use SIZE bytes of BUF for buffering. */ > > > extern void setbuffer (FILE *__restrict __stream, char > > > *__restrict > > > __buf, > > > - size_t __size) __THROW; > > > + size_t __size) __THROW __nonnull ((1)); > > > /* Make STREAM line-buffered. */ > > > -extern void setlinebuf (FILE *__stream) __THROW; > > > +extern void setlinebuf (FILE *__stream) __THROW __nonnull ((1)); > > > #endif > > > @@ -418,7 +418,7 @@ extern int dprintf (int __fd, const char > > > *__restrict __fmt, ...) > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > extern int fscanf (FILE *__restrict __stream, > > > - const char *__restrict __format, ...) __wur; > > > + const char *__restrict __format, ...) __wur __nonnull > > > ((1)); > > > /* Read formatted input from stdin. > > > This function is a possible cancellation point and therefore > > > not > > > @@ -439,7 +439,7 @@ extern int sscanf (const char *__restrict __s, > > > # ifdef __REDIRECT > > > extern int __REDIRECT (fscanf, (FILE *__restrict __stream, > > > const char *__restrict __format, ...), > > > - __isoc23_fscanf) __wur; > > > + __isoc23_fscanf) __wur __nonnull ((1)); > > > extern int __REDIRECT (scanf, (const char *__restrict __format, > > > ...), > > > __isoc23_scanf) __wur; > > > extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > > > @@ -447,7 +447,7 @@ extern int __REDIRECT_NTH (sscanf, (const char > > > *__restrict __s, > > > __isoc23_sscanf); > > > # else > > > extern int __isoc23_fscanf (FILE *__restrict __stream, > > > - const char *__restrict __format, ...) __wur; > > > + const char *__restrict __format, ...) __wur > > > __nonnull > > > ((1)); > > > extern int __isoc23_scanf (const char *__restrict __format, ...) > > > __wur; > > > extern int __isoc23_sscanf (const char *__restrict __s, > > > const char *__restrict __format, ...) __THROW; > > > @@ -459,7 +459,7 @@ extern int __isoc23_sscanf (const char > > > *__restrict > > > __s, > > > # ifdef __REDIRECT > > > extern int __REDIRECT (fscanf, (FILE *__restrict __stream, > > > const char *__restrict __format, ...), > > > - __isoc99_fscanf) __wur; > > > + __isoc99_fscanf) __wur __nonnull ((1)); > > > extern int __REDIRECT (scanf, (const char *__restrict __format, > > > ...), > > > __isoc99_scanf) __wur; > > > extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s, > > > @@ -467,7 +467,7 @@ extern int __REDIRECT_NTH (sscanf, (const char > > > *__restrict __s, > > > __isoc99_sscanf); > > > # else > > > extern int __isoc99_fscanf (FILE *__restrict __stream, > > > - const char *__restrict __format, ...) __wur; > > > + const char *__restrict __format, ...) __wur > > > __nonnull > > > ((1)); > > > extern int __isoc99_scanf (const char *__restrict __format, ...) > > > __wur; > > > extern int __isoc99_sscanf (const char *__restrict __s, > > > const char *__restrict __format, ...) __THROW; > > > @@ -485,7 +485,7 @@ extern int __isoc99_sscanf (const char > > > *__restrict > > > __s, > > > marked with __THROW. */ > > > extern int vfscanf (FILE *__restrict __s, const char *__restrict > > > __format, > > > __gnuc_va_list __arg) > > > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > > > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur > > > __nonnull > > > ((1)); > > > /* Read formatted input from stdin into argument list ARG. > > > @@ -508,7 +508,7 @@ extern int __REDIRECT (vfscanf, > > > (FILE *__restrict __s, > > > const char *__restrict __format, __gnuc_va_list > > > __arg), > > > __isoc23_vfscanf) > > > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > > > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur > > > __nonnull > > > ((1)); > > > extern int __REDIRECT (vscanf, (const char *__restrict __format, > > > __gnuc_va_list __arg), __isoc23_vscanf) > > > __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; > > > @@ -520,7 +520,7 @@ extern int __REDIRECT_NTH (vsscanf, > > > # elif !defined __REDIRECT > > > extern int __isoc23_vfscanf (FILE *__restrict __s, > > > const char *__restrict __format, > > > - __gnuc_va_list __arg) __wur; > > > + __gnuc_va_list __arg) __wur __nonnull ((1)); > > > extern int __isoc23_vscanf (const char *__restrict __format, > > > __gnuc_va_list __arg) __wur; > > > extern int __isoc23_vsscanf (const char *__restrict __s, > > > @@ -537,7 +537,7 @@ extern int __REDIRECT (vfscanf, > > > (FILE *__restrict __s, > > > const char *__restrict __format, __gnuc_va_list > > > __arg), > > > __isoc99_vfscanf) > > > - __attribute__ ((__format__ (__scanf__, 2, 0))) __wur; > > > + __attribute__ ((__format__ (__scanf__, 2, 0))) __wur > > > __nonnull > > > ((1)); > > > extern int __REDIRECT (vscanf, (const char *__restrict __format, > > > __gnuc_va_list __arg), __isoc99_vscanf) > > > __attribute__ ((__format__ (__scanf__, 1, 0))) __wur; > > > @@ -549,7 +549,7 @@ extern int __REDIRECT_NTH (vsscanf, > > > # elif !defined __REDIRECT > > > extern int __isoc99_vfscanf (FILE *__restrict __s, > > > const char *__restrict __format, > > > - __gnuc_va_list __arg) __wur; > > > + __gnuc_va_list __arg) __wur __nonnull ((1)); > > > extern int __isoc99_vscanf (const char *__restrict __format, > > > __gnuc_va_list __arg) __wur; > > > extern int __isoc99_vsscanf (const char *__restrict __s, > > > @@ -568,8 +568,8 @@ extern int __isoc99_vsscanf (const char > > > *__restrict __s, > > > These functions are possible cancellation points and > > > therefore not > > > marked with __THROW. */ > > > -extern int fgetc (FILE *__stream); > > > -extern int getc (FILE *__stream); > > > +extern int fgetc (FILE *__stream) __nonnull ((1)); > > > +extern int getc (FILE *__stream) __nonnull ((1)); > > > /* Read a character from stdin. > > > @@ -582,7 +582,7 @@ extern int getchar (void); > > > These functions are possible cancellation points and > > > therefore not > > > marked with __THROW. */ > > > -extern int getc_unlocked (FILE *__stream); > > > +extern int getc_unlocked (FILE *__stream) __nonnull ((1)); > > > extern int getchar_unlocked (void); > > > #endif /* Use POSIX. */ > > > @@ -593,7 +593,7 @@ extern int getchar_unlocked (void); > > > cancellation point. But due to similarity with an POSIX > > > interface > > > or due to the implementation it is a cancellation point and > > > therefore not marked with __THROW. */ > > > -extern int fgetc_unlocked (FILE *__stream); > > > +extern int fgetc_unlocked (FILE *__stream) __nonnull ((1)); > > > #endif /* Use MISC. */ > > > @@ -604,8 +604,8 @@ extern int fgetc_unlocked (FILE *__stream); > > > These functions is a possible cancellation point and > > > therefore not > > > > Aside: here's a typo mixing plural and singular in the sentence (not > > part of your commit). I'll prepare a patch for it. > > > > > marked with __THROW. */ > > > -extern int fputc (int __c, FILE *__stream); > > > -extern int putc (int __c, FILE *__stream); > > > +extern int fputc (int __c, FILE *__stream) __nonnull ((2)); > > > +extern int putc (int __c, FILE *__stream) __nonnull ((2)); > > > /* Write a character to stdout. > > > @@ -620,7 +620,7 @@ extern int putchar (int __c); > > > cancellation point. But due to similarity with an POSIX > > > interface > > > or due to the implementation it is a cancellation point and > > > therefore not marked with __THROW. */ > > > -extern int fputc_unlocked (int __c, FILE *__stream); > > > +extern int fputc_unlocked (int __c, FILE *__stream) __nonnull > > > ((2)); > > > #endif /* Use MISC. */ > > > #ifdef __USE_POSIX199506 > > > @@ -628,7 +628,7 @@ extern int fputc_unlocked (int __c, FILE > > > *__stream); > > > These functions are possible cancellation points and > > > therefore not > > > marked with __THROW. */ > > > -extern int putc_unlocked (int __c, FILE *__stream); > > > +extern int putc_unlocked (int __c, FILE *__stream) __nonnull > > > ((2)); > > > extern int putchar_unlocked (int __c); > > > #endif /* Use POSIX. */ > > > @@ -636,10 +636,10 @@ extern int putchar_unlocked (int __c); > > > #if defined __USE_MISC \ > > > || (defined __USE_XOPEN && !defined __USE_XOPEN2K) > > > /* Get a word (int) from STREAM. */ > > > -extern int getw (FILE *__stream); > > > +extern int getw (FILE *__stream) __nonnull ((1)); > > > /* Write a word (int) to STREAM. */ > > > -extern int putw (int __w, FILE *__stream); > > > +extern int putw (int __w, FILE *__stream) __nonnull ((2)); > > > #endif > > > @@ -689,10 +689,10 @@ extern char *fgets_unlocked (char > > > *__restrict > > > __s, int __n, > > > therefore not marked with __THROW. */ > > > extern __ssize_t __getdelim (char **__restrict __lineptr, > > > size_t *__restrict __n, int > > > __delimiter, > > > - FILE *__restrict __stream) __wur; > > > + FILE *__restrict __stream) __wur > > > __nonnull ((4)); > > > extern __ssize_t getdelim (char **__restrict __lineptr, > > > size_t *__restrict __n, int > > > __delimiter, > > > - FILE *__restrict __stream) __wur; > > > + FILE *__restrict __stream) __wur > > > __nonnull > > > ((4)); > > > /* Like `getdelim', but reads up to a newline. > > > @@ -702,7 +702,7 @@ extern __ssize_t getdelim (char **__restrict > > > __lineptr, > > > therefore not marked with __THROW. */ > > > extern __ssize_t getline (char **__restrict __lineptr, > > > size_t *__restrict __n, > > > - FILE *__restrict __stream) __wur; > > > + FILE *__restrict __stream) __wur > > > __nonnull > > > ((3)); > > > #endif > > > @@ -723,7 +723,7 @@ extern int puts (const char *__s); > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int ungetc (int __c, FILE *__stream); > > > +extern int ungetc (int __c, FILE *__stream) __nonnull ((2)); > > > /* Read chunks of generic data from STREAM. > > > @@ -768,17 +768,17 @@ extern size_t fwrite_unlocked (const void > > > *__restrict __ptr, size_t __size, > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int fseek (FILE *__stream, long int __off, int __whence); > > > +extern int fseek (FILE *__stream, long int __off, int __whence) > > > __nonnull ((1)); > > > /* Return the current position of STREAM. > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern long int ftell (FILE *__stream) __wur; > > > +extern long int ftell (FILE *__stream) __wur __nonnull ((1)); > > > /* Rewind to the beginning of STREAM. > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern void rewind (FILE *__stream); > > > +extern void rewind (FILE *__stream) __nonnull ((1)); > > > /* The Single Unix Specification, Version 2, specifies an > > > alternative, > > > more adequate interface for the two functions above which > > > deal with > > > @@ -791,18 +791,19 @@ extern void rewind (FILE *__stream); > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int fseeko (FILE *__stream, __off_t __off, int __whence); > > > +extern int fseeko (FILE *__stream, __off_t __off, int __whence) > > > __nonnull ((1)); > > > /* Return the current position of STREAM. > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern __off_t ftello (FILE *__stream) __wur; > > > +extern __off_t ftello (FILE *__stream) __wur __nonnull ((1)); > > > # else > > > # ifdef __REDIRECT > > > extern int __REDIRECT (fseeko, > > > (FILE *__stream, __off64_t __off, int __whence), > > > - fseeko64); > > > -extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64); > > > + fseeko64) __nonnull ((1)); > > > +extern __off64_t __REDIRECT (ftello, (FILE *__stream), ftello64) > > > + __nonnull ((1)); > > > # else > > > # define fseeko fseeko64 > > > # define ftello ftello64 > > > @@ -815,18 +816,20 @@ extern __off64_t __REDIRECT (ftello, (FILE > > > *__stream), ftello64); > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict > > > __pos); > > > +extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict > > > __pos) > > > + __nonnull ((1)); > > > /* Set STREAM's position. > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int fsetpos (FILE *__stream, const fpos_t *__pos); > > > +extern int fsetpos (FILE *__stream, const fpos_t *__pos) > > > __nonnull > > > ((1)); > > > #else > > > # ifdef __REDIRECT > > > extern int __REDIRECT (fgetpos, (FILE *__restrict __stream, > > > - fpos_t *__restrict __pos), fgetpos64); > > > + fpos_t *__restrict __pos), fgetpos64) __nonnull > > > ((1)); > > > extern int __REDIRECT (fsetpos, > > > - (FILE *__stream, const fpos_t *__pos), fsetpos64); > > > + (FILE *__stream, const fpos_t *__pos), fsetpos64) > > > + __nonnull ((1)); > > > # else > > > # define fgetpos fgetpos64 > > > # define fsetpos fsetpos64 > > > @@ -834,24 +837,26 @@ extern int __REDIRECT (fsetpos, > > > #endif > > > #ifdef __USE_LARGEFILE64 > > > -extern int fseeko64 (FILE *__stream, __off64_t __off, int > > > __whence); > > > -extern __off64_t ftello64 (FILE *__stream) __wur; > > > -extern int fgetpos64 (FILE *__restrict __stream, fpos64_t > > > *__restrict > > > __pos); > > > -extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos); > > > +extern int fseeko64 (FILE *__stream, __off64_t __off, int > > > __whence) > > > + __nonnull ((1)); > > > +extern __off64_t ftello64 (FILE *__stream) __wur __nonnull ((1)); > > > +extern int fgetpos64 (FILE *__restrict __stream, fpos64_t > > > *__restrict > > > __pos) > > > + __nonnull ((1)); > > > +extern int fsetpos64 (FILE *__stream, const fpos64_t *__pos) > > > __nonnull ((1)); > > > #endif > > > /* Clear the error and EOF indicators for STREAM. */ > > > -extern void clearerr (FILE *__stream) __THROW; > > > +extern void clearerr (FILE *__stream) __THROW __nonnull ((1)); > > > /* Return the EOF indicator for STREAM. */ > > > -extern int feof (FILE *__stream) __THROW __wur; > > > +extern int feof (FILE *__stream) __THROW __wur __nonnull ((1)); > > > /* Return the error indicator for STREAM. */ > > > -extern int ferror (FILE *__stream) __THROW __wur; > > > +extern int ferror (FILE *__stream) __THROW __wur __nonnull ((1)); > > > #ifdef __USE_MISC > > > /* Faster versions when locking is not required. */ > > > -extern void clearerr_unlocked (FILE *__stream) __THROW; > > > -extern int feof_unlocked (FILE *__stream) __THROW __wur; > > > -extern int ferror_unlocked (FILE *__stream) __THROW __wur; > > > +extern void clearerr_unlocked (FILE *__stream) __THROW __nonnull > > > ((1)); > > > +extern int feof_unlocked (FILE *__stream) __THROW __wur __nonnull > > > ((1)); > > > +extern int ferror_unlocked (FILE *__stream) __THROW __wur > > > __nonnull > > > ((1)); > > > #endif > > > @@ -864,12 +869,12 @@ extern void perror (const char *__s) __COLD; > > > #ifdef __USE_POSIX > > > /* Return the system file descriptor for STREAM. */ > > > -extern int fileno (FILE *__stream) __THROW __wur; > > > +extern int fileno (FILE *__stream) __THROW __wur __nonnull ((1)); > > > #endif /* Use POSIX. */ > > > #ifdef __USE_MISC > > > /* Faster version when locking is not required. */ > > > -extern int fileno_unlocked (FILE *__stream) __THROW __wur; > > > +extern int fileno_unlocked (FILE *__stream) __THROW __wur > > > __nonnull > > > ((1)); > > > #endif > > > @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) > > > __THROW __wur; > > > This function is a possible cancellation point and therefore > > > not > > > marked with __THROW. */ > > > -extern int pclose (FILE *__stream); > > > +extern int pclose (FILE *__stream) __nonnull ((1)); > > > > You didn't patch fclose(3). Any reason? I guess it's similarly UB > > to > > call fclose(NULL). > > > > Cheers, > > Alex > > > > > /* Create a new stream connected to a pipe running the given > > > command. > > > @@ -922,14 +927,14 @@ extern int obstack_vprintf (struct obstack > > > *__restrict __obstack, > > > /* These are defined in POSIX.1:1996. */ > > > /* Acquire ownership of STREAM. */ > > > -extern void flockfile (FILE *__stream) __THROW; > > > +extern void flockfile (FILE *__stream) __THROW __nonnull ((1)); > > > /* Try to acquire ownership of STREAM but do not block if it is > > > not > > > possible. */ > > > -extern int ftrylockfile (FILE *__stream) __THROW __wur; > > > +extern int ftrylockfile (FILE *__stream) __THROW __wur __nonnull > > > ((1)); > > > /* Relinquish the ownership granted for STREAM. */ > > > -extern void funlockfile (FILE *__stream) __THROW; > > > +extern void funlockfile (FILE *__stream) __THROW __nonnull ((1)); > > > #endif /* POSIX */ > > > #if defined __USE_XOPEN && !defined __USE_XOPEN2K && !defined > > > __USE_GNU > > > > -- > <http://www.alejandro-colomar.es/> > GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 > -- Xi Ruoyao <xry111@xry111.site> School of Aerospace Science and Technology, Xidian University ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-19 4:13 ` Xi Ruoyao @ 2023-05-19 5:21 ` Xi Ruoyao 2023-05-19 12:40 ` Alejandro Colomar 0 siblings, 1 reply; 9+ messages in thread From: Xi Ruoyao @ 2023-05-19 5:21 UTC (permalink / raw) To: Alex Colomar, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell On Fri, 2023-05-19 at 12:13 +0800, Xi Ruoyao wrote: > On Thu, 2023-05-18 at 20:29 +0200, Alex Colomar wrote: > > On 5/18/23 20:06, Alex Colomar wrote: > > > Hi Xi! > > > > > > On 5/18/23 19:25, Xi Ruoyao via Libc-alpha wrote: > > > > During the review of a GCC analyzer test case, we found most stdio > > > > functions accepting a FILE * argument expect it to be nonnull and > > > > just > > > > segfault when the argument is NULL. Add nonnull attribute for > > > > them. > > > > > > > > setbuf is well defined when __stream is NULL so it's not touched. > > > > Is this true? I couldn't find anything about it in either setbuf(3), > > setbuf(3POSIX), or info libc. > > > > The buffer can be NULL, but the stream? > > I guess when I took the note on the paper I misspelled "fflush" as > "setbuf" for some reason (maybe lack of coffee :( ). > > I'll retest all the changes in one hour or two hours. I've sent v2 with the mistakes in fflush, fflush_unlocked, and setbuf fixed. Thanks for pointing out my mistake! I guess I need to avoid creating a patch at 0100 AM in the future :). -- Xi Ruoyao <xry111@xry111.site> School of Aerospace Science and Technology, Xidian University ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-19 5:21 ` Xi Ruoyao @ 2023-05-19 12:40 ` Alejandro Colomar 2023-05-19 13:03 ` Xi Ruoyao 0 siblings, 1 reply; 9+ messages in thread From: Alejandro Colomar @ 2023-05-19 12:40 UTC (permalink / raw) To: Xi Ruoyao, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell [-- Attachment #1.1: Type: text/plain, Size: 1270 bytes --] On 5/19/23 07:21, Xi Ruoyao via Libc-alpha wrote: > On Fri, 2023-05-19 at 12:13 +0800, Xi Ruoyao wrote: >> On Thu, 2023-05-18 at 20:29 +0200, Alex Colomar wrote: [...] >> >> I guess when I took the note on the paper I misspelled "fflush" as >> "setbuf" for some reason (maybe lack of coffee :( ). >> >> I'll retest all the changes in one hour or two hours. > > I've sent v2 with the mistakes in fflush, fflush_unlocked, and setbuf > fixed. Thanks for pointing out my mistake! > > I guess I need to avoid creating a patch at 0100 AM in the future :). I'm glad to help :-) How about fclose(3)? Was it left out on purpose, or was it a sleep(0) issue too? :p On 5/18/23 20:06, Alex Colomar via Libc-alpha wrote: >> @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) >> __THROW __wur; >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int pclose (FILE *__stream); >> +extern int pclose (FILE *__stream) __nonnull ((1)); > > You didn't patch fclose(3). Any reason? I guess it's similarly UB to > call fclose(NULL). Cheers, Alex > -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-19 12:40 ` Alejandro Colomar @ 2023-05-19 13:03 ` Xi Ruoyao 2023-05-19 13:07 ` Alejandro Colomar 0 siblings, 1 reply; 9+ messages in thread From: Xi Ruoyao @ 2023-05-19 13:03 UTC (permalink / raw) To: Alejandro Colomar, libc-alpha Cc: Adhemerval Zanella Netto, Carlos O'Donell On Fri, 2023-05-19 at 14:40 +0200, Alejandro Colomar wrote: > On 5/19/23 07:21, Xi Ruoyao via Libc-alpha wrote: > > On Fri, 2023-05-19 at 12:13 +0800, Xi Ruoyao wrote: > > > On Thu, 2023-05-18 at 20:29 +0200, Alex Colomar wrote: > > [...] > > > > > > > I guess when I took the note on the paper I misspelled "fflush" as > > > "setbuf" for some reason (maybe lack of coffee :( ). > > > > > > I'll retest all the changes in one hour or two hours. > > > > I've sent v2 with the mistakes in fflush, fflush_unlocked, and > > setbuf > > fixed. Thanks for pointing out my mistake! > > > I guess I need to avoid creating a patch at 0100 AM in the future > > :). > > I'm glad to help :-) > > How about fclose(3)? Was it left out on purpose, or was it a sleep(0) > issue too? :p It was done at https://sourceware.org/git/?p=glibc.git;a=commit;h=71d9e0fe Actually fclose is the start point of this __nonnull addition: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109570 But unfortunately in Apr I didn't have enough time to check the entire stdio.h function by function. Then in the following discussion for the GCC PR we found ferror should have __nonnull too and I decided to check all stdio.h functions this time. > > On 5/18/23 20:06, Alex Colomar via Libc-alpha wrote: > >> @@ -878,7 +883,7 @@ extern int fileno_unlocked (FILE *__stream) > >> __THROW __wur; > >> This function is a possible cancellation point and therefore > not > >> marked with __THROW. */ > >> -extern int pclose (FILE *__stream); > >> +extern int pclose (FILE *__stream) __nonnull ((1)); > > > > You didn't patch fclose(3). Any reason? I guess it's similarly UB > to > > call fclose(NULL). > > Cheers, > Alex > > > > > -- > <http://www.alejandro-colomar.es/> > GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 > -- Xi Ruoyao <xry111@xry111.site> School of Aerospace Science and Technology, Xidian University ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-19 13:03 ` Xi Ruoyao @ 2023-05-19 13:07 ` Alejandro Colomar 0 siblings, 0 replies; 9+ messages in thread From: Alejandro Colomar @ 2023-05-19 13:07 UTC (permalink / raw) To: Xi Ruoyao, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell [-- Attachment #1.1: Type: text/plain, Size: 1533 bytes --] On 5/19/23 15:03, Xi Ruoyao wrote: > On Fri, 2023-05-19 at 14:40 +0200, Alejandro Colomar wrote: >> On 5/19/23 07:21, Xi Ruoyao via Libc-alpha wrote: >>> On Fri, 2023-05-19 at 12:13 +0800, Xi Ruoyao wrote: >>>> On Thu, 2023-05-18 at 20:29 +0200, Alex Colomar wrote: >> >> [...] >> >>>> >>>> I guess when I took the note on the paper I misspelled "fflush" as >>>> "setbuf" for some reason (maybe lack of coffee :( ). >>>> >>>> I'll retest all the changes in one hour or two hours. >>> >>> I've sent v2 with the mistakes in fflush, fflush_unlocked, and >>> setbuf >>> fixed. Thanks for pointing out my mistake! > >>> I guess I need to avoid creating a patch at 0100 AM in the future >>> :). >> >> I'm glad to help :-) >> >> How about fclose(3)? Was it left out on purpose, or was it a sleep(0) >> issue too? :p > > It was done at > https://sourceware.org/git/?p=glibc.git;a=commit;h=71d9e0fe > > Actually fclose is the start point of this __nonnull addition: > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109570 > > But unfortunately in Apr I didn't have enough time to check the entire > stdio.h function by function. Then in the following discussion for the > GCC PR we found ferror should have __nonnull too and I decided to check > all stdio.h functions this time. Good to know! Makes sense. LGTM then. Acked-by: Alejandro Colomar <alx@kernel.org> Cheers, Alex -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h 2023-05-18 18:06 ` Alex Colomar 2023-05-18 18:29 ` Alex Colomar @ 2023-05-18 18:56 ` Alejandro Colomar 1 sibling, 0 replies; 9+ messages in thread From: Alejandro Colomar @ 2023-05-18 18:56 UTC (permalink / raw) To: Xi Ruoyao, libc-alpha; +Cc: Adhemerval Zanella Netto, Carlos O'Donell [-- Attachment #1.1: Type: text/plain, Size: 3605 bytes --] On 5/18/23 20:06, Alex Colomar wrote: > Hi Xi! > > On 5/18/23 19:25, Xi Ruoyao via Libc-alpha wrote: >> During the review of a GCC analyzer test case, we found most stdio >> functions accepting a FILE * argument expect it to be nonnull and just >> segfault when the argument is NULL. Add nonnull attribute for them. >> >> setbuf is well defined when __stream is NULL so it's not touched. >> >> For fputs, fgets, fread, fwrite, fprintf, vfprintf, and their unlocked >> version, if __stream is empty but there is nothing to read or write, >> they don't segfault and I'm not sure if the standard allows such a use >> so I left them out. >> --- >> libio/stdio.h | 119 ++++++++++++++++++++++++++------------------------ >> 1 file changed, 62 insertions(+), 57 deletions(-) >> >> diff --git a/libio/stdio.h b/libio/stdio.h >> index 4cf9f1c012..ae3d7295d4 100644 >> --- a/libio/stdio.h >> +++ b/libio/stdio.h >> @@ -232,7 +232,7 @@ extern char *tempnam (const char *__dir, const >> char *__pfx) >> This function is a possible cancellation point and therefore not >> marked with __THROW. */ >> -extern int fflush (FILE *__stream); >> +extern int fflush (FILE *__stream) __nonnull ((1)); > > flush(NULL) is well defined. It flushes all streams that can be > flushed. This reminds me that I should document that in the SYNOPSIS > section of the manual page; an oversight on my side. I just pushed this: <https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/commit/?id=cd03c9b8d1f4d43ab7b010d02287dec1805ada34> commit cd03c9b8d1f4d43ab7b010d02287dec1805ada34 (HEAD -> master, korg/master, alx/main, alx/HEAD, main) Author: Alejandro Colomar <alx@kernel.org> Date: Thu May 18 20:53:14 2023 +0200 fflush.3, unlocked_stdio.3: SYNOPSIS: The streams can be null Cc: Xi Ruoyao <xry111@xry111.site> Signed-off-by: Alejandro Colomar <alx@kernel.org> diff --git a/man3/fflush.3 b/man3/fflush.3 index 327786cef..2098bba08 100644 --- a/man3/fflush.3 +++ b/man3/fflush.3 @@ -25,7 +25,7 @@ Standard C library .nf .B #include <stdio.h> .PP -.BI "int fflush(FILE *" stream ); +.BI "int fflush(FILE *_Nullable " stream ); .fi .SH DESCRIPTION For output streams, diff --git a/man3/unlocked_stdio.3 b/man3/unlocked_stdio.3 index faab29f06..feed708db 100644 --- a/man3/unlocked_stdio.3 +++ b/man3/unlocked_stdio.3 @@ -23,7 +23,7 @@ Standard C library .BI "int feof_unlocked(FILE *" stream ); .BI "int ferror_unlocked(FILE *" stream ); .BI "int fileno_unlocked(FILE *" stream ); -.BI "int fflush_unlocked(FILE *" stream ); +.BI "int fflush_unlocked(FILE *_Nullable " stream ); .PP .BI "int fgetc_unlocked(FILE *" stream ); .BI "int fputc_unlocked(int " c ", FILE *" stream ); > >> #ifdef __USE_MISC >> /* Faster versions when locking is not required. >> @@ -241,7 +241,7 @@ extern int fflush (FILE *__stream); >> cancellation point. But due to similarity with an POSIX interface >> or due to the implementation it is a cancellation point and >> therefore not marked with __THROW. */ >> -extern int fflush_unlocked (FILE *__stream); >> +extern int fflush_unlocked (FILE *__stream) __nonnull ((1)); > > Without checking, I'll guess that fflush_unlocked(NULL) is also well > defined. > > I didn't see any other similar cases, but I may have missed some; I > didn't revise them all thoroughly; please check. > -- <http://www.alejandro-colomar.es/> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5 [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-05-19 13:07 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2023-05-18 17:25 [PATCH] libio: Add nonnull attribute for most FILE * arguments in stdio.h Xi Ruoyao 2023-05-18 18:06 ` Alex Colomar 2023-05-18 18:29 ` Alex Colomar 2023-05-19 4:13 ` Xi Ruoyao 2023-05-19 5:21 ` Xi Ruoyao 2023-05-19 12:40 ` Alejandro Colomar 2023-05-19 13:03 ` Xi Ruoyao 2023-05-19 13:07 ` Alejandro Colomar 2023-05-18 18:56 ` Alejandro Colomar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).