summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-03-14 14:44:54 +0100
committerLennart Poettering <lennart@poettering.net>2022-03-14 18:18:24 +0100
commit56da8d5af37bda6950f058066fa05c5fdcc20f6e (patch)
tree53474755b81812e382ad7f3450f39969aa2088c6
parent845ed472315e5e4ac6960d809ee03ad841fa14ec (diff)
downloadsystemd-56da8d5af37bda6950f058066fa05c5fdcc20f6e.tar.gz
macro: handle DECIMAL_STR_MAX() special cases more accurately
So far DECIMAL_STR_MAX() overestimated the types in two ways: it would also adds space for a "-" for unsigned types. And it would always return the same size for 64bit values regardless of signedness, even though the longest maximum numbers for signed and unsigned differ in length by one digit. i.e. 2^64-1 (i.e. UINT64_MAX) is one decimal digit longer than -2^63 (INT64_MIN) - for the other integer widths the number of digits in the "longest" decimal value is always the same, regardless of signedness. by example: strlen("65535") == strlen("32768") (i.e. the relevant 16 bit limits) holds — and similar for 8bit and 32bit integer width limits — but strlen("18446744073709551615") > strlen("9223372036854775808") (i.e. the relevant 64 bit limits). Let's fix both misestimations.
-rw-r--r--src/basic/macro.h11
-rw-r--r--src/test/test-format-util.c10
2 files changed, 11 insertions, 10 deletions
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 214654386c..fb1ae65d28 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -309,15 +309,14 @@ static inline int __coverity_check_and_return__(int condition) {
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
-/* Returns the number of chars needed to format variables of the
- * specified type as a decimal string. Adds in extra space for a
- * negative '-' prefix (hence works correctly on signed
- * types). Includes space for the trailing NUL. */
+/* Returns the number of chars needed to format variables of the specified type as a decimal string. Adds in
+ * extra space for a negative '-' prefix for signed types. Includes space for the trailing NUL. */
#define DECIMAL_STR_MAX(type) \
- (2U+(sizeof(type) <= 1 ? 3U : \
+ ((size_t) IS_SIGNED_INTEGER_TYPE(type) + 1U + \
+ (sizeof(type) <= 1 ? 3U : \
sizeof(type) <= 2 ? 5U : \
sizeof(type) <= 4 ? 10U : \
- sizeof(type) <= 8 ? 20U : sizeof(int[-2*(sizeof(type) > 8)])))
+ sizeof(type) <= 8 ? (IS_SIGNED_INTEGER_TYPE(type) ? 19U : 20U) : sizeof(int[-2*(sizeof(type) > 8)])))
/* Returns the number of chars needed to format the specified integer value. It's hence more specific than
* DECIMAL_STR_MAX() which answers the same question for all possible values of the specified type. Does
diff --git a/src/test/test-format-util.c b/src/test/test-format-util.c
index 3e640a84b3..ee74d1c898 100644
--- a/src/test/test-format-util.c
+++ b/src/test/test-format-util.c
@@ -10,10 +10,12 @@ assert_cc(STRLEN("xxx") == 3);
assert_cc(STRLEN("") == 0);
assert_cc(STRLEN(L"xxx") == 3 * sizeof(wchar_t));
assert_cc(STRLEN(L"") == 0);
-assert_cc(DECIMAL_STR_MAX(uint8_t) == 5);
-assert_cc(DECIMAL_STR_MAX(int8_t) == 5);
-assert_cc(DECIMAL_STR_MAX(uint64_t) == 22);
-assert_cc(DECIMAL_STR_MAX(char) == 5);
+assert_cc(DECIMAL_STR_MAX(uint8_t) == STRLEN("255")+1);
+assert_cc(DECIMAL_STR_MAX(int8_t) == STRLEN("-127")+1);
+assert_cc(DECIMAL_STR_MAX(uint64_t) == STRLEN("18446744073709551615")+1);
+assert_cc(DECIMAL_STR_MAX(int64_t) == CONST_MAX(STRLEN("-9223372036854775808"), STRLEN("9223372036854775807"))+1);
+assert_cc(DECIMAL_STR_MAX(signed char) == STRLEN("-127")+1);
+assert_cc(DECIMAL_STR_MAX(unsigned char) == STRLEN("255")+1);
assert_cc(CONST_MAX(DECIMAL_STR_MAX(int8_t), STRLEN("xxx")) == 5);
static void test_format_bytes_one(uint64_t val, bool trailing_B, const char *iec_with_p, const char *iec_without_p,