Skip to content

Use countof() where appropriate, and do it implicitly where possible#1588

Open
alejandro-colomar wants to merge 8 commits into
shadow-maint:masterfrom
alejandro-colomar:of
Open

Use countof() where appropriate, and do it implicitly where possible#1588
alejandro-colomar wants to merge 8 commits into
shadow-maint:masterfrom
alejandro-colomar:of

Conversation

@alejandro-colomar
Copy link
Copy Markdown
Collaborator

@alejandro-colomar alejandro-colomar commented Mar 16, 2026

This improves bounds safety by using countof(3) where appropriate, and doing it implicitly where possible.

Cc: @kees


Revisions:

v1b
  • Update lib/string/README.
$ git rd 
1:  91814a70 = 1:  91814a70 lib/, src/, tests/: Use countof() or sizeof_a() where appropriate
2:  35962749 = 2:  35962749 lib/salt.c: crypt_make_salt(): Use countof() instead of a hardcoded value
3:  b53f7325 = 3:  b53f7325 lib/sizeof.h: endof(): Add macro
4:  f355a1b4 = 4:  f355a1b4 lib/fields.[ch]: change_field_a(): Add macro
5:  cd6d3c42 = 5:  cd6d3c42 src/: Use change_field_a() instead of its pattern
6:  39e963ed ! 6:  b5e41a06 lib/string/memset/: bzero_a(): Add macro
    @@ lib/Makefile.am: libshadow_la_SOURCES = \
        string/memset/memzero.h \
        string/sprintf/aprintf.c \
     
    + ## lib/string/README ##
    +@@ lib/string/README: ctype/ - Character classification and conversion functions
    + 
    + memset/ - Memory zeroing
    + 
    ++    bzero_a()
    ++  Like bzero(3), but takes an array.
    ++
    +     memzero()
    +   Synonym of explicit_bzero(3).
    +     memzero_a()
    +
      ## lib/string/memset/bzero.c (new) ##
     @@
     +// SPDX-FileCopyrightText: 2024, Alejandro Colomar <[email protected]>
7:  b02d91a9 = 7:  210f91ef lib/: Use bzero_a() instead of its pattern
8:  077542bd = 8:  dd2262a8 lib/audit_help.c: Use countof() instead of sizeof()
v2
  • Consistently use sizeof_a() with read(2).
$ git rd 
1:  91814a70 ! 1:  580ccf69 lib/, src/, tests/: Use countof() or sizeof_a() where appropriate
    @@ src/newgidmap.c: static void write_setgroups(int proc_dir_fd, bool allow_setgrou
         * fail.
         */
     -  if (read(setgroups_fd, policy_buffer, sizeof(policy_buffer)) < 0) {
    -+  if (read(setgroups_fd, policy_buffer, countof(policy_buffer)) < 0) {
    ++  if (read(setgroups_fd, policy_buffer, sizeof_a(policy_buffer)) < 0) {
                fprintf(stderr, _("%s: failed to read setgroups: %s\n"),
                        Prog, strerrno());
                exit(EXIT_FAILURE);
2:  35962749 = 2:  3805154d lib/salt.c: crypt_make_salt(): Use countof() instead of a hardcoded value
3:  b53f7325 = 3:  aa6a3dcd lib/sizeof.h: endof(): Add macro
4:  f355a1b4 = 4:  d29e1cac lib/fields.[ch]: change_field_a(): Add macro
5:  cd6d3c42 = 5:  524beee5 src/: Use change_field_a() instead of its pattern
6:  b5e41a06 = 6:  2d4f61d4 lib/string/memset/: bzero_a(): Add macro
7:  210f91ef = 7:  68da424c lib/: Use bzero_a() instead of its pattern
8:  dd2262a8 = 8:  8ae2c113 lib/audit_help.c: Use countof() instead of sizeof()
v2b
  • Rebase
$ git rd 
1:  580ccf69 ! 1:  5b876d74 lib/, src/, tests/: Use countof() or sizeof_a() where appropriate
    @@ lib/shadow/passwd/sgetpwent.c
     
      ## lib/subordinateio.c ##
     @@
    - #include "alloc/malloc.h"
    - #include "alloc/reallocf.h"
      #include "atoi/a2i.h"
    + #include "atoi/getnum.h"
    + #include "shadow/passwd/getpw.h"
     +#include "sizeof.h"
      #include "string/ctype/strisascii/strisdigit.h"
      #include "string/sprintf/snprintf.h"
2:  3805154d = 2:  47998f8e lib/salt.c: crypt_make_salt(): Use countof() instead of a hardcoded value
3:  aa6a3dcd = 3:  7403f8a7 lib/sizeof.h: endof(): Add macro
4:  d29e1cac = 4:  ddc4c557 lib/fields.[ch]: change_field_a(): Add macro
5:  524beee5 = 5:  2d445619 src/: Use change_field_a() instead of its pattern
6:  2d4f61d4 = 6:  d41e8f8b lib/string/memset/: bzero_a(): Add macro
7:  68da424c = 7:  f7fcf073 lib/: Use bzero_a() instead of its pattern
8:  8ae2c113 = 8:  d401c9c7 lib/audit_help.c: Use countof() instead of sizeof()
v2c
  • Rebase
$ git rd 
1:  5b876d74 ! 1:  a55ef44c lib/, src/, tests/: Use countof() or sizeof_a() where appropriate
    @@ lib/env.c
      #include "shadowlog.h"
     +#include "sizeof.h"
      #include "string/sprintf/aprintf.h"
    - #include "string/sprintf/snprintf.h"
    - #include "string/sprintf/aprintf.h"
    + #include "string/sprintf/stprintf.h"
    + #include "string/strcmp/strprefix.h"
     @@ lib/env.c: void set_env (int argc, char *const *argv)
        char  *cp;
      
    @@ lib/pwauth.c
     -#include "getdef.h"
     +#include "sizeof.h"
      #include "string/memset/memzero.h"
    - #include "string/sprintf/snprintf.h"
    + #include "string/sprintf/stprintf.h"
      #include "string/strcmp/streq.h"
     @@ lib/pwauth.c: pw_auth(const char *cipher, const char *user)
         * Some BSD updates to the S/KEY API adds a fourth parameter; the
    @@ lib/subordinateio.c
      #include "shadow/passwd/getpw.h"
     +#include "sizeof.h"
      #include "string/ctype/strisascii/strisdigit.h"
    - #include "string/sprintf/snprintf.h"
    + #include "string/sprintf/stprintf.h"
      #include "string/strcmp/streq.h"
     @@ lib/subordinateio.c: subordinate_parse(const char *line)
         * Copy the string to a temporary buffer so the substrings can
    @@ src/chage.c
      #include "shadowlog.h"
     +#include "sizeof.h"
      #include "string/memset/memzero.h"
    - #include "string/sprintf/snprintf.h"
    + #include "string/sprintf/stprintf.h"
      #include "string/strcmp/streq.h"
     @@ src/chage.c: static int new_fields (void)
        (void) puts ("");
    @@ src/login.c
      #include "shadowlog.h"
     +#include "sizeof.h"
      #include "string/memset/memzero.h"
    - #include "string/sprintf/snprintf.h"
    + #include "string/sprintf/stprintf.h"
      #include "string/strcmp/streq.h"
     @@ src/login.c: int main (int argc, char **argv)
                unsigned int  failcount = 0;
2:  47998f8e = 2:  8dcccac7 lib/salt.c: crypt_make_salt(): Use countof() instead of a hardcoded value
3:  7403f8a7 = 3:  59b70f98 lib/sizeof.h: endof(): Add macro
4:  ddc4c557 = 4:  e5e22386 lib/fields.[ch]: change_field_a(): Add macro
5:  2d445619 = 5:  cde6ecb1 src/: Use change_field_a() instead of its pattern
6:  d41e8f8b = 6:  e592ba7e lib/string/memset/: bzero_a(): Add macro
7:  f7fcf073 ! 7:  11f603e9 lib/: Use bzero_a() instead of its pattern
    @@ lib/idmapping.c
      #include "shadowlog.h"
      #include "sizeof.h"
     +#include "string/memset/bzero.h"
    - #include "string/sprintf/stpeprintf.h"
    + #include "string/sprintf/seprintf.h"
      #include "string/strcmp/streq.h"
      #include "string/strerrno.h"
     @@ lib/idmapping.c: void write_mapping(int proc_dir_fd, int ranges, const struct map_range *mappings
    @@ lib/salt.c
      #include "prototypes.h"
      #include "shadowlog.h"
     +#include "string/memset/bzero.h"
    + #include "string/sprintf/stprintf.h"
      #include "string/strcmp/streq.h"
      
    - #undef NDEBUG
     @@ lib/salt.c: static /*@observer@*/const char *gensalt (size_t salt_size)
      {
        static char salt[MAX_SALT_SIZE + 6];
8:  d401c9c7 ! 8:  53e44dca lib/audit_help.c: Use countof() instead of sizeof()
    @@ lib/audit_help.c
      #include "prototypes.h"
      #include "shadowlog.h"
     +#include "sizeof.h"
    - #include "string/sprintf/snprintf.h"
    + #include "string/sprintf/stprintf.h"
      
     +
      int audit_fd;

sizeof() is dangerous with arrays.  We usually want to know the length
of the array, with countof(), and in very few cases, we want to know the
size (in bytes) of the array, with sizeof_a().  Use sizeof() only
with variables that are not arrays.

Signed-off-by: Alejandro Colomar <[email protected]>
endof() returns a pointer to the end of an array, that is,
one after the last element.  It's similar to C++11's std::end().

Signed-off-by: Alejandro Colomar <[email protected]>
It calculates the length of the array internally.
Rename the variable that stores the length.

Signed-off-by: Alejandro Colomar <[email protected]>
This is a bzero() wrapper for arrays.

Signed-off-by: Alejandro Colomar <[email protected]>
This is a count of the number of elements.  sizeof() works because
sizeof(char)==1, but it's more dangerous, as it blindly accepts other
types.

Signed-off-by: Alejandro Colomar <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant