303 lines
11 KiB
Diff
303 lines
11 KiB
Diff
From 06d47e2efe1387a3873529c52a4c7c680ddeee22 Mon Sep 17 00:00:00 2001
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
Date: Thu, 7 Jul 2022 12:37:10 +0100
|
|
Subject: [PATCH] common/include: Add ARRAY_SIZE macro
|
|
|
|
This macro returns the length (in elements) at compile time of arrays
|
|
declared as:
|
|
|
|
int foo[] = { 1, 2, 3 };
|
|
|
|
ARRAY_SIZE(foo)
|
|
===> 3
|
|
|
|
It also attempts to detect some errors, such as using the macro with a
|
|
pointer instead of an array, with some ideas borrowed (not copied)
|
|
from Linux, QEMU and Stack Overflow questions.
|
|
|
|
Link: https://stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers
|
|
Link: https://listman.redhat.com/archives/libguestfs/2022-July/029412.html
|
|
Thanks: Laszlo Ersek
|
|
(cherry picked from commit 0fa23df5cd5dc97a55857416ea81d5de6d867c18)
|
|
---
|
|
.gitignore | 1 +
|
|
common/include/Makefile.am | 7 +++
|
|
common/include/array-size.h | 41 +++++++++++++
|
|
common/include/compiler-macros.h | 60 +++++++++++++++++++
|
|
common/include/test-array-size.c | 100 +++++++++++++++++++++++++++++++
|
|
5 files changed, 209 insertions(+)
|
|
create mode 100644 common/include/array-size.h
|
|
create mode 100644 common/include/compiler-macros.h
|
|
create mode 100644 common/include/test-array-size.c
|
|
|
|
diff --git a/.gitignore b/.gitignore
|
|
index 10e1f99d..658fd4e6 100644
|
|
--- a/.gitignore
|
|
+++ b/.gitignore
|
|
@@ -35,6 +35,7 @@ plugins/*/*.3
|
|
/aclocal.m4
|
|
/autom4te.cache
|
|
/common/bitmap/test-bitmap
|
|
+/common/include/test-array-size
|
|
/common/include/test-ascii-ctype
|
|
/common/include/test-ascii-string
|
|
/common/include/test-byte-swapping
|
|
diff --git a/common/include/Makefile.am b/common/include/Makefile.am
|
|
index b73dd471..d3cf9408 100644
|
|
--- a/common/include/Makefile.am
|
|
+++ b/common/include/Makefile.am
|
|
@@ -34,10 +34,12 @@ 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 = \
|
|
+ array-size.h \
|
|
ascii-ctype.h \
|
|
ascii-string.h \
|
|
byte-swapping.h \
|
|
checked-overflow.h \
|
|
+ compiler-macros.h \
|
|
exit-with-parent.h \
|
|
hexdigit.h \
|
|
isaligned.h \
|
|
@@ -55,6 +57,7 @@ EXTRA_DIST = \
|
|
# Unit tests.
|
|
|
|
TESTS = \
|
|
+ test-array-size \
|
|
test-ascii-ctype \
|
|
test-ascii-string \
|
|
test-byte-swapping \
|
|
@@ -69,6 +72,10 @@ TESTS = \
|
|
$(NULL)
|
|
check_PROGRAMS = $(TESTS)
|
|
|
|
+test_array_size_SOURCES = test-array-size.c array-size.h
|
|
+test_array_size_CPPFLAGS = -I$(srcdir)
|
|
+test_array_size_CFLAGS = $(WARNINGS_CFLAGS)
|
|
+
|
|
test_ascii_ctype_SOURCES = test-ascii-ctype.c ascii-ctype.h
|
|
test_ascii_ctype_CPPFLAGS = -I$(srcdir)
|
|
test_ascii_ctype_CFLAGS = $(WARNINGS_CFLAGS)
|
|
diff --git a/common/include/array-size.h b/common/include/array-size.h
|
|
new file mode 100644
|
|
index 00000000..b6d33dde
|
|
--- /dev/null
|
|
+++ b/common/include/array-size.h
|
|
@@ -0,0 +1,41 @@
|
|
+/* nbdkit
|
|
+ * Copyright (C) 2013-2022 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.
|
|
+ */
|
|
+
|
|
+#ifndef NBDKIT_ARRAY_SIZE_H
|
|
+#define NBDKIT_ARRAY_SIZE_H
|
|
+
|
|
+#include "compiler-macros.h"
|
|
+
|
|
+#define ARRAY_SIZE(a) \
|
|
+ ((sizeof (a) / sizeof ((a)[0])) + BUILD_BUG_ON_ZERO (!TYPE_IS_ARRAY(a)))
|
|
+
|
|
+#endif /* NBDKIT_ARRAY_SIZE_H */
|
|
diff --git a/common/include/compiler-macros.h b/common/include/compiler-macros.h
|
|
new file mode 100644
|
|
index 00000000..504e0085
|
|
--- /dev/null
|
|
+++ b/common/include/compiler-macros.h
|
|
@@ -0,0 +1,60 @@
|
|
+/* nbdkit
|
|
+ * Copyright (C) 2013-2022 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.
|
|
+ */
|
|
+
|
|
+#ifndef NBDKIT_COMPILER_MACROS_H
|
|
+#define NBDKIT_COMPILER_MACROS_H
|
|
+
|
|
+#ifndef __cplusplus
|
|
+
|
|
+/* This expression fails at compile time if 'expr' is true. It does
|
|
+ * this by constructing a struct which has an impossible
|
|
+ * (negative-sized) array.
|
|
+ *
|
|
+ * If 'expr' is false then we subtract the sizes of the two identical
|
|
+ * structures, returning zero.
|
|
+ */
|
|
+#define BUILD_BUG_ON_ZERO_SIZEOF(expr) \
|
|
+ (sizeof (struct { int _array_size_failed[(expr) ? -1 : 1]; }))
|
|
+#define BUILD_BUG_ON_ZERO(expr) \
|
|
+ (BUILD_BUG_ON_ZERO_SIZEOF(expr) - BUILD_BUG_ON_ZERO_SIZEOF(expr))
|
|
+
|
|
+#define TYPE_IS_ARRAY(a) \
|
|
+ (!__builtin_types_compatible_p (typeof (a), typeof (&(a)[0])))
|
|
+
|
|
+#else /* __cplusplus */
|
|
+
|
|
+#define BUILD_BUG_ON_ZERO(expr) 0
|
|
+#define TYPE_IS_ARRAY(a) 1
|
|
+
|
|
+#endif /* __cplusplus */
|
|
+
|
|
+#endif /* NBDKIT_COMPILER_MACROS_H */
|
|
diff --git a/common/include/test-array-size.c b/common/include/test-array-size.c
|
|
new file mode 100644
|
|
index 00000000..d77ba3c9
|
|
--- /dev/null
|
|
+++ b/common/include/test-array-size.c
|
|
@@ -0,0 +1,100 @@
|
|
+/* nbdkit
|
|
+ * Copyright (C) 2020-2022 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>
|
|
+#undef NDEBUG /* Keep test strong even for nbdkit built without assertions */
|
|
+#include <assert.h>
|
|
+
|
|
+#include "array-size.h"
|
|
+
|
|
+struct st { const char *s; int i; };
|
|
+
|
|
+static const char *s0[] = { };
|
|
+static const char *s1[] = { "a" };
|
|
+static const char *s3[] = { "a", "b", "c" };
|
|
+static const char *s4[4] = { "a", "b", "c", "d" };
|
|
+static int i0[] = { };
|
|
+static int i1[] = { 1 };
|
|
+static int i3[] = { 1, 2, 3 };
|
|
+static int i4[4] = { 1, 2, 3, 4 };
|
|
+static struct st st0[] = { };
|
|
+static struct st st1[] = { { "a", 1 } };
|
|
+static struct st st3[] = { { "a", 1 }, { "b", 2 }, { "c", 3 } };
|
|
+static struct st st4[4] = { { "a", 1 }, { "b", 2 }, { "c", 3 }, { "d", 4 } };
|
|
+static struct st st4_0[4];
|
|
+
|
|
+int
|
|
+main (void)
|
|
+{
|
|
+ assert (ARRAY_SIZE (s0) == 0);
|
|
+ assert (ARRAY_SIZE (s1) == 1);
|
|
+ assert (ARRAY_SIZE (s3) == 3);
|
|
+ assert (ARRAY_SIZE (s4) == 4);
|
|
+ assert (ARRAY_SIZE (i0) == 0);
|
|
+ assert (ARRAY_SIZE (i1) == 1);
|
|
+ assert (ARRAY_SIZE (i3) == 3);
|
|
+ assert (ARRAY_SIZE (i4) == 4);
|
|
+ assert (ARRAY_SIZE (st0) == 0);
|
|
+ assert (ARRAY_SIZE (st1) == 1);
|
|
+ assert (ARRAY_SIZE (st3) == 3);
|
|
+ assert (ARRAY_SIZE (st4) == 4);
|
|
+ assert (ARRAY_SIZE (st4_0) == 4);
|
|
+
|
|
+#ifdef static_assert
|
|
+ static_assert (ARRAY_SIZE (s0) == 0, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (s1) == 1, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (s3) == 3, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (s4) == 4, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (i0) == 0, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (i1) == 1, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (i3) == 3, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (i4) == 4, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (st0) == 0, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (st1) == 1, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (st3) == 3, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (st4) == 4, "ARRAY_SIZE macro does not work");
|
|
+ static_assert (ARRAY_SIZE (st4_0) == 4, "ARRAY_SIZE macro does not work");
|
|
+#endif
|
|
+
|
|
+ /* You can uncomment this to test the negative case. Unfortunately
|
|
+ * it's difficult to automate this test.
|
|
+ */
|
|
+#if 0
|
|
+ int *p = i4;
|
|
+ assert (ARRAY_SIZE (p) == 4);
|
|
+#endif
|
|
+
|
|
+ exit (EXIT_SUCCESS);
|
|
+}
|
|
--
|
|
2.31.1
|
|
|