Page MenuHome GnuPG

ctype(3) API use
Open, Needs TriagePublic

Description

While testing recent gnupg fixes on NetBSD, I looked at the build output a lot and noticed that there are many warnings about the use of the ctype(3) API.

The standards are clear that only 'unsigned char' arguments and EOF are allowed (see e.g. https://pubs.opengroup.org/onlinepubs/9699919799/functions/isalnum_l.html: "The c argument is an int, the value of which the application shall ensure is representable as an unsigned char or equal to the value of the macro EOF. If the argument has any other value, the behavior is undefined."), but NetBSD is especially picky about this. More details are in the NetBSD man page:
https://man.netbsd.org/ctype.3

gnupg has multiple places where it passes 'char' values instead. In NetBSD 11, negative char values (undefined behaviour) will cause programs to dump core. I haven't seen any with gnupg yet, but I have seen them with Unicode arguments like "ü" in other programs before.

Here are the warnings from gnupg git HEAD as of today (c86374ea7756984b3673a4c34cb12a808411e5a4):

In file included from /usr/include/ctype.h:100,
                 from ../../common/gettime.c:33:
../../common/gettime.c: In function 'isotime_p':
../../common/gettime.c:380:42: warning: array subscript has type 'char' [-Wchar-subscripts]
  380 |   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
      |                                          ^
In file included from /usr/include/ctype.h:100,
                 from ../../common/stringhelp.c:39:
../../common/stringhelp.c: In function 'strlwr':
../../common/stringhelp.c:1072:22: warning: array subscript has type 'char' [-Wchar-subscripts]
 1072 |         *p = tolower(*p);
      |                      ^
In file included from /usr/include/ctype.h:100,
                 from ../../common/stringhelp.c:39:
../../common/stringhelp.c: In function 'strlwr':
../../common/stringhelp.c:1072:22: warning: array subscript has type 'char' [-Wchar-subscripts]
 1072 |         *p = tolower(*p);
      |                      ^

In file included from /usr/include/ctype.h:100,
                 from ../../common/convert.c:33:
../../common/convert.c: In function 'hex2bin':
../../common/convert.c:61:41: warning: array subscript has type 'char' [-Wchar-subscripts]
   61 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^
../../common/convert.c: In function 'hexcolon2bin':
../../common/convert.c:104:41: warning: array subscript has type 'char' [-Wchar-subscripts]
  104 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^
../../common/convert.c: In function 'hex2str':
../../common/convert.c:211:41: warning: array subscript has type 'char' [-Wchar-subscripts]
  211 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^

In file included from /usr/include/ctype.h:100,
                 from ../../common/convert.c:33:
../../common/convert.c: In function 'hex2bin':
../../common/convert.c:61:41: warning: array subscript has type 'char' [-Wchar-subscripts]
   61 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^
../../common/convert.c: In function 'hexcolon2bin':
../../common/convert.c:104:41: warning: array subscript has type 'char' [-Wchar-subscripts]
  104 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^
../../common/convert.c: In function 'hex2str':
../../common/convert.c:211:41: warning: array subscript has type 'char' [-Wchar-subscripts]
  211 |   if (*s && (!isascii (*s) || !isspace (*s)) )
      |                                         ^

In file included from /usr/include/ctype.h:100,
                 from ../../common/gettime.c:33:
../../common/gettime.c: In function 'isotime_p':
../../common/gettime.c:380:42: warning: array subscript has type 'char' [-Wchar-subscripts]
  380 |   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
      |                                          ^

In file included from /usr/include/ctype.h:100,
                 from ../../g10/build-packet.c:25:
../../g10/build-packet.c: In function 'string_to_notation':
../../g10/build-packet.c:1623:45: warning: array subscript has type 'char' [-Wchar-subscripts]
 1623 |       if( !*s || !isascii (*s) || (!isgraph(*s) && !isspace(*s)) )
      |                                             ^
../../g10/build-packet.c:1623:61: warning: array subscript has type 'char' [-Wchar-subscripts]
 1623 |       if( !*s || !isascii (*s) || (!isgraph(*s) && !isspace(*s)) )
      |                                                             ^
../../g10/build-packet.c:1659:28: warning: array subscript has type 'char' [-Wchar-subscripts]
 1659 |           else if (iscntrl(*s))
      |                            ^
../../g10/build-packet.c: In function 'blob_to_notation':
../../g10/build-packet.c:1737:38: warning: array subscript has type 'char' [-Wchar-subscripts]
 1737 |       if (!isascii (*s) || (!isgraph(*s) && !isspace(*s)))
      |                                      ^
../../g10/build-packet.c:1737:54: warning: array subscript has type 'char' [-Wchar-subscripts]
 1737 |       if (!isascii (*s) || (!isgraph(*s) && !isspace(*s)))
      |                                                      ^
In file included from /usr/include/ctype.h:100,
                 from ../../g10/gpg.c:28:
../../g10/gpg.c: In function 'main':
../../g10/gpg.c:3374:51: warning: array subscript has type 'char' [-Wchar-subscripts]
 3374 |                   if (!isascii (*pt) || !isdigit (*pt))
      |                                                   ^

../../g10/gpg.c: In function 'add_policy_url':
../../g10/gpg.c:5949:47: warning: array subscript has type 'char' [-Wchar-subscripts]
 5949 |     if( !isascii (string[i]) || iscntrl(string[i]))
      |                                               ^
../../g10/gpg.c: In function 'add_keyserver_url':
../../g10/gpg.c:5982:47: warning: array subscript has type 'char' [-Wchar-subscripts]
 5982 |     if( !isascii (string[i]) || iscntrl(string[i]))
      |                                               ^

In file included from /usr/include/ctype.h:100,
                 from ../../g10/keyedit.c:27:
../../g10/keyedit.c: In function 'menu_select_key':
../../g10/keyedit.c:6421:30: warning: array subscript has type 'char' [-Wchar-subscripts]
 6421 |             p[j] = toupper (p[i]);
      |                              ^

In file included from /usr/include/ctype.h:100,
                 from ../../sm/t-minip12.c:27:
../../sm/t-minip12.c: In function 'read_textline':
../../sm/t-minip12.c:276:56: warning: array subscript has type 'char' [-Wchar-subscripts]
  276 |       for (p--;p > line && my_isascii (*p) && isspace (*p); p--)
      |                                                        ^
../../sm/t-minip12.c: In function 'copy_data':
../../sm/t-minip12.c:300:41: warning: array subscript has type 'char' [-Wchar-subscripts]
  300 |   for (s++; my_isascii (*s) && isspace (*s); s++)
      |                                         ^
../../sm/t-minip12.c: In function 'hexdowncase':
../../sm/t-minip12.c:314:23: warning: array subscript has type 'char' [-Wchar-subscripts]
  314 |         *p = tolower (*p);
      |                       ^
In file included from /usr/include/ctype.h:100,
                 from ../../sm/call-dirmngr.c:28:
../../sm/call-dirmngr.c: In function 'gpgsm_dirmngr_run_command':
../../sm/call-dirmngr.c:1174:30: warning: array subscript has type 'char' [-Wchar-subscripts]
 1174 |           else if (!isprint (*s) || *s == '+')
      |                              ^

In file included from /usr/include/ctype.h:100,
                 from ../../agent/genkey.c:26:
../../agent/genkey.c: In function 'nonalpha_count':
../../agent/genkey.c:146:36: warning: array subscript has type 'char' [-Wchar-subscripts]
  146 |     if (isascii (*s) && ( isdigit (*s) || ispunct (*s) ))
      |                                    ^
../../agent/genkey.c:146:52: warning: array subscript has type 'char' [-Wchar-subscripts]
  146 |     if (isascii (*s) && ( isdigit (*s) || ispunct (*s) ))
      |                                                    ^

../../dirmngr/ks-action.c: In function 'ks_action_del':
../../dirmngr/ks-action.c:600:23: warning: unused parameter 'ctrl' [-Wunused-parameter]
  600 | ks_action_del (ctrl_t ctrl, uri_item_t keyservers, strlist_t fprlist)
      |                ~~~~~~~^~~~
../../dirmngr/ks-action.c:600:62: warning: unused parameter 'fprlist' [-Wunused-parameter]
  600 | ks_action_del (ctrl_t ctrl, uri_item_t keyservers, strlist_t fprlist)
      |                                                    ~~~~~~~~~~^~~~~~~

../../dirmngr/dns.c: In function 'dns_so_check':
../../dirmngr/dns.c: In function 'dns_so_check':
../../dirmngr/dns.c:7750:9: warning: label 'udp_connect_retry' defined but not used [-Wunused-label]
 7750 |         udp_connect_retry:
      |         ^~~~~~~~~~~~~~~~~
../../dirmngr/dns.c:7750:9: warning: label 'udp_connect_retry' defined but not used [-Wunused-label]
 7750 |         udp_connect_retry:
      |         ^~~~~~~~~~~~~~~~~
../../dirmngr/dns.c: In function 'dns_so_check':
../../dirmngr/dns.c:7750:9: warning: label 'udp_connect_retry' defined but not used [-Wunused-label]
 7750 |         udp_connect_retry:
      |         ^~~~~~~~~~~~~~~~~
../../dirmngr/dns.c: In function 'dns_so_check':
../../dirmngr/dns.c:7750:9: warning: label 'udp_connect_retry' defined but not used [-Wunused-label]
 7750 |         udp_connect_retry:
      |         ^~~~~~~~~~~~~~~~~

In file included from /usr/include/ctype.h:100,
                 from ../../tools/gpg-check-pattern.c:41:
../../tools/gpg-check-pattern.c: In function 'parse_pattern_file':
../../tools/gpg-check-pattern.c:358:39: warning: array subscript has type 'char' [-Wchar-subscripts]
  358 |       while (isascii (*p) && isspace (*p))
      |                                       ^
../../tools/gpg-check-pattern.c:362:50: warning: array subscript has type 'char' [-Wchar-subscripts]
  362 |       while (p2 > p && isascii (*p2) && isspace (*p2))
      |                                                  ^
../../tools/gpg-check-pattern.c: In function 'process':
../../tools/gpg-check-pattern.c:576:71: warning: array subscript has type 'char' [-Wchar-subscripts]
  576 |               while (idx && isascii (buffer[idx-1]) && isspace (buffer[idx-1]))
      |                                                                       ^

In file included from /usr/include/ctype.h:100,
                 from ../../tools/gpgtar.c:32:
../../tools/gpgtar.c: In function 'shell_parse_stringlist':
../../tools/gpgtar.c:267:24: warning: array subscript has type 'char' [-Wchar-subscripts]
  267 |           if (isspace (*s))
      |                        ^

In file included from /usr/include/ctype.h:100,
                 from ../../tools/gpgconf-comp.c:38:
../../tools/gpgconf-comp.c: In function 'all_digits_p':
../../tools/gpgconf-comp.c:1243:36: warning: array subscript has type 'char' [-Wchar-subscripts]
 1243 |     if (!isascii (*p) || !isdigit (*p))
      |                                    ^
../../tools/gpgconf-comp.c: In function 'collect_error_output':
../../tools/gpgconf-comp.c:1300:39: warning: array subscript has type 'char' [-Wchar-subscripts]
 1300 |                   for (p2++; isdigit (*p2); p2++)
      |                                       ^

In file included from /usr/include/ctype.h:100,
                 from ../../../tests/gpgscm/scheme.c:38:
../../../tests/gpgscm/scheme.c: In function 'strlwr':
../../../tests/gpgscm/scheme.c:109:16: warning: array subscript has type 'char' [-Wchar-subscripts]
  109 |     *s=tolower(*s);
      |                ^
../../../tests/gpgscm/scheme.c: In function 'mk_atom':
../../../tests/gpgscm/scheme.c:1566:69: warning: array subscript has type 'char' [-Wchar-subscripts]
 1566 |                           if ((*p == '-') || (*p == '+') || isdigit(*p)) {
      |                                                                     ^
In file included from /usr/include/ctype.h:100,
                 from ../../../tests/gpgscm/ffi.c:24:
../../../tests/gpgscm/ffi.c: In function 'rl_gets':
../../../tests/gpgscm/ffi.c:171:49: warning: array subscript has type 'char' [-Wchar-subscripts]
  171 |     for (p = &line[strlen (line) - 1]; isspace (*p); p--)
      |                                                 ^


../../../tests/gpgscm/ffi.c: In function 'ffi_schemify_name':
../../../tests/gpgscm/ffi.c:1575:28: warning: array subscript has type 'char' [-Wchar-subscripts]
 1575 |       *p = (char) tolower (*p);
      |                            ^

(I noticed that some lines are duplicated here - this is from a 'make -j10' build, so perhaps this points out some missing dependency rules, I haven't investigated.)

Event Timeline