blob: 34c4aa0addae7472b1ea244619f084e4ebe4881f [file] [log] [blame]
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001/*
2 * testOOM.c: Test out-of-memory handling
3 *
4 * See Copyright for the status of this software.
5 *
6 * Copyright 2003 Red Hat, Inc.
7 * Written by: hp@redhat.com
8 */
9
10#include "testOOMlib.h"
11
12#ifdef HAVE_STDLIB_H
13#include <stdlib.h>
14#endif
15
16#include <string.h>
17
18#define _TEST_INT_MAX 2147483647
19#ifndef TRUE
20#define TRUE (1)
21#endif
22#ifndef FALSE
23#define FALSE (0)
24#endif
25#ifndef NULL
26#define NULL ((void*)0)
27#endif
28
29#include <libxml/xmlmemory.h>
30
31static int fail_alloc_counter = _TEST_INT_MAX;
32static int n_failures_per_failure = 1;
33static int n_failures_this_failure = 0;
34static int n_blocks_outstanding = 0;
35
36/**
William M. Brack60f394e2003-11-16 06:25:42 +000037 * set_fail_alloc_counter:
38 * @until_next_fail: number of successful allocs before one fails
39 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000040 * Sets the number of allocations until we simulate a failed
41 * allocation. If set to 0, the next allocation to run
42 * fails; if set to 1, one succeeds then the next fails; etc.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080043 * Set to _TEST_INT_MAX to not fail anything.
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000044 */
45static void
46set_fail_alloc_counter (int until_next_fail)
47{
48 fail_alloc_counter = until_next_fail;
49}
50
51/**
William M. Brack60f394e2003-11-16 06:25:42 +000052 * get_fail_alloc_counter:
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000053 *
William M. Brack60f394e2003-11-16 06:25:42 +000054 * Returns the number of successful allocs until we'll simulate
55 * a failed alloc.
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000056 */
57static int
58get_fail_alloc_counter (void)
59{
60 return fail_alloc_counter;
61}
62
63/**
William M. Brack60f394e2003-11-16 06:25:42 +000064 * set_fail_alloc_failures:
65 * @failures_per_failure: number to fail
66 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000067 * Sets how many mallocs to fail when the fail alloc counter reaches
68 * 0.
69 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000070 */
71static void
72set_fail_alloc_failures (int failures_per_failure)
73{
74 n_failures_per_failure = failures_per_failure;
75}
76
77/**
William M. Brack60f394e2003-11-16 06:25:42 +000078 * decrement_fail_alloc_counter:
79 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000080 * Called when about to alloc some memory; if
81 * it returns #TRUE, then the allocation should
82 * fail. If it returns #FALSE, then the allocation
83 * should not fail.
84 *
William M. Brack60f394e2003-11-16 06:25:42 +000085 * returns #TRUE if this alloc should fail
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000086 */
87static int
88decrement_fail_alloc_counter (void)
89{
90 if (fail_alloc_counter <= 0)
91 {
92 n_failures_this_failure += 1;
93 if (n_failures_this_failure >= n_failures_per_failure)
94 {
95 fail_alloc_counter = _TEST_INT_MAX;
96
97 n_failures_this_failure = 0;
98 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +080099
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000100 return TRUE;
101 }
102 else
103 {
104 fail_alloc_counter -= 1;
105 return FALSE;
106 }
107}
108
109/**
William M. Brack60f394e2003-11-16 06:25:42 +0000110 * test_get_malloc_blocks_outstanding:
111 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000112 * Get the number of outstanding malloc()'d blocks.
113 *
William M. Brack60f394e2003-11-16 06:25:42 +0000114 * Returns number of blocks
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000115 */
116int
117test_get_malloc_blocks_outstanding (void)
118{
119 return n_blocks_outstanding;
120}
121
122void*
123test_malloc (size_t bytes)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800124{
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000125 if (decrement_fail_alloc_counter ())
126 {
127 /* FAIL the malloc */
128 return NULL;
129 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800130
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000131 if (bytes == 0) /* some system mallocs handle this, some don't */
132 return NULL;
133 else
134 {
135 void *mem;
136 mem = xmlMemMalloc (bytes);
137
138 if (mem)
139 n_blocks_outstanding += 1;
140
141 return mem;
142 }
143}
144
145void*
146test_realloc (void *memory,
147 size_t bytes)
148{
149 if (decrement_fail_alloc_counter ())
150 {
151 /* FAIL */
152 return NULL;
153 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800154
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000155 if (bytes == 0) /* guarantee this is safe */
156 {
157 test_free (memory);
158 return NULL;
159 }
160 else
161 {
162 void *mem;
163 mem = xmlMemRealloc (memory, bytes);
164
165 if (memory == NULL && mem != NULL)
166 n_blocks_outstanding += 1;
167
168 return mem;
169 }
170}
171
172void
173test_free (void *memory)
174{
175 if (memory) /* we guarantee it's safe to free (NULL) */
176 {
177 n_blocks_outstanding -= 1;
178
179 xmlMemFree (memory);
180 }
181}
182
183char*
184test_strdup (const char *str)
185{
186 int len;
187 char *copy;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800188
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000189 if (str == NULL)
190 return NULL;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800191
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000192 len = strlen (str);
193
194 copy = test_malloc (len + 1);
195 if (copy == NULL)
196 return NULL;
197
198 memcpy (copy, str, len + 1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800199
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000200 return copy;
201}
202
203static int
204run_failing_each_malloc (int n_mallocs,
205 TestMemoryFunction func,
206 void *data)
207{
208 n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800209
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000210 while (n_mallocs >= 0)
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800211 {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000212 set_fail_alloc_counter (n_mallocs);
213
214 if (!(* func) (data))
215 return FALSE;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800216
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000217 n_mallocs -= 1;
218 }
219
220 set_fail_alloc_counter (_TEST_INT_MAX);
221
222 return TRUE;
223}
224
225/**
William M. Brack60f394e2003-11-16 06:25:42 +0000226 * test_oom_handling:
227 * @func: function to call
228 * @data: data to pass to function
229 *
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000230 * Tests how well the given function responds to out-of-memory
231 * situations. Calls the function repeatedly, failing a different
232 * call to malloc() each time. If the function ever returns #FALSE,
233 * the test fails. The function should return #TRUE whenever something
234 * valid (such as returning an error, or succeeding) occurs, and #FALSE
235 * if it gets confused in some way.
236 *
William M. Brack60f394e2003-11-16 06:25:42 +0000237 * Returns #TRUE if the function never returns FALSE
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000238 */
239int
240test_oom_handling (TestMemoryFunction func,
241 void *data)
242{
243 int approx_mallocs;
244
245 /* Run once to see about how many mallocs are involved */
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800246
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000247 set_fail_alloc_counter (_TEST_INT_MAX);
248
249 if (!(* func) (data))
250 return FALSE;
251
252 approx_mallocs = _TEST_INT_MAX - get_fail_alloc_counter ();
253
254 set_fail_alloc_failures (1);
255 if (!run_failing_each_malloc (approx_mallocs, func, data))
256 return FALSE;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800257
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000258 set_fail_alloc_failures (2);
259 if (!run_failing_each_malloc (approx_mallocs, func, data))
260 return FALSE;
261
262 set_fail_alloc_failures (3);
263 if (!run_failing_each_malloc (approx_mallocs, func, data))
264 return FALSE;
265
266 set_fail_alloc_counter (_TEST_INT_MAX);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800267
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000268 return TRUE;
269}