1/* ----------------------------------------------------------------------------
2Copyright (c) 2018, Microsoft Research, Daan Leijen
3This is free software; you can redistribute it and/or modify it under the
4terms of the MIT license. A copy of the license can be found in the file
5"LICENSE" at the root of this distribution.
6-----------------------------------------------------------------------------*/
7
8/*
9Testing allocators is difficult as bugs may only surface after particular
10allocation patterns. The main approach to testing _mimalloc_ is therefore
11to have extensive internal invariant checking (see `page_is_valid` in `page.c`
12for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
13The main testing is then to run `mimalloc-bench` [1] using full invariant checking
14to catch any potential problems over a wide range of intensive allocation bench
15marks.
16
17However, this does not test well for the entire API surface. In this test file
18we therefore test the API over various inputs. Please add more tests :-)
19
20[1] https://github.com/daanx/mimalloc-bench
21*/
22
23#include <stdio.h>
24#include <assert.h>
25#include <stdbool.h>
26#include <stdint.h>
27#include <errno.h>
28#include "mimalloc.h"
29#include "mimalloc-internal.h"
30
31// ---------------------------------------------------------------------------
32// Test macros: CHECK(name,predicate) and CHECK_BODY(name,body)
33// ---------------------------------------------------------------------------
34static int ok = 0;
35static int failed = 0;
36
37#define CHECK_BODY(name,body) \
38 do { \
39 fprintf(stderr,"test: %s... ", name ); \
40 bool result = true; \
41 do { body } while(false); \
42 if (!(result)) { \
43 failed++; \
44 fprintf(stderr, \
45 "\n FAILED: %s:%d:\n %s\n", \
46 __FILE__, \
47 __LINE__, \
48 #body); \
49 /* exit(1); */ \
50 } \
51 else { \
52 ok++; \
53 fprintf(stderr,"ok.\n"); \
54 } \
55 } while (false)
56
57#define CHECK(name,expr) CHECK_BODY(name,{ result = (expr); })
58
59// ---------------------------------------------------------------------------
60// Test functions
61// ---------------------------------------------------------------------------
62bool test_heap1();
63bool test_heap2();
64
65// ---------------------------------------------------------------------------
66// Main testing
67// ---------------------------------------------------------------------------
68int main() {
69 mi_option_disable(mi_option_verbose);
70
71 // ---------------------------------------------------
72 // Malloc
73 // ---------------------------------------------------
74
75 CHECK_BODY("malloc-zero",{
76 void* p = mi_malloc(0); mi_free(p);
77 });
78 CHECK_BODY("malloc-nomem1",{
79 result = (mi_malloc(SIZE_MAX/2) == NULL);
80 });
81 CHECK_BODY("malloc-null",{
82 mi_free(NULL);
83 });
84
85 // ---------------------------------------------------
86 // Extended
87 // ---------------------------------------------------
88 #if defined(MI_MALLOC_OVERRIDE) && !defined(_WIN32)
89 CHECK_BODY("posix_memalign1", {
90 void* p = &p;
91 int err = posix_memalign(&p, sizeof(void*), 32);
92 mi_assert((err==0 && (uintptr_t)p % sizeof(void*) == 0) || p==&p);
93 mi_free(p);
94 result = (err==0);
95 });
96 CHECK_BODY("posix_memalign_no_align", {
97 void* p = &p;
98 int err = posix_memalign(&p, 3, 32);
99 mi_assert(p==&p);
100 result = (err==EINVAL);
101 });
102 CHECK_BODY("posix_memalign_zero", {
103 void* p = &p;
104 int err = posix_memalign(&p, sizeof(void*), 0);
105 mi_free(p);
106 result = (err==0);
107 });
108 CHECK_BODY("posix_memalign_nopow2", {
109 void* p = &p;
110 int err = posix_memalign(&p, 3*sizeof(void*), 32);
111 result = (err==EINVAL && p==&p);
112 });
113 CHECK_BODY("posix_memalign_nomem", {
114 void* p = &p;
115 int err = posix_memalign(&p, sizeof(void*), SIZE_MAX);
116 result = (err==ENOMEM && p==&p);
117 });
118 #endif
119
120 // ---------------------------------------------------
121 // Aligned API
122 // ---------------------------------------------------
123 CHECK_BODY("malloc-aligned1", {
124 void* p = mi_malloc_aligned(32,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p);
125 });
126 CHECK_BODY("malloc-aligned2", {
127 void* p = mi_malloc_aligned(48,32); result = (p != NULL && (uintptr_t)(p) % 32 == 0); mi_free(p);
128 });
129 CHECK_BODY("malloc-aligned-at1", {
130 void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p);
131 });
132 CHECK_BODY("malloc-aligned-at2", {
133 void* p = mi_malloc_aligned_at(50,32,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 32 == 0); mi_free(p);
134 });
135
136 // ---------------------------------------------------
137 // Heaps
138 // ---------------------------------------------------
139 CHECK("heap_destroy", test_heap1());
140 CHECK("heap_delete", test_heap2());
141
142 //mi_stats_print(NULL);
143
144 // ---------------------------------------------------
145 // various
146 // ---------------------------------------------------
147 CHECK_BODY("realpath", {
148 char* s = mi_realpath( ".", NULL );
149 // printf("realpath: %s\n",s);
150 mi_free(s);
151 });
152
153 // ---------------------------------------------------
154 // Done
155 // ---------------------------------------------------[]
156 fprintf(stderr,"\n\n---------------------------------------------\n"
157 "succeeded: %i\n"
158 "failed : %i\n\n", ok, failed);
159 return failed;
160}
161
162// ---------------------------------------------------
163// Larger test functions
164// ---------------------------------------------------
165
166bool test_heap1() {
167 mi_heap_t* heap = mi_heap_new();
168 int* p1 = mi_heap_malloc_tp(heap,int);
169 int* p2 = mi_heap_malloc_tp(heap,int);
170 *p1 = *p2 = 43;
171 mi_heap_destroy(heap);
172 return true;
173}
174
175bool test_heap2() {
176 mi_heap_t* heap = mi_heap_new();
177 int* p1 = mi_heap_malloc_tp(heap,int);
178 int* p2 = mi_heap_malloc_tp(heap,int);
179 mi_heap_delete(heap);
180 *p1 = 42;
181 mi_free(p1);
182 mi_free(p2);
183 return true;
184}
185