From: Tobias Brunner Date: Wed, 16 Oct 2019 16:48:22 +0000 (+0200) Subject: enum: Add compile-time check for missing strings X-Git-Tag: 5.8.2dr2~15^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b98482e041a7ee2a5c0327b16fcbec30d8d878b;p=thirdparty%2Fstrongswan.git enum: Add compile-time check for missing strings 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). --- diff --git a/src/libstrongswan/tests/suites/test_enum.c b/src/libstrongswan/tests/suites/test_enum.c index dd6b86f8e2..06b2c3ff3c 100644 --- a/src/libstrongswan/tests/suites/test_enum.c +++ b/src/libstrongswan/tests/suites/test_enum.c @@ -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, diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h index 4312cb9a1d..888dbe54fc 100644 --- a/src/libstrongswan/utils/enum.h +++ b/src/libstrongswan/utils/enum.h @@ -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.