Skip to content

Commit 5b5041f

Browse files
committed
test: add coverage for untested allocator behavior
Add small self-contained test cases and wire them into the Makefile and test_smc.py harness: - invalid_free_aligned_sized_small: free_aligned_sized() with a non-power-of-two alignment, covering the "invalid sized deallocation alignment (small)" fatal path. - invalid_malloc_object_size_small_canary: malloc_object_size() queried at an offset past the usable region, covering the "invalid malloc_object_size (canary)" fatal path. - pvalloc: regression test for pvalloc(0) returning a valid allocation. - reallocarray_overflow: reallocarray() returns NULL/ENOMEM on overflow. - posix_memalign_einval: posix_memalign() returns EINVAL for an invalid alignment and leaves the output pointer untouched. - aligned_alloc_einval: aligned_alloc() returns NULL/EINVAL for a non-power-of-two alignment.
1 parent 1976e09 commit 5b5041f

8 files changed

Lines changed: 118 additions & 0 deletions

test/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ EXECUTABLES := \
6464
invalid_aligned_sized_delete_small \
6565
aligned_sized_delete_large \
6666
invalid_aligned_sized_delete_large \
67+
invalid_free_aligned_sized_small \
6768
free_sized_small \
6869
free_sized_large \
6970
unaligned_malloc_usable_size_small \
@@ -74,10 +75,15 @@ EXECUTABLES := \
7475
malloc_object_size_zero \
7576
invalid_malloc_object_size_small \
7677
invalid_malloc_object_size_small_quarantine \
78+
invalid_malloc_object_size_small_canary \
7779
impossibly_large_malloc \
7880
realloc_init \
81+
reallocarray_overflow \
7982
calloc_overflow \
8083
calloc_zeroed \
84+
pvalloc \
85+
posix_memalign_einval \
86+
aligned_alloc_einval \
8187
malloc_zero_different \
8288
malloc_noreuse
8389

test/aligned_alloc_einval.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <errno.h>
2+
#include <stdlib.h>
3+
4+
#include "test_util.h"
5+
6+
OPTNONE int main(void) {
7+
errno = 0;
8+
// alignment is not a power of two
9+
void *p = aligned_alloc(17, 100);
10+
return !(p == NULL && errno == EINVAL);
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "../include/h_malloc.h"
2+
3+
int main(void) {
4+
void *p = malloc(16);
5+
// alignment 3 is not a power of two
6+
free_aligned_sized(p, 3, 16);
7+
return 0;
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdlib.h>
2+
3+
#include "test_util.h"
4+
5+
size_t malloc_object_size(void *ptr);
6+
7+
OPTNONE int main(void) {
8+
char *p = malloc(16);
9+
// offset past the usable size, into the slab canary region
10+
return (int)malloc_object_size(p + 25);
11+
}

test/posix_memalign_einval.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <errno.h>
2+
#include <stdlib.h>
3+
4+
#include "test_util.h"
5+
6+
OPTNONE int main(void) {
7+
void *p = (void *)0x1;
8+
// alignment must be a power of two multiple of sizeof(void *)
9+
if (posix_memalign(&p, 17, 100) != EINVAL) {
10+
return 1;
11+
}
12+
// the output pointer must be left untouched on failure
13+
return p != (void *)0x1;
14+
}

test/pvalloc.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <malloc.h>
2+
#include <stdlib.h>
3+
4+
#include "../include/h_malloc.h"
5+
#include "test_util.h"
6+
7+
OPTNONE int main(void) {
8+
// pvalloc(0) must return a valid, freeable allocation
9+
void *p = pvalloc(0);
10+
if (p == NULL) {
11+
return 1;
12+
}
13+
free(p);
14+
15+
void *q = pvalloc(100);
16+
if (q == NULL) {
17+
return 1;
18+
}
19+
free(q);
20+
21+
return 0;
22+
}

test/reallocarray_overflow.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <errno.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
#include "test_util.h"
6+
7+
#pragma GCC diagnostic ignored "-Walloc-size-larger-than="
8+
9+
OPTNONE int main(void) {
10+
errno = 0;
11+
void *p = reallocarray(NULL, SIZE_MAX, 2);
12+
return !(p == NULL && errno == ENOMEM);
13+
}

test/test_smc.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ def test_invalid_aligned_sized_delete_large(self):
5151
self.assertEqual(stderr.decode(
5252
"utf-8"), "fatal allocator error: sized deallocation mismatch (large)\n")
5353

54+
def test_invalid_free_aligned_sized_small(self):
55+
_stdout, stderr, returncode = self.run_test(
56+
"invalid_free_aligned_sized_small")
57+
self.assertEqual(returncode, -6)
58+
self.assertEqual(stderr.decode(
59+
"utf-8"), "fatal allocator error: invalid sized deallocation alignment (small)\n")
60+
5461
def test_free_sized_small(self):
5562
_stdout, _stderr, returncode = self.run_test("free_sized_small")
5663
self.assertEqual(returncode, 0)
@@ -255,6 +262,13 @@ def test_invalid_malloc_object_size_small_quarantine(self):
255262
self.assertEqual(stderr.decode(
256263
"utf-8"), "fatal allocator error: invalid malloc_object_size (quarantine)\n")
257264

265+
def test_invalid_malloc_object_size_small_canary(self):
266+
_stdout, stderr, returncode = self.run_test(
267+
"invalid_malloc_object_size_small_canary")
268+
self.assertEqual(returncode, -6)
269+
self.assertEqual(stderr.decode(
270+
"utf-8"), "fatal allocator error: invalid malloc_object_size (canary)\n")
271+
258272
def test_impossibly_large_malloc(self):
259273
_stdout, stderr, returncode = self.run_test(
260274
"impossibly_large_malloc")
@@ -290,11 +304,30 @@ def test_calloc_overflow(self):
290304
"calloc_overflow")
291305
self.assertEqual(returncode, 0)
292306

307+
def test_reallocarray_overflow(self):
308+
_stdout, _stderr, returncode = self.run_test(
309+
"reallocarray_overflow")
310+
self.assertEqual(returncode, 0)
311+
293312
def test_calloc_zeroed(self):
294313
_stdout, _stderr, returncode = self.run_test(
295314
"calloc_zeroed")
296315
self.assertEqual(returncode, 0)
297316

317+
def test_pvalloc(self):
318+
_stdout, _stderr, returncode = self.run_test("pvalloc")
319+
self.assertEqual(returncode, 0)
320+
321+
def test_posix_memalign_einval(self):
322+
_stdout, _stderr, returncode = self.run_test(
323+
"posix_memalign_einval")
324+
self.assertEqual(returncode, 0)
325+
326+
def test_aligned_alloc_einval(self):
327+
_stdout, _stderr, returncode = self.run_test(
328+
"aligned_alloc_einval")
329+
self.assertEqual(returncode, 0)
330+
298331
def test_malloc_zero_different(self):
299332
_stdout, _stderr, returncode = self.run_test(
300333
"malloc_zero_different")

0 commit comments

Comments
 (0)