Skip to content

Commit

Permalink
common/include: Add ASCII-only ctype header and ascii_is* functions.
Browse files Browse the repository at this point in the history
Our existing uses of <ctype.h> were not necessarily safe if the locale
was changed.

Also I removed the unnecessary use of isascii, deprecated by POSIX.1-2008.
  • Loading branch information
rwmjones committed May 19, 2020
1 parent 737651d commit 9f34db7
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -33,6 +33,7 @@ plugins/*/*.3
/aclocal.m4
/autom4te.cache
/common/bitmap/test-bitmap
/common/include/test-ascii-ctype
/common/include/test-byte-swapping
/common/include/test-current-dir-name
/common/include/test-isaligned
Expand Down
6 changes: 6 additions & 0 deletions common/include/Makefile.am
Expand Up @@ -34,6 +34,7 @@ include $(top_srcdir)/common-rules.mk
# These headers contain only common code shared by the core server,
# plugins and/or filters. They are not installed.
EXTRA_DIST = \
ascii-ctype.h \
byte-swapping.h \
exit-with-parent.h \
get-current-dir-name.h \
Expand All @@ -50,6 +51,7 @@ EXTRA_DIST = \
# Unit tests.

TESTS = \
test-ascii-ctype \
test-byte-swapping \
test-current-dir-name \
test-isaligned \
Expand All @@ -62,6 +64,10 @@ TESTS = \
$(NULL)
check_PROGRAMS = $(TESTS)

test_ascii_ctype_SOURCES = test-ascii-ctype.c ascii-ctype.h
test_ascii_ctype_CPPFLAGS = -I$(srcdir)
test_ascii_ctype_CFLAGS = $(WARNINGS_CFLAGS)

test_byte_swapping_SOURCES = test-byte-swapping.c byte-swapping.h
test_byte_swapping_CPPFLAGS = -I$(srcdir)
test_byte_swapping_CFLAGS = $(WARNINGS_CFLAGS)
Expand Down
60 changes: 60 additions & 0 deletions common/include/ascii-ctype.h
@@ -0,0 +1,60 @@
/* nbdkit
* Copyright (C) 2013-2020 Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Red Hat nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

/* Normal ctype functions are affected by the current locale. For
* example isupper() might recognize Ä in some but not all locales.
* These functions match only 7 bit ASCII characters.
*/

#ifndef NBDKIT_ASCII_CTYPE_H
#define NBDKIT_ASCII_CTYPE_H

#define ascii_isalnum(c) (ascii_isalpha (c) || ascii_isdigit (c))

#define ascii_isalpha(c) \
(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))

#define ascii_isdigit(c) \
((c) >= '0' && (c) <= '9')

#define ascii_isspace(c) \
((c) == '\t' || (c) == '\n' || (c) == '\f' || (c) == '\r' || (c) == ' ')

#define ascii_isxdigit(c) \
((c) == '0' || (c) == '1' || (c) == '2' || (c) == '3' || (c) == '4' || \
(c) == '5' || (c) == '6' || (c) == '7' || (c) == '8' || (c) == '9' || \
(c) == 'a' || (c) == 'b' || (c) == 'c' || \
(c) == 'd' || (c) == 'e' || (c) == 'f' || \
(c) == 'A' || (c) == 'B' || (c) == 'C' || \
(c) == 'D' || (c) == 'E' || (c) == 'F')

#endif /* NBDKIT_ASCII_CTYPE_H */
63 changes: 63 additions & 0 deletions common/include/test-ascii-ctype.c
@@ -0,0 +1,63 @@
/* nbdkit
* Copyright (C) 2020 Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Red Hat nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "ascii-ctype.h"

int
main (void)
{
assert (ascii_isspace (' '));
assert (ascii_isspace ('\t'));
assert (ascii_isspace ('\n'));
assert (! ascii_isspace ('a'));

assert (ascii_isalpha ('a'));
assert (ascii_isalpha ('Z'));
assert (ascii_isalpha ('z'));
assert (! ascii_isalpha (' '));
assert (! ascii_isalpha ('0'));
{ const char *s = "Ä"; assert (! ascii_isalpha (s[0])); }
{ const char *s = "®"; assert (! ascii_isalpha (s[0])); }

assert (ascii_isdigit ('0'));
assert (ascii_isdigit ('9'));
{ const char *s = "Ø"; assert (! ascii_isdigit (s[0])); } /* U+00D8 */
{ const char *s = "9"; assert (! ascii_isdigit (s[0])); } /* U+FF19 */

exit (EXIT_SUCCESS);
}
12 changes: 6 additions & 6 deletions plugins/partitioning/partition-gpt.c
Expand Up @@ -36,12 +36,12 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include <assert.h>

#include <nbdkit-plugin.h>

#include "ascii-ctype.h"
#include "byte-swapping.h"

#include "efi-crc32.h"
Expand Down Expand Up @@ -244,19 +244,19 @@ parse_guid (const char *str, char *out)
return -1;

for (i = 0; i < 8; ++i)
if (!isxdigit (str[i]))
if (!ascii_isxdigit (str[i]))
return -1;
for (i = 9; i < 13; ++i)
if (!isxdigit (str[i]))
if (!ascii_isxdigit (str[i]))
return -1;
for (i = 14; i < 18; ++i)
if (!isxdigit (str[i]))
if (!ascii_isxdigit (str[i]))
return -1;
for (i = 19; i < 23; ++i)
if (!isxdigit (str[i]))
if (!ascii_isxdigit (str[i]))
return -1;
for (i = 24; i < 36; ++i)
if (!isxdigit (str[i]))
if (!ascii_isxdigit (str[i]))
return -1;

/* The first, second and third blocks are parsed as little endian,
Expand Down
1 change: 1 addition & 0 deletions plugins/sh/Makefile.am
Expand Up @@ -50,6 +50,7 @@ nbdkit_sh_plugin_la_SOURCES = \

nbdkit_sh_plugin_la_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/common/include \
-I$(top_srcdir)/common/utils \
$(NULL)
nbdkit_sh_plugin_la_CFLAGS = $(WARNINGS_CFLAGS)
Expand Down
6 changes: 3 additions & 3 deletions plugins/sh/call.c
Expand Up @@ -44,10 +44,10 @@
#include <poll.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>

#include <nbdkit-plugin.h>

#include "ascii-ctype.h"
#include "cleanup.h"
#include "utils.h"

Expand Down Expand Up @@ -443,15 +443,15 @@ handle_script_error (const char *argv0, char *ebuf, size_t len)
}

if (skip && ebuf[skip]) {
if (!isspace ((unsigned char) ebuf[skip])) {
if (!ascii_isspace ((unsigned char) ebuf[skip])) {
/* Treat 'EINVALID' as EIO, not EINVAL */
err = EIO;
skip = 0;
}
else
do
skip++;
while (isspace ((unsigned char) ebuf[skip]));
while (ascii_isspace ((unsigned char) ebuf[skip]));
}

while (len > 0 && ebuf[len-1] == '\n')
Expand Down
7 changes: 4 additions & 3 deletions server/backend.c
Expand Up @@ -37,13 +37,14 @@
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#include <dlfcn.h>

#include "internal.h"
#include "ascii-ctype.h"
#include "minmax.h"

#include "internal.h"

/* Helpers for registering a new backend. */

/* Use:
Expand Down Expand Up @@ -100,7 +101,7 @@ backend_load (struct backend *b, const char *name, void (*load) (void))
for (i = 0; i < len; ++i) {
unsigned char c = name[i];

if (!(isascii (c) && isalnum (c))) {
if (! ascii_isalnum (c)) {
fprintf (stderr,
"%s: %s: %s.name ('%s') field "
"must contain only ASCII alphanumeric characters\n",
Expand Down
4 changes: 2 additions & 2 deletions server/public.c
Expand Up @@ -45,13 +45,13 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <termios.h>
#include <errno.h>
#include <poll.h>
#include <signal.h>
#include <sys/socket.h>

#include "ascii-ctype.h"
#include "get-current-dir-name.h"

#include "internal.h"
Expand Down Expand Up @@ -210,7 +210,7 @@ nbdkit_parse_int64_t (const char *what, const char *str, int64_t *rp)
*/
#define PARSE_ERROR_IF_NEGATIVE \
do { \
while (isspace (*str)) \
while (ascii_isspace (*str)) \
str++; \
if (*str == '-') { \
nbdkit_error ("%s: negative numbers are not allowed", what); \
Expand Down

0 comments on commit 9f34db7

Please sign in to comment.