mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
macro: introduce u64_multiply_safe() to avoid overflow
Just a paranoia.
This commit is contained in:
@@ -51,6 +51,13 @@
|
||||
#error "neither int nor long are four bytes long?!?"
|
||||
#endif
|
||||
|
||||
static inline uint64_t u64_multiply_safe(uint64_t a, uint64_t b) {
|
||||
if (_unlikely_(a != 0 && b > (UINT64_MAX / a)))
|
||||
return 0; /* overflow */
|
||||
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
|
||||
static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
|
||||
|
||||
@@ -795,7 +795,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
|
||||
if (fstatvfs(f->fd, &svfs) >= 0) {
|
||||
uint64_t available;
|
||||
|
||||
available = LESS_BY((uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize, f->metrics.keep_free);
|
||||
available = LESS_BY(u64_multiply_safe(svfs.f_bfree, svfs.f_bsize), f->metrics.keep_free);
|
||||
|
||||
if (new_size - old_size > available)
|
||||
return -E2BIG;
|
||||
@@ -3881,7 +3881,7 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) {
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fstatvfs(fd, &ss) >= 0)
|
||||
fs_size = ss.f_frsize * ss.f_blocks;
|
||||
fs_size = u64_multiply_safe(ss.f_frsize, ss.f_blocks);
|
||||
else
|
||||
log_debug_errno(errno, "Failed to determine disk size: %m");
|
||||
|
||||
|
||||
@@ -1012,4 +1012,29 @@ TEST(round_up) {
|
||||
TEST_ROUND_UP_BY_TYPE(uint64_t, UINT64_MAX);
|
||||
}
|
||||
|
||||
TEST(u64_multiply_safe) {
|
||||
assert_se(u64_multiply_safe(0, 0) == 0);
|
||||
assert_se(u64_multiply_safe(10, 0) == 0);
|
||||
assert_se(u64_multiply_safe(0, 10) == 0);
|
||||
assert_se(u64_multiply_safe(10, 10) == 100);
|
||||
|
||||
assert_se(u64_multiply_safe(UINT64_MAX, 0) == 0);
|
||||
assert_se(u64_multiply_safe(UINT64_MAX, 1) == UINT64_MAX);
|
||||
assert_se(u64_multiply_safe(UINT64_MAX, 2) == 0);
|
||||
assert_se(u64_multiply_safe(0, UINT64_MAX) == 0);
|
||||
assert_se(u64_multiply_safe(1, UINT64_MAX) == UINT64_MAX);
|
||||
assert_se(u64_multiply_safe(2, UINT64_MAX) == 0);
|
||||
|
||||
assert_se(u64_multiply_safe(UINT64_MAX / 2, 0) == 0);
|
||||
assert_se(u64_multiply_safe(UINT64_MAX / 2, 1) == UINT64_MAX / 2);
|
||||
assert_se(u64_multiply_safe(UINT64_MAX / 2, 2) == UINT64_MAX - 1);
|
||||
assert_se(u64_multiply_safe(UINT64_MAX / 2, 3) == 0);
|
||||
assert_se(u64_multiply_safe(0, UINT64_MAX / 2) == 0);
|
||||
assert_se(u64_multiply_safe(1, UINT64_MAX / 2) == UINT64_MAX / 2);
|
||||
assert_se(u64_multiply_safe(2, UINT64_MAX / 2) == UINT64_MAX - 1);
|
||||
assert_se(u64_multiply_safe(3, UINT64_MAX / 2) == 0);
|
||||
|
||||
assert_se(u64_multiply_safe(UINT64_MAX, UINT64_MAX) == 0);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
||||
Reference in New Issue
Block a user