]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
enum: Add compile-time check for missing strings
authorTobias Brunner <tobias@strongswan.org>
Wed, 16 Oct 2019 16:48:22 +0000 (18:48 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 28 Oct 2019 13:26:32 +0000 (14:26 +0100)
If strings are missing (e.g. because the last value of a range changed
unknowingly or adding a string was simply forgotten) compilation will
now fail.

This could be problematic if the upper limit is out of our control (e.g.
from a system header like pfkeyv2.h), in which case patches might be
required on certain platforms (enforcing at least, and not exactly, the
required number of strings might also be an option to compile against
older versions of such a header - for internal enums it's obviously
better to enforce an exact match, though).

src/libstrongswan/tests/suites/test_enum.c
src/libstrongswan/utils/enum.h

index dd6b86f8e2794044260dd99796ea6cc1ac39fccc..06b2c3ff3c8c9aabd49f0f71b8c9dc76087109fd 100644 (file)
@@ -28,9 +28,6 @@ enum {
        CONT5,
 } test_enum_cont;
 
-/* can't be static */
-enum_name_t *test_enum_cont_names;
-
 ENUM_BEGIN(test_enum_cont_names, CONT1, CONT5,
        "CONT1", "CONT2", "CONT3", "CONT4", "CONT5");
 ENUM_END(test_enum_cont_names, CONT5);
@@ -46,9 +43,6 @@ enum {
        SPLIT5 = 255,
 } test_enum_split;
 
-/* can't be static */
-enum_name_t *test_enum_split_names;
-
 ENUM_BEGIN(test_enum_split_names, SPLIT1, SPLIT2,
        "SPLIT1", "SPLIT2");
 ENUM_NEXT(test_enum_split_names, SPLIT3, SPLIT4, SPLIT2,
index 4312cb9a1d5f1fd9717db7ecb973fb470dfa2983..888dbe54fcd9eb8ca688360c9dd83e4d1de53a56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2019 Tobias Brunner
  * Copyright (C) 2006-2008 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -59,10 +59,11 @@ typedef struct enum_name_t enum_name_t;
  * by the numerical enum value.
  */
 struct enum_name_t {
-       /** value of the first enum string */
-       int first;
+       /** value of the first enum string, values are expected to be (u_)int, using
+        * int64_t here instead, however, avoids warnings for large unsigned ints */
+       int64_t first;
        /** value of the last enum string */
-       int last;
+       int64_t last;
        /** next enum_name_t in list, or ENUM_FLAG_MAGIC */
        enum_name_t *next;
        /** array of strings containing names from first to last */
@@ -77,7 +78,10 @@ struct enum_name_t {
  * @param last enum value of the last enum string
  * @param ...  a list of strings
  */
-#define ENUM_BEGIN(name, first, last, ...) static enum_name_t name##last = {first, last, NULL, { __VA_ARGS__ }}
+#define ENUM_BEGIN(name, first, last, ...) \
+       static enum_name_t name##last = {first, last + \
+               BUILD_ASSERT(((last)-(first)+1) == countof(((char*[]){__VA_ARGS__}))), \
+               NULL, { __VA_ARGS__ }}
 
 /**
  * Continue a enum name list startetd with ENUM_BEGIN.
@@ -88,7 +92,10 @@ struct enum_name_t {
  * @param prev enum value of the "last" defined in ENUM_BEGIN/previous ENUM_NEXT
  * @param ...  a list of strings
  */
-#define ENUM_NEXT(name, first, last, prev, ...) static enum_name_t name##last = {first, last, &name##prev, { __VA_ARGS__ }}
+#define ENUM_NEXT(name, first, last, prev, ...) \
+       static enum_name_t name##last = {first, last + \
+               BUILD_ASSERT(((last)-(first)+1) == countof(((char*[]){__VA_ARGS__}))), \
+               &name##prev, { __VA_ARGS__ }}
 
 /**
  * Complete enum name list started with ENUM_BEGIN.
@@ -109,7 +116,8 @@ struct enum_name_t {
  * @param last enum value of the last enum string
  * @param ...  a list of strings
  */
-#define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last)
+#define ENUM(name, first, last, ...) \
+       ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last)
 
 /**
  * Define a enum name with only one range for flags.
@@ -125,8 +133,10 @@ struct enum_name_t {
  * @param ...  a list of strings
  */
 #define ENUM_FLAGS(name, first, last, ...) \
-       static enum_name_t name##last = {first, last, ENUM_FLAG_MAGIC, { __VA_ARGS__ }}; \
-       ENUM_END(name, last)
+       static enum_name_t name##last = {first, last + \
+               BUILD_ASSERT((__builtin_ffs(last)-__builtin_ffs(first)+1) == \
+                       countof(((char*[]){__VA_ARGS__}))), \
+               ENUM_FLAG_MAGIC, { __VA_ARGS__ }}; ENUM_END(name, last)
 
 /**
  * Convert a enum value to its string representation.