1 /*===========================================================================
2 * Filename : test-gc-protect.c
3 * About : garbage collector protection test
4 *
5 * Copyright (c) 2007-2008 SigScheme Project <uim-en AT googlegroups.com>
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of authors nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
23 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ===========================================================================*/
34
35 #include <sigscheme/config.h>
36
37 #include "sscm-test.h"
38 #include "sigscheme.h"
39 #include "sigschemeinternal.h"
40
41 /* Due to the conservative GC algorithm, an object cannot be detected as "this
42 * object is NOT protected", although "IS protected" can. But since testing
43 * such uncertain unprotected objects helps GC debugging, this file try such
44 * tests iff --enable-debug is specified although they may fail.
45 * -- YamaKen 2008-04-27 */
46 #define TRY_TESTS_THAT_PASS_IN_MOST_CASES SCM_DEBUG
47
48 static ScmObj make_obj(void);
49 static void *make_obj_internal(void *dummy);
50 static void *protected_func(void *arg);
51 static void *var_in_protected_func(void *arg);
52 static void *vars_in_protected_func(void *arg);
53 static void *test_implicit_protection(void *dummy);
54
55 /* To disable GC stack protection, remove scm_call_with_gc_ready_stack() */
56 #undef TST_RUN
57 #define TST_RUN(fn, s, c) (fn(s, c))
58
59 #define N_OBJS 128
60 static ScmObj static_objs[N_OBJS];
61 static ScmObj protected_lst, unprotected_lst;
62
63 static ScmObj
make_obj(void)64 make_obj(void)
65 {
66 return (ScmObj)scm_call_with_gc_ready_stack(make_obj_internal, NULL);
67 }
68
69 static void *
make_obj_internal(void * dummy)70 make_obj_internal(void *dummy)
71 {
72 return (void *)CONS(SCM_FALSE, SCM_FALSE);
73 }
74
75 TST_CASE("scm_gc_protected_contextp()")
76 {
77 TST_TN_FALSE(scm_gc_protected_contextp());
78
79 TST_TN_FALSE(protected_func(NULL));
80 TST_TN_TRUE (scm_call_with_gc_ready_stack(protected_func, NULL));
81 TST_TN_FALSE(protected_func(NULL));
82 }
83
84 static void *
protected_func(void * arg)85 protected_func(void *arg)
86 {
87 return (void *)scm_gc_protected_contextp();
88 }
89
90 TST_CASE("GC stack protection")
91 {
92 TST_TN_FALSE(scm_gc_protected_contextp());
93
94 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
95 TST_TN_FALSE(var_in_protected_func(NULL));
96 #endif
97 TST_TN_TRUE (scm_call_with_gc_ready_stack(var_in_protected_func, NULL));
98 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
99 TST_TN_FALSE(var_in_protected_func(NULL));
100 #endif
101 }
102
103 static void *
var_in_protected_func(void * arg)104 var_in_protected_func(void *arg)
105 {
106 ScmObj obj;
107
108 obj = make_obj();
109 return (void *)scm_gc_protectedp(obj);
110 }
111
112 TST_CASE("GC stack protection for long array")
113 {
114 TST_TN_FALSE(scm_gc_protected_contextp());
115
116 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
117 TST_TN_FALSE(vars_in_protected_func(NULL));
118 #endif
119 TST_TN_TRUE (scm_call_with_gc_ready_stack(vars_in_protected_func, NULL));
120 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
121 TST_TN_FALSE(vars_in_protected_func(NULL));
122 #endif
123 }
124
125 static void *
vars_in_protected_func(void * arg)126 vars_in_protected_func(void *arg)
127 {
128 ScmObj objs[N_OBJS];
129 int i;
130 scm_bool protectedp;
131
132 for (i = 0; i < N_OBJS; i++)
133 objs[i] = make_obj();
134 for (i = 0, protectedp = scm_true; i < N_OBJS; i++)
135 protectedp = protectedp && scm_gc_protectedp(objs[i]);
136
137 return (void *)protectedp;
138 }
139
140 TST_CASE("GC static variable protection")
141 {
142 int i;
143
144 TST_TN_FALSE(scm_gc_protected_contextp());
145
146 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
147 /* unprotected */
148 for (i = 0; i < N_OBJS; i++)
149 static_objs[i] = make_obj();
150 for (i = 0; i < N_OBJS; i++)
151 TST_TN_FALSE(scm_gc_protectedp(static_objs[i]));
152 #endif
153
154 /* protected */
155 for (i = 0; i < N_OBJS; i++) {
156 scm_gc_protect(&static_objs[i]);
157 static_objs[i] = make_obj();
158 }
159 for (i = 0; i < N_OBJS; i++)
160 TST_TN_TRUE(scm_gc_protectedp(static_objs[i]));
161
162 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
163 /* unprotect again */
164 for (i = 0; i < N_OBJS; i++)
165 scm_gc_unprotect(&static_objs[i]);
166 for (i = 0; i < N_OBJS; i++)
167 TST_TN_FALSE(scm_gc_protectedp(static_objs[i]));
168 #endif
169 }
170
171 TST_CASE("GC auto variable protection with scm_gc_protect()")
172 {
173 ScmObj auto_objs[N_OBJS];
174 int i;
175
176 TST_TN_FALSE(scm_gc_protected_contextp());
177
178 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
179 /* unprotected */
180 for (i = 0; i < N_OBJS; i++)
181 auto_objs[i] = make_obj();
182 for (i = 0; i < N_OBJS; i++)
183 TST_TN_FALSE(scm_gc_protectedp(auto_objs[i]));
184 #endif
185
186 /* protected */
187 for (i = 0; i < N_OBJS; i++) {
188 scm_gc_protect(&auto_objs[i]);
189 auto_objs[i] = make_obj();
190 }
191 for (i = 0; i < N_OBJS; i++)
192 TST_TN_TRUE(scm_gc_protectedp(auto_objs[i]));
193
194 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
195 /* unprotect again */
196 for (i = 0; i < N_OBJS; i++)
197 scm_gc_unprotect(&auto_objs[i]);
198 for (i = 0; i < N_OBJS; i++)
199 TST_TN_FALSE(scm_gc_protectedp(auto_objs[i]));
200 #endif
201 }
202
203 static void *
test_implicit_protection(void * dummy)204 test_implicit_protection(void *dummy)
205 {
206 scm_bool result;
207 ScmObj lst;
208
209 lst = LIST_2(SCM_FALSE, SCM_FALSE);
210 unprotected_lst = CDR(lst);
211
212 result = scm_gc_protectedp(lst);
213 /* the cdr is implicitly protected since indirectly referred from the lst */
214 result = result && scm_gc_protectedp(unprotected_lst);
215 /* unlink the indirect reference */
216 lst = SCM_FALSE;
217 /* it makes the variable unprotected */
218 #if 0
219 /* This condition may not be met since the values of unprotected_lst or
220 * lst may be remained in registers */
221 result = result && !scm_gc_protectedp(unprotected_lst);
222 #endif
223
224 return (void *)result;
225 }
226
227 TST_CASE("GC indirect protection via on-heap object reference")
228 {
229 ScmObj lst; /* unprotected */
230
231 TST_TN_FALSE(scm_gc_protected_contextp());
232
233 TST_TN_TRUE (scm_call_with_gc_ready_stack(test_implicit_protection, NULL));
234
235 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
236 /* unprotected lst */
237 lst = LIST_2(SCM_FALSE, SCM_FALSE);
238 unprotected_lst = CDR(lst);
239
240 TST_TN_FALSE(scm_gc_protectedp(lst));
241 TST_TN_FALSE(scm_gc_protectedp(unprotected_lst));
242 lst = SCM_FALSE;
243 TST_TN_FALSE(scm_gc_protectedp(unprotected_lst));
244
245 /* unprotected static lst */
246 protected_lst = LIST_2(SCM_FALSE, SCM_FALSE);
247 unprotected_lst = CDR(protected_lst);
248
249 TST_TN_FALSE(scm_gc_protectedp(protected_lst));
250 TST_TN_FALSE(scm_gc_protectedp(unprotected_lst));
251 lst = SCM_FALSE;
252 TST_TN_FALSE(scm_gc_protectedp(unprotected_lst));
253 #endif
254
255 /* protected static lst */
256 scm_gc_protect(&protected_lst);
257 protected_lst = LIST_2(SCM_FALSE, SCM_FALSE);
258 unprotected_lst = CDR(protected_lst);
259
260 TST_TN_TRUE (scm_gc_protectedp(protected_lst));
261 TST_TN_TRUE (scm_gc_protectedp(unprotected_lst));
262 protected_lst = SCM_FALSE;
263 #if TRY_TESTS_THAT_PASS_IN_MOST_CASES
264 TST_TN_FALSE(scm_gc_protectedp(unprotected_lst));
265 #endif
266 }
267