BRANCH release for 2.5.x critical patches
[baserock-morphs:libxml2.git] / testOOMlib.c
1 /*
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
31 static int fail_alloc_counter = _TEST_INT_MAX;
32 static int n_failures_per_failure = 1;
33 static int n_failures_this_failure = 0;
34 static int n_blocks_outstanding = 0;
35
36 /**
37  * Sets the number of allocations until we simulate a failed
38  * allocation. If set to 0, the next allocation to run
39  * fails; if set to 1, one succeeds then the next fails; etc.
40  * Set to _TEST_INT_MAX to not fail anything. 
41  *
42  * @param until_next_fail number of successful allocs before one fails
43  */
44 static void
45 set_fail_alloc_counter (int until_next_fail)
46 {
47   fail_alloc_counter = until_next_fail;
48 }
49
50 /**
51  * Gets the number of successful allocs until we'll simulate
52  * a failed alloc.
53  *
54  * @returns current counter value
55  */
56 static int
57 get_fail_alloc_counter (void)
58 {
59   return fail_alloc_counter;
60 }
61
62 /**
63  * Sets how many mallocs to fail when the fail alloc counter reaches
64  * 0.
65  *
66  * @param number to fail
67  */
68 static void
69 set_fail_alloc_failures (int failures_per_failure)
70 {
71   n_failures_per_failure = failures_per_failure;
72 }
73
74 /**
75  * Called when about to alloc some memory; if
76  * it returns #TRUE, then the allocation should
77  * fail. If it returns #FALSE, then the allocation
78  * should not fail.
79  *
80  * @returns #TRUE if this alloc should fail
81  */
82 static int
83 decrement_fail_alloc_counter (void)
84 {
85   if (fail_alloc_counter <= 0)
86     {
87       n_failures_this_failure += 1;
88       if (n_failures_this_failure >= n_failures_per_failure)
89         {
90           fail_alloc_counter = _TEST_INT_MAX;
91
92           n_failures_this_failure = 0;
93         }
94       
95       return TRUE;
96     }
97   else
98     {
99       fail_alloc_counter -= 1;
100       return FALSE;
101     }
102 }
103
104 /**
105  * Get the number of outstanding malloc()'d blocks.
106  *
107  * @returns number of blocks
108  */
109 int
110 test_get_malloc_blocks_outstanding (void)
111 {
112   return n_blocks_outstanding;
113 }
114
115 void*
116 test_malloc (size_t bytes)
117 {  
118   if (decrement_fail_alloc_counter ())
119     {
120       /* FAIL the malloc */
121       return NULL;
122     }
123   
124   if (bytes == 0) /* some system mallocs handle this, some don't */
125     return NULL;
126   else
127     {
128       void *mem;
129       mem = xmlMemMalloc (bytes);
130
131       if (mem)
132         n_blocks_outstanding += 1;
133
134       return mem;
135     }
136 }
137
138 void*
139 test_realloc (void  *memory,
140               size_t bytes)
141 {
142   if (decrement_fail_alloc_counter ())
143     {
144       /* FAIL */
145       return NULL;
146     }
147   
148   if (bytes == 0) /* guarantee this is safe */
149     {
150       test_free (memory);
151       return NULL;
152     }
153   else
154     {
155       void *mem;
156       mem = xmlMemRealloc (memory, bytes);
157
158       if (memory == NULL && mem != NULL)
159         n_blocks_outstanding += 1;
160
161       return mem;
162     }
163 }
164
165 void
166 test_free (void  *memory)
167 {
168   if (memory) /* we guarantee it's safe to free (NULL) */
169     {
170       n_blocks_outstanding -= 1;
171
172       xmlMemFree (memory);
173     }
174 }
175
176 char*
177 test_strdup (const char *str)
178 {
179   int len;
180   char *copy;
181   
182   if (str == NULL)
183     return NULL;
184   
185   len = strlen (str);
186
187   copy = test_malloc (len + 1);
188   if (copy == NULL)
189     return NULL;
190
191   memcpy (copy, str, len + 1);
192   
193   return copy;
194 }
195
196 static int
197 run_failing_each_malloc (int                n_mallocs,
198                          TestMemoryFunction func,
199                          void              *data)
200 {
201   n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
202   
203   while (n_mallocs >= 0)
204     {      
205       set_fail_alloc_counter (n_mallocs);
206
207       if (!(* func) (data))
208         return FALSE;
209       
210       n_mallocs -= 1;
211     }
212
213   set_fail_alloc_counter (_TEST_INT_MAX);
214
215   return TRUE;
216 }
217
218 /**
219  * Tests how well the given function responds to out-of-memory
220  * situations. Calls the function repeatedly, failing a different
221  * call to malloc() each time. If the function ever returns #FALSE,
222  * the test fails. The function should return #TRUE whenever something
223  * valid (such as returning an error, or succeeding) occurs, and #FALSE
224  * if it gets confused in some way.
225  *
226  * @param func function to call
227  * @param data data to pass to function
228  * @returns #TRUE if the function never returns FALSE
229  */
230 int
231 test_oom_handling (TestMemoryFunction  func,
232                    void               *data)
233 {
234   int approx_mallocs;
235
236   /* Run once to see about how many mallocs are involved */
237   
238   set_fail_alloc_counter (_TEST_INT_MAX);
239
240   if (!(* func) (data))
241     return FALSE;
242
243   approx_mallocs = _TEST_INT_MAX - get_fail_alloc_counter ();
244
245   set_fail_alloc_failures (1);
246   if (!run_failing_each_malloc (approx_mallocs, func, data))
247     return FALSE;
248   
249   set_fail_alloc_failures (2);
250   if (!run_failing_each_malloc (approx_mallocs, func, data))
251     return FALSE;
252
253   set_fail_alloc_failures (3);
254   if (!run_failing_each_malloc (approx_mallocs, func, data))
255     return FALSE;
256
257   set_fail_alloc_counter (_TEST_INT_MAX);
258   
259   return TRUE;
260 }