]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/extract-word: replace enum with unsigned int to avoid undefined behaviour
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 22 Apr 2017 23:04:02 +0000 (19:04 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 26 Apr 2017 01:12:52 +0000 (21:12 -0400)
../src/basic/extract-word.c:255:22: warning: passing an object that undergoes default argument promotion to 'va_start' has undefined behavior [-Wvarargs]
        va_start(ap, flags);
                     ^
../src/basic/extract-word.c:244:77: note: parameter of type 'ExtractFlags' (aka 'enum ExtractFlags') is declared here
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
                                                                            ^
../src/basic/extract-word.c:286:22: warning: passing an object that undergoes default argument promotion to 'va_start' has undefined behavior [-Wvarargs]
        va_start(ap, flags);
                     ^
../src/basic/extract-word.c:244:77: note: parameter of type 'ExtractFlags' (aka 'enum ExtractFlags') is declared here
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
                                                                            ^
2 warnings generated.

I think the relevant part of C99 is 6.7.2.2 Enumeration specifiers:

Each enumerated type shall be compatible with char, a signed integer type, or
an unsigned integer type. The choice of type is implementation-defined, but
shall be capable of representing the values of all the members of the
enumeration.

and 7.16.1.4:

The parameter parmN is the identifier of the rightmost parameter in the
variable parameter list in the function definition (the one just before the
...). If the parameter parmN is declared with the register storage class, with
a function or array type, or with a type that is not compatible with the type
that results after application of the default argument promotions, the behavior
is undefined.

This might cause a real issue if the compiler chooses something that is not an
integer for ExtractFlags. Rework the code to avoid the warning, but add an
assert_cc in a large-valued ExtractFlags element is ever defined and the type
is bumped to something wider than an int.

src/basic/extract-word.c
src/basic/extract-word.h

index f8cac3e911fddef4630ff78eb731077b508089bd..804f14c44c48ac02525086ceb289d1aa41177a80 100644 (file)
@@ -241,7 +241,12 @@ int extract_first_word_and_warn(
         return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
 }
 
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+/* We pass ExtractFlags as unsigned int (to avoid undefined behaviour when passing
+ * an object that undergoes default argument promotion as an argument to va_start).
+ * Let's make sure that ExtractFlags fits into an unsigned int. */
+assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
+
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
         va_list ap;
         char **l;
         int n = 0, i, c, r;
index 21db5ef33fb550bb3e34644a9f510dcf7958079a..04746c6d085ed3db60902ebaf923a81e1fdde6b5 100644 (file)
@@ -32,4 +32,4 @@ typedef enum ExtractFlags {
 
 int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
 int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;