summaryrefslogtreecommitdiff
path: root/lib/test_overflow.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2018-09-15 21:50:42 +0300
committerThomas Gleixner <tglx@linutronix.de>2018-09-15 21:50:42 +0300
commit9ac669fc01dbfef707ecaa6b618c0d03294cca16 (patch)
tree3207995766ab5664c60026daae5da268806a3262 /lib/test_overflow.c
parentfbfa9260085b5b578a049a90135e5c51928c5f7f (diff)
parent67314ec7b0250290cc85eaa7a2f88a8ddb9e8547 (diff)
downloadlinux-9ac669fc01dbfef707ecaa6b618c0d03294cca16.tar.xz
Merge tag 'y2038' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground into timers/core
Pull more y2038 work from Arnd Bergman: y2038: convert more syscalls Here is another set of system call changes to prepare the change over to 64-bit time_t. As before, the strategy is to change system calls that take a 'struct timespec' argument over to 'struct __kernel_timespec', which for now is defined to be the same but will get redefined to use a 64-bit time_t argument once we are ready to modify the system call tables. The major change from previous patches is that the plan is no longer to directly use the 'compat' system calls for providing compatibility with the existing 32-bit time_t based entry points. Instead, we rename the compat code to something that makes more sense on 32-bit architectures, e.g. compat_timespec becomes old_timespec32. With the renamed types in place, change over the 'stat' and 'utimes' families of system calls, sched_rr_get_interval, recvmmsg and rt_sigtimedwait. Another series for poll, select and io_pgetevents is currently being tested.
Diffstat (limited to 'lib/test_overflow.c')
-rw-r--r--lib/test_overflow.c198
1 files changed, 197 insertions, 1 deletions
diff --git a/lib/test_overflow.c b/lib/test_overflow.c
index 2278fe05a1b0..fc680562d8b6 100644
--- a/lib/test_overflow.c
+++ b/lib/test_overflow.c
@@ -252,7 +252,8 @@ static int __init test_ ## t ## _overflow(void) { \
int err = 0; \
unsigned i; \
\
- pr_info("%-3s: %zu tests\n", #t, ARRAY_SIZE(t ## _tests)); \
+ pr_info("%-3s: %zu arithmetic tests\n", #t, \
+ ARRAY_SIZE(t ## _tests)); \
for (i = 0; i < ARRAY_SIZE(t ## _tests); ++i) \
err |= do_test_ ## t(&t ## _tests[i]); \
return err; \
@@ -287,6 +288,200 @@ static int __init test_overflow_calculation(void)
return err;
}
+static int __init test_overflow_shift(void)
+{
+ int err = 0;
+
+/* Args are: value, shift, type, expected result, overflow expected */
+#define TEST_ONE_SHIFT(a, s, t, expect, of) ({ \
+ int __failed = 0; \
+ typeof(a) __a = (a); \
+ typeof(s) __s = (s); \
+ t __e = (expect); \
+ t __d; \
+ bool __of = check_shl_overflow(__a, __s, &__d); \
+ if (__of != of) { \
+ pr_warn("expected (%s)(%s << %s) to%s overflow\n", \
+ #t, #a, #s, of ? "" : " not"); \
+ __failed = 1; \
+ } else if (!__of && __d != __e) { \
+ pr_warn("expected (%s)(%s << %s) == %s\n", \
+ #t, #a, #s, #expect); \
+ if ((t)-1 < 0) \
+ pr_warn("got %lld\n", (s64)__d); \
+ else \
+ pr_warn("got %llu\n", (u64)__d); \
+ __failed = 1; \
+ } \
+ if (!__failed) \
+ pr_info("ok: (%s)(%s << %s) == %s\n", #t, #a, #s, \
+ of ? "overflow" : #expect); \
+ __failed; \
+})
+
+ /* Sane shifts. */
+ err |= TEST_ONE_SHIFT(1, 0, u8, 1 << 0, false);
+ err |= TEST_ONE_SHIFT(1, 4, u8, 1 << 4, false);
+ err |= TEST_ONE_SHIFT(1, 7, u8, 1 << 7, false);
+ err |= TEST_ONE_SHIFT(0xF, 4, u8, 0xF << 4, false);
+ err |= TEST_ONE_SHIFT(1, 0, u16, 1 << 0, false);
+ err |= TEST_ONE_SHIFT(1, 10, u16, 1 << 10, false);
+ err |= TEST_ONE_SHIFT(1, 15, u16, 1 << 15, false);
+ err |= TEST_ONE_SHIFT(0xFF, 8, u16, 0xFF << 8, false);
+ err |= TEST_ONE_SHIFT(1, 0, int, 1 << 0, false);
+ err |= TEST_ONE_SHIFT(1, 16, int, 1 << 16, false);
+ err |= TEST_ONE_SHIFT(1, 30, int, 1 << 30, false);
+ err |= TEST_ONE_SHIFT(1, 0, s32, 1 << 0, false);
+ err |= TEST_ONE_SHIFT(1, 16, s32, 1 << 16, false);
+ err |= TEST_ONE_SHIFT(1, 30, s32, 1 << 30, false);
+ err |= TEST_ONE_SHIFT(1, 0, unsigned int, 1U << 0, false);
+ err |= TEST_ONE_SHIFT(1, 20, unsigned int, 1U << 20, false);
+ err |= TEST_ONE_SHIFT(1, 31, unsigned int, 1U << 31, false);
+ err |= TEST_ONE_SHIFT(0xFFFFU, 16, unsigned int, 0xFFFFU << 16, false);
+ err |= TEST_ONE_SHIFT(1, 0, u32, 1U << 0, false);
+ err |= TEST_ONE_SHIFT(1, 20, u32, 1U << 20, false);
+ err |= TEST_ONE_SHIFT(1, 31, u32, 1U << 31, false);
+ err |= TEST_ONE_SHIFT(0xFFFFU, 16, u32, 0xFFFFU << 16, false);
+ err |= TEST_ONE_SHIFT(1, 0, u64, 1ULL << 0, false);
+ err |= TEST_ONE_SHIFT(1, 40, u64, 1ULL << 40, false);
+ err |= TEST_ONE_SHIFT(1, 63, u64, 1ULL << 63, false);
+ err |= TEST_ONE_SHIFT(0xFFFFFFFFULL, 32, u64,
+ 0xFFFFFFFFULL << 32, false);
+
+ /* Sane shift: start and end with 0, without a too-wide shift. */
+ err |= TEST_ONE_SHIFT(0, 7, u8, 0, false);
+ err |= TEST_ONE_SHIFT(0, 15, u16, 0, false);
+ err |= TEST_ONE_SHIFT(0, 31, unsigned int, 0, false);
+ err |= TEST_ONE_SHIFT(0, 31, u32, 0, false);
+ err |= TEST_ONE_SHIFT(0, 63, u64, 0, false);
+
+ /* Sane shift: start and end with 0, without reaching signed bit. */
+ err |= TEST_ONE_SHIFT(0, 6, s8, 0, false);
+ err |= TEST_ONE_SHIFT(0, 14, s16, 0, false);
+ err |= TEST_ONE_SHIFT(0, 30, int, 0, false);
+ err |= TEST_ONE_SHIFT(0, 30, s32, 0, false);
+ err |= TEST_ONE_SHIFT(0, 62, s64, 0, false);
+
+ /* Overflow: shifted the bit off the end. */
+ err |= TEST_ONE_SHIFT(1, 8, u8, 0, true);
+ err |= TEST_ONE_SHIFT(1, 16, u16, 0, true);
+ err |= TEST_ONE_SHIFT(1, 32, unsigned int, 0, true);
+ err |= TEST_ONE_SHIFT(1, 32, u32, 0, true);
+ err |= TEST_ONE_SHIFT(1, 64, u64, 0, true);
+
+ /* Overflow: shifted into the signed bit. */
+ err |= TEST_ONE_SHIFT(1, 7, s8, 0, true);
+ err |= TEST_ONE_SHIFT(1, 15, s16, 0, true);
+ err |= TEST_ONE_SHIFT(1, 31, int, 0, true);
+ err |= TEST_ONE_SHIFT(1, 31, s32, 0, true);
+ err |= TEST_ONE_SHIFT(1, 63, s64, 0, true);
+
+ /* Overflow: high bit falls off unsigned types. */
+ /* 10010110 */
+ err |= TEST_ONE_SHIFT(150, 1, u8, 0, true);
+ /* 1000100010010110 */
+ err |= TEST_ONE_SHIFT(34966, 1, u16, 0, true);
+ /* 10000100000010001000100010010110 */
+ err |= TEST_ONE_SHIFT(2215151766U, 1, u32, 0, true);
+ err |= TEST_ONE_SHIFT(2215151766U, 1, unsigned int, 0, true);
+ /* 1000001000010000010000000100000010000100000010001000100010010110 */
+ err |= TEST_ONE_SHIFT(9372061470395238550ULL, 1, u64, 0, true);
+
+ /* Overflow: bit shifted into signed bit on signed types. */
+ /* 01001011 */
+ err |= TEST_ONE_SHIFT(75, 1, s8, 0, true);
+ /* 0100010001001011 */
+ err |= TEST_ONE_SHIFT(17483, 1, s16, 0, true);
+ /* 01000010000001000100010001001011 */
+ err |= TEST_ONE_SHIFT(1107575883, 1, s32, 0, true);
+ err |= TEST_ONE_SHIFT(1107575883, 1, int, 0, true);
+ /* 0100000100001000001000000010000001000010000001000100010001001011 */
+ err |= TEST_ONE_SHIFT(4686030735197619275LL, 1, s64, 0, true);
+
+ /* Overflow: bit shifted past signed bit on signed types. */
+ /* 01001011 */
+ err |= TEST_ONE_SHIFT(75, 2, s8, 0, true);
+ /* 0100010001001011 */
+ err |= TEST_ONE_SHIFT(17483, 2, s16, 0, true);
+ /* 01000010000001000100010001001011 */
+ err |= TEST_ONE_SHIFT(1107575883, 2, s32, 0, true);
+ err |= TEST_ONE_SHIFT(1107575883, 2, int, 0, true);
+ /* 0100000100001000001000000010000001000010000001000100010001001011 */
+ err |= TEST_ONE_SHIFT(4686030735197619275LL, 2, s64, 0, true);
+
+ /* Overflow: values larger than destination type. */
+ err |= TEST_ONE_SHIFT(0x100, 0, u8, 0, true);
+ err |= TEST_ONE_SHIFT(0xFF, 0, s8, 0, true);
+ err |= TEST_ONE_SHIFT(0x10000U, 0, u16, 0, true);
+ err |= TEST_ONE_SHIFT(0xFFFFU, 0, s16, 0, true);
+ err |= TEST_ONE_SHIFT(0x100000000ULL, 0, u32, 0, true);
+ err |= TEST_ONE_SHIFT(0x100000000ULL, 0, unsigned int, 0, true);
+ err |= TEST_ONE_SHIFT(0xFFFFFFFFUL, 0, s32, 0, true);
+ err |= TEST_ONE_SHIFT(0xFFFFFFFFUL, 0, int, 0, true);
+ err |= TEST_ONE_SHIFT(0xFFFFFFFFFFFFFFFFULL, 0, s64, 0, true);
+
+ /* Nonsense: negative initial value. */
+ err |= TEST_ONE_SHIFT(-1, 0, s8, 0, true);
+ err |= TEST_ONE_SHIFT(-1, 0, u8, 0, true);
+ err |= TEST_ONE_SHIFT(-5, 0, s16, 0, true);
+ err |= TEST_ONE_SHIFT(-5, 0, u16, 0, true);
+ err |= TEST_ONE_SHIFT(-10, 0, int, 0, true);
+ err |= TEST_ONE_SHIFT(-10, 0, unsigned int, 0, true);
+ err |= TEST_ONE_SHIFT(-100, 0, s32, 0, true);
+ err |= TEST_ONE_SHIFT(-100, 0, u32, 0, true);
+ err |= TEST_ONE_SHIFT(-10000, 0, s64, 0, true);
+ err |= TEST_ONE_SHIFT(-10000, 0, u64, 0, true);
+
+ /* Nonsense: negative shift values. */
+ err |= TEST_ONE_SHIFT(0, -5, s8, 0, true);
+ err |= TEST_ONE_SHIFT(0, -5, u8, 0, true);
+ err |= TEST_ONE_SHIFT(0, -10, s16, 0, true);
+ err |= TEST_ONE_SHIFT(0, -10, u16, 0, true);
+ err |= TEST_ONE_SHIFT(0, -15, int, 0, true);
+ err |= TEST_ONE_SHIFT(0, -15, unsigned int, 0, true);
+ err |= TEST_ONE_SHIFT(0, -20, s32, 0, true);
+ err |= TEST_ONE_SHIFT(0, -20, u32, 0, true);
+ err |= TEST_ONE_SHIFT(0, -30, s64, 0, true);
+ err |= TEST_ONE_SHIFT(0, -30, u64, 0, true);
+
+ /* Overflow: shifted at or beyond entire type's bit width. */
+ err |= TEST_ONE_SHIFT(0, 8, u8, 0, true);
+ err |= TEST_ONE_SHIFT(0, 9, u8, 0, true);
+ err |= TEST_ONE_SHIFT(0, 8, s8, 0, true);
+ err |= TEST_ONE_SHIFT(0, 9, s8, 0, true);
+ err |= TEST_ONE_SHIFT(0, 16, u16, 0, true);
+ err |= TEST_ONE_SHIFT(0, 17, u16, 0, true);
+ err |= TEST_ONE_SHIFT(0, 16, s16, 0, true);
+ err |= TEST_ONE_SHIFT(0, 17, s16, 0, true);
+ err |= TEST_ONE_SHIFT(0, 32, u32, 0, true);
+ err |= TEST_ONE_SHIFT(0, 33, u32, 0, true);
+ err |= TEST_ONE_SHIFT(0, 32, int, 0, true);
+ err |= TEST_ONE_SHIFT(0, 33, int, 0, true);
+ err |= TEST_ONE_SHIFT(0, 32, s32, 0, true);
+ err |= TEST_ONE_SHIFT(0, 33, s32, 0, true);
+ err |= TEST_ONE_SHIFT(0, 64, u64, 0, true);
+ err |= TEST_ONE_SHIFT(0, 65, u64, 0, true);
+ err |= TEST_ONE_SHIFT(0, 64, s64, 0, true);
+ err |= TEST_ONE_SHIFT(0, 65, s64, 0, true);
+
+ /*
+ * Corner case: for unsigned types, we fail when we've shifted
+ * through the entire width of bits. For signed types, we might
+ * want to match this behavior, but that would mean noticing if
+ * we shift through all but the signed bit, and this is not
+ * currently detected (but we'll notice an overflow into the
+ * signed bit). So, for now, we will test this condition but
+ * mark it as not expected to overflow.
+ */
+ err |= TEST_ONE_SHIFT(0, 7, s8, 0, false);
+ err |= TEST_ONE_SHIFT(0, 15, s16, 0, false);
+ err |= TEST_ONE_SHIFT(0, 31, int, 0, false);
+ err |= TEST_ONE_SHIFT(0, 31, s32, 0, false);
+ err |= TEST_ONE_SHIFT(0, 63, s64, 0, false);
+
+ return err;
+}
+
/*
* Deal with the various forms of allocator arguments. See comments above
* the DEFINE_TEST_ALLOC() instances for mapping of the "bits".
@@ -397,6 +592,7 @@ static int __init test_module_init(void)
int err = 0;
err |= test_overflow_calculation();
+ err |= test_overflow_shift();
err |= test_overflow_allocation();
if (err) {