]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Annotate additional APIs with GCC attribute access.
authorMartin Sebor <msebor@redhat.com>
Thu, 6 May 2021 16:56:25 +0000 (10:56 -0600)
committerMartin Sebor <msebor@redhat.com>
Thu, 6 May 2021 17:01:05 +0000 (11:01 -0600)
This change continues the improvements to compile-time out of bounds
checking by decorating more APIs with either attribute access, or by
explicitly providing the array bound in APIs such as tmpnam() that
expect arrays of some minimum size as arguments.  (The latter feature
is new in GCC 11.)

The only effects of the attribute and/or the array bound is to check
and diagnose calls to the functions that fail to provide a sufficient
number of elements, and the definitions of the functions that access
elements outside the specified bounds.  (There is no interplay with
_FORTIFY_SOURCE here yet.)

Tested with GCC 7 through 11 on x86_64-linux.

16 files changed:
inet/if_index.c
io/bits/poll2.h
io/sys/poll.h
libio/stdio.h
misc/sys/uio.h
nss/makedb.c
posix/bug-regex33.c
posix/regex.h
pwd/pwd.h
stdio-common/tmpnam.c
stdio-common/tmpnam_r.c
stdlib/monetary.h
sysdeps/gnu/net/if.h
sysdeps/mach/hurd/if_index.c
sysdeps/unix/sysv/linux/if_index.c
sysdeps/unix/sysv/linux/test-errno-linux.c

index b85a93f9a4534ee987e9e005f8cdc3c695d5b06c..0442633142935783a850c7bd736c2cbb0a7787d1 100644 (file)
@@ -31,7 +31,7 @@ libc_hidden_weak (if_nametoindex)
 stub_warning (if_nametoindex)
 
 char *
-__if_indextoname (unsigned int ifindex, char *ifname)
+__if_indextoname (unsigned int ifindex, char ifname[IF_NAMESIZE])
 {
   __set_errno (ENOSYS);
   return NULL;
index 882fcc9ea2d3e2a0b6a7994d26d0b18169129f2e..a623678c09f9f04f7925d47b9b14de8024c549e5 100644 (file)
@@ -26,13 +26,14 @@ __BEGIN_DECLS
 extern int __REDIRECT (__poll_alias, (struct pollfd *__fds, nfds_t __nfds,
                                      int __timeout), poll);
 extern int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
-                      __SIZE_TYPE__ __fdslen);
+                      __SIZE_TYPE__ __fdslen)
+    __attr_access ((__write_only__, 1, 2));
 extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
                                         int __timeout, __SIZE_TYPE__ __fdslen),
                       __poll_chk)
   __warnattr ("poll called with fds buffer too small file nfds entries");
 
-__fortify_function int
+__fortify_function __attr_access ((__write_only__, 1, 2)) int
 poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
 {
   if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
@@ -54,7 +55,8 @@ extern int __REDIRECT (__ppoll_alias, (struct pollfd *__fds, nfds_t __nfds,
                                       const __sigset_t *__ss), ppoll);
 extern int __ppoll_chk (struct pollfd *__fds, nfds_t __nfds,
                        const struct timespec *__timeout,
-                       const __sigset_t *__ss, __SIZE_TYPE__ __fdslen);
+                       const __sigset_t *__ss, __SIZE_TYPE__ __fdslen)
+    __attr_access ((__write_only__, 1, 2));
 extern int __REDIRECT (__ppoll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
                                          const struct timespec *__timeout,
                                          const __sigset_t *__ss,
@@ -62,7 +64,7 @@ extern int __REDIRECT (__ppoll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
                       __ppoll_chk)
   __warnattr ("ppoll called with fds buffer too small file nfds entries");
 
-__fortify_function int
+__fortify_function __attr_access ((__write_only__, 1, 2)) int
 ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
        const __sigset_t *__ss)
 {
index 2431dd1e148e469a87982b0bee9e302a472d4724..08f29df540dc10c4f6e47acb1efeafa874f27de7 100644 (file)
@@ -51,7 +51,8 @@ __BEGIN_DECLS
 
    This function is a cancellation point and therefore not marked with
    __THROW.  */
-extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
+extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+    __attr_access ((__write_only__, 1, 2));
 
 #ifdef __USE_GNU
 /* Like poll, but before waiting the threads signal mask is replaced
@@ -62,7 +63,9 @@ extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
    __THROW.  */
 extern int ppoll (struct pollfd *__fds, nfds_t __nfds,
                  const struct timespec *__timeout,
-                 const __sigset_t *__ss);
+                 const __sigset_t *__ss)
+    __attr_access ((__write_only__, 1, 2));
+
 #endif
 
 __END_DECLS
index 144137cf67aadac3e86844e37f0fe47c45072fd3..76bda3728e33766a449d0ba979efbaa627989896 100644 (file)
@@ -184,12 +184,12 @@ extern FILE *tmpfile64 (void) __wur;
 #endif
 
 /* Generate a temporary filename.  */
-extern char *tmpnam (char *__s) __THROW __wur;
+extern char *tmpnam (char[L_tmpnam]) __THROW __wur;
 
 #ifdef __USE_MISC
 /* This is the reentrant variant of `tmpnam'.  The only difference is
    that it does not allow S to be NULL.  */
-extern char *tmpnam_r (char *__s) __THROW __wur;
+extern char *tmpnam_r (char __s[L_tmpnam]) __THROW __wur;
 #endif
 
 
@@ -808,13 +808,15 @@ extern int pclose (FILE *__stream);
 
 #ifdef __USE_POSIX
 /* Return the name of the controlling terminal.  */
-extern char *ctermid (char *__s) __THROW;
+extern char *ctermid (char *__s) __THROW
+  __attr_access ((__write_only__, 1));
 #endif /* Use POSIX.  */
 
 
 #if (defined __USE_XOPEN && !defined __USE_XOPEN2K) || defined __USE_GNU
 /* Return the name of the current user.  */
-extern char *cuserid (char *__s);
+extern char *cuserid (char *__s)
+  __attr_access ((__write_only__, 1));
 #endif /* Use X/Open, but not issue 6.  */
 
 
index 474527d11215109ee4995c04c7f6cefc56dbab5f..08dcb39c99e885c0d1e7e4f8740a042ab3a4c5c4 100644 (file)
@@ -39,7 +39,7 @@ __BEGIN_DECLS
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t readv (int __fd, const struct iovec *__iovec, int __count)
-  __wur;
+  __wur __attr_access ((__read_only__, 2, 3));
 
 /* Write data pointed by the buffers described by IOVEC, which
    is a vector of COUNT 'struct iovec's, to file descriptor FD.
@@ -50,7 +50,7 @@ extern ssize_t readv (int __fd, const struct iovec *__iovec, int __count)
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t writev (int __fd, const struct iovec *__iovec, int __count)
-  __wur;
+  __wur __attr_access ((__read_only__, 2, 3));
 
 
 #ifdef __USE_MISC
@@ -65,7 +65,8 @@ extern ssize_t writev (int __fd, const struct iovec *__iovec, int __count)
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t preadv (int __fd, const struct iovec *__iovec, int __count,
-                      __off_t __offset) __wur;
+                      __off_t __offset)
+  __wur __attr_access ((__read_only__, 2, 3));
 
 /* Write data pointed by the buffers described by IOVEC, which is a
    vector of COUNT 'struct iovec's, to file descriptor FD at the given
@@ -77,16 +78,19 @@ extern ssize_t preadv (int __fd, const struct iovec *__iovec, int __count,
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t pwritev (int __fd, const struct iovec *__iovec, int __count,
-                       __off_t __offset) __wur;
+                       __off_t __offset)
+  __wur __attr_access ((__read_only__, 2, 3));
 
 # else
 #  ifdef __REDIRECT
 extern ssize_t __REDIRECT (preadv, (int __fd, const struct iovec *__iovec,
                                    int __count, __off64_t __offset),
-                          preadv64) __wur;
+                          preadv64)
+  __wur __attr_access ((__read_only__, 2, 3));
 extern ssize_t __REDIRECT (pwritev, (int __fd, const struct iovec *__iovec,
                                     int __count, __off64_t __offset),
-                          pwritev64) __wur;
+                          pwritev64)
+  __wur __attr_access ((__read_only__, 2, 3));
 #  else
 #   define preadv preadv64
 #   define pwritev pwritev64
@@ -104,7 +108,8 @@ extern ssize_t __REDIRECT (pwritev, (int __fd, const struct iovec *__iovec,
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t preadv64 (int __fd, const struct iovec *__iovec, int __count,
-                        __off64_t __offset) __wur;
+                        __off64_t __offset)
+  __wur __attr_access ((__read_only__, 2, 3));
 
 /* Write data pointed by the buffers described by IOVEC, which is a
    vector of COUNT 'struct iovec's, to file descriptor FD at the given
@@ -116,7 +121,8 @@ extern ssize_t preadv64 (int __fd, const struct iovec *__iovec, int __count,
    This function is a cancellation point and therefore not marked with
    __THROW.  */
 extern ssize_t pwritev64 (int __fd, const struct iovec *__iovec, int __count,
-                         __off64_t __offset) __wur;
+                         __off64_t __offset)
+  __wur __attr_access ((__read_only__, 2, 3));
 # endif
 #endif /* Use misc.  */
 
@@ -125,7 +131,8 @@ extern ssize_t pwritev64 (int __fd, const struct iovec *__iovec, int __count,
 # ifndef __USE_FILE_OFFSET64
 /* Same as preadv but with an additional flag argumenti defined at uio.h.  */
 extern ssize_t preadv2 (int __fp, const struct iovec *__iovec, int __count,
-                       __off_t __offset, int ___flags) __wur;
+                       __off_t __offset, int ___flags)
+  __wur __attr_access ((__read_only__, 2, 3));
 
 /* Same as preadv but with an additional flag argument defined at uio.h.  */
 extern ssize_t pwritev2 (int __fd, const struct iovec *__iodev, int __count,
@@ -136,11 +143,13 @@ extern ssize_t pwritev2 (int __fd, const struct iovec *__iodev, int __count,
 extern ssize_t __REDIRECT (pwritev2, (int __fd, const struct iovec *__iovec,
                                      int __count, __off64_t __offset,
                                      int __flags),
-                          pwritev64v2) __wur;
+                          pwritev64v2)
+  __wur __attr_access ((__read_only__, 2, 3));
 extern ssize_t __REDIRECT (preadv2, (int __fd, const struct iovec *__iovec,
                                     int __count, __off64_t __offset,
                                     int __flags),
-                          preadv64v2) __wur;
+                          preadv64v2)
+  __wur __attr_access ((__read_only__, 2, 3));
 #  else
 #   define preadv2 preadv64v2
 #   define pwritev2 pwritev64v2
@@ -151,12 +160,14 @@ extern ssize_t __REDIRECT (preadv2, (int __fd, const struct iovec *__iovec,
 /* Same as preadv but with an additional flag argumenti defined at uio.h.  */
 extern ssize_t preadv64v2 (int __fp, const struct iovec *__iovec,
                           int __count, __off64_t __offset,
-                          int ___flags) __wur;
+                          int ___flags)
+  __wur __attr_access ((__read_only__, 2, 3));
 
 /* Same as preadv but with an additional flag argument defined at uio.h.  */
 extern ssize_t pwritev64v2 (int __fd, const struct iovec *__iodev,
                            int __count, __off64_t __offset,
-                           int __flags) __wur;
+                           int __flags)
+  __wur __attr_access ((__read_only__, 2, 3));
 # endif
 #endif /* Use GNU.  */
 
index 74edb749cf45c82291e90e1cf169a685c5caf86e..9389f6b548e5788bdd020c54cfe9755be1cb5854 100644 (file)
@@ -747,7 +747,8 @@ write_output (int fd)
   header->valstrlen = valstrlen;
 
   size_t filled_dbs = 0;
-  struct iovec iov[2 + ndatabases * 3];
+  size_t iov_nelts = 2 + ndatabases * 3;
+  struct iovec iov[iov_nelts];
   iov[0].iov_base = header;
   iov[0].iov_len = file_offset;
 
@@ -791,7 +792,9 @@ write_output (int fd)
                          + nhashentries_total * sizeof (stridx_t)));
   header->allocate = file_offset;
 
-  if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)
+  /* Help GCC 10 see iov_nelts doesn't overflow the writev argument.  */
+  assert (iov_nelts <= INT_MAX);
+  if (writev (fd, iov, iov_nelts) != keydataoffset)
     {
       error (0, errno, gettext ("failed to write new database file"));
       return EXIT_FAILURE;
index 2140cda96a1711c5c4bc5d43ddf823e04c2fed8d..86569465cfea97f50039622aea10d2dd69edf33a 100644 (file)
@@ -105,7 +105,7 @@ do_test (void)
                 /* 新処圭新, \xb7\xbd here really matches 圭,
                  * this is a reproducer of bug-regex25 */
   e = re_search (&r, "\xbf\xb7\xbd\xe8\xb7\xbd\xbf\xb7",
-                 10, 0, 10, &s);
+                 9, 0, 9, &s);
   if (e != 4)
     {
       printf ("bug-regex33.7: no match or false match: re_search() returned %d, should return 4\n", e);
index 8e4ef45578383fa98b2f0060eca67c1cc654354f..14fb1d8364a11d2973d3eb9aaa481372418b4b98 100644 (file)
@@ -536,7 +536,8 @@ extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
    'regcomp', with a malloc'ed value, or set to NULL before calling
    'regfree'.  */
 extern const char *re_compile_pattern (const char *__pattern, size_t __length,
-                                      struct re_pattern_buffer *__buffer);
+                                      struct re_pattern_buffer *__buffer)
+    __attr_access ((__read_only__, 1, 2));
 
 
 /* Compile a fastmap for the compiled pattern in BUFFER; used to
@@ -553,7 +554,8 @@ extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
 extern regoff_t re_search (struct re_pattern_buffer *__buffer,
                           const char *__String, regoff_t __length,
                           regoff_t __start, regoff_t __range,
-                          struct re_registers *__regs);
+                          struct re_registers *__regs)
+    __attr_access ((__read_only__, 2, 3));
 
 
 /* Like 're_search', but search in the concatenation of STRING1 and
@@ -563,14 +565,17 @@ extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer,
                             const char *__string2, regoff_t __length2,
                             regoff_t __start, regoff_t __range,
                             struct re_registers *__regs,
-                            regoff_t __stop);
+                            regoff_t __stop)
+    __attr_access ((__read_only__, 2, 3))
+    __attr_access ((__read_only__, 4, 5));
 
 
 /* Like 're_search', but return how many characters in STRING the regexp
    in BUFFER matched, starting at position START.  */
 extern regoff_t re_match (struct re_pattern_buffer *__buffer,
                          const char *__String, regoff_t __length,
-                         regoff_t __start, struct re_registers *__regs);
+                         regoff_t __start, struct re_registers *__regs)
+    __attr_access ((__read_only__, 2, 3));
 
 
 /* Relates to 're_match' as 're_search_2' relates to 're_search'.  */
@@ -578,7 +583,9 @@ extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer,
                            const char *__string1, regoff_t __length1,
                            const char *__string2, regoff_t __length2,
                            regoff_t __start, struct re_registers *__regs,
-                           regoff_t __stop);
+                           regoff_t __stop)
+    __attr_access ((__read_only__, 2, 3))
+    __attr_access ((__read_only__, 4, 5));
 
 
 /* Set REGS to hold NUM_REGS registers, storing them in STARTS and
@@ -648,10 +655,12 @@ extern int regcomp (regex_t *_Restrict_ __preg,
 extern int regexec (const regex_t *_Restrict_ __preg,
                    const char *_Restrict_ __String, size_t __nmatch,
                    regmatch_t __pmatch[_Restrict_arr_],
-                   int __eflags);
+                   int __eflags)
+    __attr_access ((__write_only__, 4, 3));
 
 extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
-                       char *_Restrict_ __errbuf, size_t __errbuf_size);
+                       char *_Restrict_ __errbuf, size_t __errbuf_size)
+    __attr_access ((__write_only__, 3, 4));
 
 extern void regfree (regex_t *__preg);
 
index c2ddce2b2defa3510b4f2ba3ee8b15fc2282eaf8..ec83c0963b83c971eb892a7ea80c3d0c4d624c4e 100644 (file)
--- a/pwd/pwd.h
+++ b/pwd/pwd.h
@@ -139,20 +139,23 @@ extern struct passwd *getpwnam (const char *__name) __nonnull ((1));
 extern int getpwent_r (struct passwd *__restrict __resultbuf,
                       char *__restrict __buffer, size_t __buflen,
                       struct passwd **__restrict __result)
-                      __nonnull ((1, 2, 4));
+    __nonnull ((1, 2, 4))
+    __attr_access ((__write_only__, 2, 3));
 # endif
 
 extern int getpwuid_r (__uid_t __uid,
                       struct passwd *__restrict __resultbuf,
                       char *__restrict __buffer, size_t __buflen,
                       struct passwd **__restrict __result)
-                      __nonnull ((2, 3, 5));
+    __nonnull ((2, 3, 5))
+    __attr_access ((__write_only__, 3, 4));
 
 extern int getpwnam_r (const char *__restrict __name,
                       struct passwd *__restrict __resultbuf,
                       char *__restrict __buffer, size_t __buflen,
                       struct passwd **__restrict __result)
-                      __nonnull ((1, 2, 3, 5));
+    __nonnull ((1, 2, 3, 5))
+    __attr_access ((__write_only__, 3, 4));
 
 
 # ifdef        __USE_MISC
@@ -167,7 +170,8 @@ extern int fgetpwent_r (FILE *__restrict __stream,
                        struct passwd *__restrict __resultbuf,
                        char *__restrict __buffer, size_t __buflen,
                        struct passwd **__restrict __result)
-                       __nonnull ((1, 2, 3, 5));
+    __nonnull ((1, 2, 3, 5))
+    __attr_access ((__write_only__, 3, 4));
 # endif
 
 #endif /* POSIX or reentrant */
index a5621c2aa55d7cec0a944a57fc5adb04d488c366..701ec95606d9b1dec4f697cc95ea4efceae8393c 100644 (file)
@@ -24,7 +24,7 @@ static char tmpnam_buffer[L_tmpnam];
 
    This function is *not* thread safe!  */
 char *
-tmpnam (char *s)
+tmpnam (char s[L_tmpnam])
 {
   /* By using two buffers we manage to be thread safe in the case
      where S != NULL.  */
index 3fd20308be8023be455e0b65297255d0a2595877..1af0aa82dac15e07923994d5a212db9eac9c0914 100644 (file)
@@ -20,7 +20,7 @@
 /* Generate a unique filename in P_tmpdir.  If S is NULL return NULL.
    This makes this function thread safe.  */
 char *
-tmpnam_r (char *s)
+tmpnam_r (char s[L_tmpnam])
 {
   if (s == NULL)
     return NULL;
index a29af54c0b194316a627c7fa910c820ea809d543..52a2f510028730a5347ff80575659d312e997095 100644 (file)
@@ -37,7 +37,8 @@ __BEGIN_DECLS
 /* Formatting a monetary value according to the current locale.  */
 extern ssize_t strfmon (char *__restrict __s, size_t __maxsize,
                        const char *__restrict __format, ...)
-     __THROW __attribute_format_strfmon__ (3, 4);
+     __THROW __attribute_format_strfmon__ (3, 4)
+     __attr_access ((__write_only__, 1, 2));
 
 #ifdef __USE_XOPEN2K8
 /* POSIX.1-2008 extended locale interface (see locale.h).  */
@@ -47,7 +48,8 @@ extern ssize_t strfmon (char *__restrict __s, size_t __maxsize,
 extern ssize_t strfmon_l (char *__restrict __s, size_t __maxsize,
                          locale_t __loc,
                          const char *__restrict __format, ...)
-     __THROW __attribute_format_strfmon__ (4, 5);
+     __THROW __attribute_format_strfmon__ (4, 5)
+     __attr_access ((__write_only__, 1, 2));
 #endif
 
 #include <bits/floatn.h>
index 61e6bc25276257c63bf314c910bfdc9adea2a5b2..79d3c885126f33b931c7628f7476ad8efc9abb30 100644 (file)
@@ -191,7 +191,9 @@ __BEGIN_DECLS
 
 /* Convert an interface name to an index, and vice versa.  */
 extern unsigned int if_nametoindex (const char *__ifname) __THROW;
-extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
+extern char *if_indextoname (unsigned int __ifindex,
+                            char __ifname[IF_NAMESIZE]) __THROW
+    __attr_access ((__write_only__, 2));
 
 /* Return a list of all interfaces and their indices.  */
 extern struct if_nameindex *if_nameindex (void) __THROW;
index 56e63a4a92b50adbdb2ef3154e36ad2f6b115578..0eab510453c9e86182e461b7863e62b1b8d170aa 100644 (file)
@@ -166,7 +166,7 @@ libc_hidden_weak (if_nameindex)
    IFNAME (which has space for at least IFNAMSIZ characters).  Return
    IFNAME, or NULL on error.  */
 char *
-__if_indextoname (unsigned int ifindex, char *ifname)
+__if_indextoname (unsigned int ifindex, char ifname[IF_NAMESIZE])
 {
   struct ifreq ifr;
   int fd = __opensock ();
index 70a16a69c4f8738f139bffbb5600ab4f6d67aa11..d38340bb64d1e3fb44eaebd0a10a0f37333ab310 100644 (file)
@@ -215,7 +215,7 @@ libc_hidden_weak (if_nameindex)
 
 
 char *
-__if_indextoname (unsigned int ifindex, char *ifname)
+__if_indextoname (unsigned int ifindex, char ifname[IF_NAMESIZE])
 {
   /* We may be able to do the conversion directly, rather than searching a
      list.  This ioctl is not present in kernels before version 2.1.50.  */
index d63836e584c040e5fac1f9827e9821b8b3bcad32..65fb90f9fcaf6733b4917b2ddc4c4d12d6a17702 100644 (file)
@@ -44,6 +44,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <libc-diag.h>
 
 /* This is not an exhaustive test: only system calls that can be
    persuaded to fail with a consistent error code and no side effects
@@ -171,7 +172,18 @@ do_test (void)
      allocation.  */
   fails |= test_wrp2 (LIST (EINVAL, ENOMEM), mlock, (void *) -1, 1);
   fails |= test_wrp (EINVAL, nanosleep, &ts, &ts);
+
+  DIAG_POP_NEEDS_COMMENT;
+
+#if __GNUC_PREREQ (9, 0)
+  /* Suppress valid GCC warning:
+     'poll' specified size 18446744073709551608 exceeds maximum object size
+  */
+  DIAG_IGNORE_NEEDS_COMMENT (9, "-Wstringop-overflow=");
+#endif
   fails |= test_wrp (EINVAL, poll, &pollfd, -1, 0);
+  DIAG_POP_NEEDS_COMMENT;
+
   /* quotactl returns ENOSYS for kernels not configured with
      CONFIG_QUOTA, and may return EPERM if called within certain types
      of containers.  Linux 5.4 added additional argument validation