test: Add a unit test for overflow detection Signed-off-by: Simon McVittie <smcv@collabora.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c
index bfc8ad3..4c978fa 100644
--- a/test/testautomation_stdlib.c
+++ b/test/testautomation_stdlib.c
@@ -322,6 +322,168 @@ stdlib_sscanf(void *arg)
return TEST_COMPLETED;
}
+#if defined(_WIN64)
+# define SIZE_FORMAT "I64u"
+#elif defined(__WIN32__)
+# define SIZE_FORMAT "I32u"
+#else
+# define SIZE_FORMAT "zu"
+#endif
+
+typedef struct
+{
+ size_t a;
+ size_t b;
+ size_t result;
+ int status;
+} overflow_test;
+
+static const overflow_test multiplications[] =
+{
+ { 1, 1, 1, 0 },
+ { 0, 0, 0, 0 },
+ { SDL_SIZE_MAX, 0, 0, 0 },
+ { SDL_SIZE_MAX, 1, SDL_SIZE_MAX, 0 },
+ { SDL_SIZE_MAX / 2, 2, SDL_SIZE_MAX - (SDL_SIZE_MAX % 2), 0 },
+ { SDL_SIZE_MAX / 23, 23, SDL_SIZE_MAX - (SDL_SIZE_MAX % 23), 0 },
+
+ { (SDL_SIZE_MAX / 2) + 1, 2, 0, -1 },
+ { (SDL_SIZE_MAX / 23) + 42, 23, 0, -1 },
+ { SDL_SIZE_MAX, SDL_SIZE_MAX, 0, -1 },
+};
+
+static const overflow_test additions[] =
+{
+ { 1, 1, 2, 0 },
+ { 0, 0, 0, 0 },
+ { SDL_SIZE_MAX, 0, SDL_SIZE_MAX, 0 },
+ { SDL_SIZE_MAX - 1, 1, SDL_SIZE_MAX, 0 },
+ { SDL_SIZE_MAX - 42, 23, SDL_SIZE_MAX - (42 - 23), 0 },
+
+ { SDL_SIZE_MAX, 1, 0, -1 },
+ { SDL_SIZE_MAX, 23, 0, -1 },
+ { SDL_SIZE_MAX, SDL_SIZE_MAX, 0, -1 },
+};
+
+static int
+stdlib_overflow(void *arg)
+{
+ size_t i;
+ size_t useBuiltin;
+
+ for (useBuiltin = 0; useBuiltin < 2; useBuiltin++) {
+ if (useBuiltin) {
+ SDLTest_Log("Using gcc/clang builtins if possible");
+ } else {
+ SDLTest_Log("Not using gcc/clang builtins");
+ }
+
+ for (i = 0; i < SDL_arraysize(multiplications); i++) {
+ const overflow_test *t = &multiplications[i];
+ int status;
+ size_t result = ~t->result;
+
+ if (useBuiltin) {
+ status = SDL_size_mul_overflow(t->a, t->b, &result);
+ } else {
+ /* This disables the macro that tries to use a gcc/clang
+ * builtin, so we test the fallback implementation instead. */
+ status = (SDL_size_mul_overflow)(t->a, t->b, &result);
+ }
+
+ if (t->status == 0) {
+ SDLTest_AssertCheck(status == 0,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT ") should succeed",
+ t->a, t->b);
+ SDLTest_AssertCheck(result == t->result,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT "): expected %" SIZE_FORMAT ", got %" SIZE_FORMAT,
+ t->a, t->b, t->result, result);
+ } else {
+ SDLTest_AssertCheck(status == -1,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT ") should fail",
+ t->a, t->b);
+ }
+
+ if (t->a == t->b) {
+ continue;
+ }
+
+ result = ~t->result;
+
+ if (useBuiltin) {
+ status = SDL_size_mul_overflow(t->b, t->a, &result);
+ } else {
+ status = (SDL_size_mul_overflow)(t->b, t->a, &result);
+ }
+
+ if (t->status == 0) {
+ SDLTest_AssertCheck(status == 0,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT ") should succeed",
+ t->b, t->a);
+ SDLTest_AssertCheck(result == t->result,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT "): expected %" SIZE_FORMAT ", got %" SIZE_FORMAT,
+ t->b, t->a, t->result, result);
+ } else {
+ SDLTest_AssertCheck(status == -1,
+ "(%" SIZE_FORMAT " * %" SIZE_FORMAT ") should fail",
+ t->b, t->a);
+ }
+ }
+
+ for (i = 0; i < SDL_arraysize(additions); i++) {
+ const overflow_test *t = &additions[i];
+ int status;
+ size_t result = ~t->result;
+
+ if (useBuiltin) {
+ status = SDL_size_add_overflow(t->a, t->b, &result);
+ } else {
+ status = (SDL_size_add_overflow)(t->a, t->b, &result);
+ }
+
+ if (t->status == 0) {
+ SDLTest_AssertCheck(status == 0,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT ") should succeed",
+ t->a, t->b);
+ SDLTest_AssertCheck(result == t->result,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT "): expected %" SIZE_FORMAT ", got %" SIZE_FORMAT,
+ t->a, t->b, t->result, result);
+ } else {
+ SDLTest_AssertCheck(status == -1,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT ") should fail",
+ t->a, t->b);
+ }
+
+ if (t->a == t->b) {
+ continue;
+ }
+
+ result = ~t->result;
+
+ if (useBuiltin) {
+ status = SDL_size_add_overflow(t->b, t->a, &result);
+ } else {
+ status = (SDL_size_add_overflow)(t->b, t->a, &result);
+ }
+
+ if (t->status == 0) {
+ SDLTest_AssertCheck(status == 0,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT ") should succeed",
+ t->b, t->a);
+ SDLTest_AssertCheck(result == t->result,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT "): expected %" SIZE_FORMAT ", got %" SIZE_FORMAT,
+ t->b, t->a, t->result, result);
+ } else {
+ SDLTest_AssertCheck(status == -1,
+ "(%" SIZE_FORMAT " + %" SIZE_FORMAT ") should fail",
+ t->b, t->a);
+ }
+ }
+ }
+
+ return TEST_COMPLETED;
+}
+
/* ================= Test References ================== */
/* Standard C routine test cases */
@@ -337,9 +499,17 @@ static const SDLTest_TestCaseReference stdlibTest3 =
static const SDLTest_TestCaseReference stdlibTest4 =
{ (SDLTest_TestCaseFp)stdlib_sscanf, "stdlib_sscanf", "Call to SDL_sscanf", TEST_ENABLED };
+static const SDLTest_TestCaseReference stdlibTestOverflow =
+ { stdlib_overflow, "stdlib_overflow", "Overflow detection", TEST_ENABLED };
+
/* Sequence of Standard C routine test cases */
static const SDLTest_TestCaseReference *stdlibTests[] = {
- &stdlibTest1, &stdlibTest2, &stdlibTest3, &stdlibTest4, NULL
+ &stdlibTest1,
+ &stdlibTest2,
+ &stdlibTest3,
+ &stdlibTest4,
+ &stdlibTestOverflow,
+ NULL
};
/* Standard C routine test suite (global) */