diff options
author | Benjamin Barenblat <bbaren@google.com> | 2020-05-13 13:48:32 -0400 |
---|---|---|
committer | Benjamin Barenblat <bbaren@google.com> | 2020-05-13 13:48:32 -0400 |
commit | afbf22d62076868d6db30411ad1924d99fbdb05d (patch) | |
tree | 09c226042542225302b95cd4fa9f4b72785539cf | |
parent | f099f30489f958c4466b83ecb0427f28b9c11e9d (diff) |
Don’t pass `char` to `va_start`cleanup
Passing `va_start` an argument of a type that undergoes promotion
(`char`, `float`, etc.) triggers undefined behavior. Make `_cat_with`
take an `int c` instead, and assert that `c` can be stored in a `char`
before using it as one.
-rw-r--r-- | brightnessctl.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/brightnessctl.c b/brightnessctl.c index 31a066d..922a3c4 100644 --- a/brightnessctl.c +++ b/brightnessctl.c @@ -1,3 +1,4 @@ +#include <assert.h> #include <sys/types.h> #include <sys/utsname.h> #include <sys/stat.h> @@ -31,7 +32,7 @@ enum operation; static void fail(char *, ...); static void usage(void); #define cat_with(...) _cat_with(__VA_ARGS__, NULL) -static char *_cat_with(char, ...); +static char *_cat_with(int, ...); static char *dir_child(char *, char*); static char *device_path(struct device *); static char *class_path(char *); @@ -601,12 +602,16 @@ bool ensure_dev_dir(struct device *dev) { return ret; } -char *_cat_with(char c, ...) { +char *_cat_with(int c, ...) { + // We'd like c to be a char, but passing a char to va_start triggers + // undefined behavior. Take it as an int instead, and assert that it can + // fit in a char before using it as one. + assert(c >= CHAR_MIN && c <= CHAR_MAX); size_t size = 32; size_t length = 0; char *buf = calloc(1, size + 1); char *curr; - char split[2] = {c, '\0'}; + char split[2] = {(char) c, '\0'}; va_list va; va_start(va, c); curr = va_arg(va, char *); |