From 7c5ece0b649ebea23ebb28eb3cafdb28ba49a9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 9 Aug 2023 18:21:13 +0200 Subject: [PATCH] errno-util: allow ERRNO_IS_* to accept types wider than int This is useful if the variable is ssize_t and we don't want to trigger a warning or truncation. With gcc (gcc-13.2.1-1.fc38.x86_64), the resulting systemd binary is identical, so I assume that the compiler is able to completely optimize away the type. (cherry picked from commit fe0feacb9e9641874fde459af4067d9b7e9d7462) Related: RHEL-22443 --- src/basic/errno-util.h | 27 +++++++++++++++------------ src/test/test-errno-util.c | 13 +++++++++++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h index be5c04e285..b10dd755c9 100644 --- a/src/basic/errno-util.h +++ b/src/basic/errno-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include #include #include @@ -86,14 +87,16 @@ static inline int errno_or_else(int fallback) { /* abs(3) says: Trying to take the absolute value of the most negative integer is not defined. */ #define _DEFINE_ABS_WRAPPER(name) \ - static inline bool ERRNO_IS_##name(int r) { \ - if (r == INT_MIN) \ + static inline bool ERRNO_IS_##name(intmax_t r) { \ + if (r == INTMAX_MIN) \ return false; \ - return ERRNO_IS_NEG_##name(-abs(r)); \ + return ERRNO_IS_NEG_##name(-imaxabs(r)); \ } +assert_cc(INT_MAX <= INTMAX_MAX); + /* For send()/recv() or read()/write(). */ -static inline bool ERRNO_IS_NEG_TRANSIENT(int r) { +static inline bool ERRNO_IS_NEG_TRANSIENT(intmax_t r) { return IN_SET(r, -EAGAIN, -EINTR); @@ -107,7 +110,7 @@ _DEFINE_ABS_WRAPPER(TRANSIENT); * * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet, * kernel tells us that with ETIMEDOUT, see tcp(7). */ -static inline bool ERRNO_IS_NEG_DISCONNECT(int r) { +static inline bool ERRNO_IS_NEG_DISCONNECT(intmax_t r) { return IN_SET(r, -ECONNABORTED, -ECONNREFUSED, @@ -129,7 +132,7 @@ _DEFINE_ABS_WRAPPER(DISCONNECT); /* Transient errors we might get on accept() that we should ignore. As per error handling comment in * the accept(2) man page. */ -static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(int r) { +static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(intmax_t r) { return ERRNO_IS_NEG_DISCONNECT(r) || ERRNO_IS_NEG_TRANSIENT(r) || r == -EOPNOTSUPP; @@ -137,7 +140,7 @@ static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(int r) { _DEFINE_ABS_WRAPPER(ACCEPT_AGAIN); /* Resource exhaustion, could be our fault or general system trouble */ -static inline bool ERRNO_IS_NEG_RESOURCE(int r) { +static inline bool ERRNO_IS_NEG_RESOURCE(intmax_t r) { return IN_SET(r, -EMFILE, -ENFILE, @@ -146,7 +149,7 @@ static inline bool ERRNO_IS_NEG_RESOURCE(int r) { _DEFINE_ABS_WRAPPER(RESOURCE); /* Seven different errors for "operation/system call/ioctl/socket feature not supported" */ -static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(int r) { +static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(intmax_t r) { return IN_SET(r, -EOPNOTSUPP, -ENOTTY, @@ -159,7 +162,7 @@ static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(int r) { _DEFINE_ABS_WRAPPER(NOT_SUPPORTED); /* Two different errors for access problems */ -static inline bool ERRNO_IS_NEG_PRIVILEGE(int r) { +static inline bool ERRNO_IS_NEG_PRIVILEGE(intmax_t r) { return IN_SET(r, -EACCES, -EPERM); @@ -167,7 +170,7 @@ static inline bool ERRNO_IS_NEG_PRIVILEGE(int r) { _DEFINE_ABS_WRAPPER(PRIVILEGE); /* Three different errors for "not enough disk space" */ -static inline bool ERRNO_IS_NEG_DISK_SPACE(int r) { +static inline bool ERRNO_IS_NEG_DISK_SPACE(intmax_t r) { return IN_SET(r, -ENOSPC, -EDQUOT, @@ -176,7 +179,7 @@ static inline bool ERRNO_IS_NEG_DISK_SPACE(int r) { _DEFINE_ABS_WRAPPER(DISK_SPACE); /* Three different errors for "this device does not quite exist" */ -static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(int r) { +static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(intmax_t r) { return IN_SET(r, -ENODEV, -ENXIO, @@ -186,7 +189,7 @@ _DEFINE_ABS_WRAPPER(DEVICE_ABSENT); /* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and * where it simply doesn't have the requested xattr the same way */ -static inline bool ERRNO_IS_NEG_XATTR_ABSENT(int r) { +static inline bool ERRNO_IS_NEG_XATTR_ABSENT(intmax_t r) { return r == -ENODATA || ERRNO_IS_NEG_NOT_SUPPORTED(r); } diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c index 507d53df7a..cac0d5402b 100644 --- a/src/test/test-errno-util.c +++ b/src/test/test-errno-util.c @@ -52,6 +52,19 @@ TEST(ERRNO_IS_TRANSIENT) { assert_se(!ERRNO_IS_NEG_TRANSIENT(EINTR)); assert_se( ERRNO_IS_TRANSIENT(-EINTR)); assert_se( ERRNO_IS_TRANSIENT(EINTR)); + + /* Test with type wider than int */ + ssize_t r = -EAGAIN; + assert_se( ERRNO_IS_NEG_TRANSIENT(r)); + + /* On 64-bit arches, now (int) r == EAGAIN */ + r = SSIZE_MAX - EAGAIN + 1; + assert_se(!ERRNO_IS_NEG_TRANSIENT(r)); + + assert_se(!ERRNO_IS_NEG_TRANSIENT(INT_MAX)); + assert_se(!ERRNO_IS_NEG_TRANSIENT(INT_MIN)); + assert_se(!ERRNO_IS_NEG_TRANSIENT(INTMAX_MAX)); + assert_se(!ERRNO_IS_NEG_TRANSIENT(INTMAX_MIN)); } DEFINE_TEST_MAIN(LOG_INFO);