From 6febe75da76517a69f073fb50abffc5c2c7d58cd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 13 Dec 2017 08:17:07 +0100 Subject: [PATCH 1/2] basic/macros: add STRLEN() to get length of string literal as constant expression While the compiler likely optimizes strlen(x) for string literals, it is not a constant expression. Hence, char buffer[strlen("OPTION_000") + 1]; declares a variable-length array. STRLEN() can be used instead when a constant espression is needed. It's not entirely identical to strlen(), as STRLEN("a\0") counts 2. Also, it only works with string literals and the macro enforces that the argument is a literal. --- src/basic/macro.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/basic/macro.h b/src/basic/macro.h index 78679083e8..02d22de833 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -144,6 +144,14 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ sizeof(x)/sizeof((x)[0]), \ (void)0)) + +/* + * STRLEN - return the length of a string literal, minus the trailing NUL byte. + * Contrary to strlen(), this is a constant expression. + * @x: a string literal. + */ +#define STRLEN(x) (sizeof(""x"") - 1) + /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. From dbcb4a900ef7e9673604caabc1e1842309b7fd73 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 13 Dec 2017 08:41:11 +0100 Subject: [PATCH 2/2] tree-wide: use STRLEN() to allocate buffer of constant size Using strlen() to declare a buffer results in a variable-length array, even if the compiler likely optimizes it to be a compile time constant. When building with -Wvla, certain versions of gcc complain about such buffers. Compiling with -Wvla has the advantage of preventing variably length array, which defeat static asserts that are implemented by declaring an array of negative length. --- src/basic/fd-util.c | 2 +- src/libsystemd-network/sd-dhcp-lease.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index f3863722ee..a0820a9667 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -368,7 +368,7 @@ bool fdname_is_valid(const char *s) { } int fd_get_path(int fd, char **ret) { - char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; int r; xsprintf(procfs_path, "/proc/self/fd/%i", fd); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 7063bd986e..a186bca38f 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -987,7 +987,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { } LIST_FOREACH(options, option, lease->private_options) { - char key[strlen("OPTION_000")+1]; + char key[STRLEN("OPTION_000")+1]; xsprintf(key, "OPTION_%" PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length);