#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) {
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;
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");
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);