Skip to content

Commit 9e3010f

Browse files
committed
Added test for GitHub issue Ravenbrook#306
Note that it does not currently compile on recent GCC versions due to issue Ravenbrook#302.
1 parent 9fd0577 commit 9e3010f

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

test/function/238.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
TEST_HEADER
3+
id = $Id$
4+
summary = regression test for GitHub issue #306
5+
language = c
6+
link = testlib.o newfmt.o
7+
parameters =
8+
END_HEADER
9+
*/
10+
11+
#include "testlib.h"
12+
13+
#if MPS_WORD_WIDTH > 32
14+
15+
#include "mpsavm.h"
16+
#include "mpscamc.h"
17+
#include "newfmt.h"
18+
19+
#include <stdio.h>
20+
21+
/* On UNIX systems, the protection ProtSet in code/protix.c contained
22+
* an assert that AddrOffset(base, limit) <= INT_MAX (also with the
23+
* comment "should be redundant". An allocation larger than INT_MAX
24+
* therefore triggers the assert, even though the MPS happily allows
25+
* the allocation otherwise.
26+
*
27+
* Note that this is only a problem on platforms where sizeof(int) <
28+
* sizeof(size_t). If sizeof(int) == sizeof(size_t) then everything
29+
* works as expected.
30+
*
31+
* To trigger the assertion, it is usually enough to just ask the MPS
32+
* to do a garbage collection cycle.
33+
*
34+
* As such, this test simply allocates a large block of memory and
35+
* forces the MPS to do a collection. The test is enabled for other
36+
* 64-bit platforms to detect other potential problems there as well.
37+
*/
38+
39+
/* Number of allocations to do to encourage a collection. */
40+
#define NUM_ALLOCS 1000
41+
42+
/* Number of times to allocate objects with a mps_arena_step in
43+
* between. */
44+
#define NUM_STEPS 2
45+
46+
/* Allocate an object that is >= 2 GiB. In a separate function to avoid
47+
* accidentally pinning the pointer to the large object just in case. */
48+
static void create_large(mps_ap_t ap, mycell *store)
49+
{
50+
mycell *created;
51+
/* Allocate an object with a size that overflows a signed 32-bit integer. */
52+
size_t target_bytes = 0x80000000;
53+
/* This is not exact, which is why there is a slight margin. */
54+
size_t elements = (target_bytes / sizeof(struct refitem)) + 1;
55+
/* Make sure the number of elements fits in the int in newfmt. */
56+
asserts(elements < INT_MAX, "INT_MAX is too small");
57+
58+
created = allocone(ap, (int)elements);
59+
60+
/* Add some pointers to make the MPS try to protect the object. */
61+
setref(created, 0, created);
62+
setref(created, 1, store);
63+
64+
/* Store it in 'store' so that it is kept alive. */
65+
setref(store, 0, created);
66+
}
67+
68+
69+
static void test(void *stack_pointer)
70+
{
71+
mps_arena_t arena;
72+
mps_fmt_t format;
73+
mps_pool_t pool;
74+
mps_thr_t thread;
75+
mps_root_t root;
76+
mps_chain_t chain;
77+
mps_ap_t ap;
78+
79+
mycell *object;
80+
81+
int i, j;
82+
83+
mps_gen_param_s gen_params[2] = {
84+
{ 512, 0.9 },
85+
{ 10 * 1024, 0.5 }
86+
};
87+
88+
die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), "mps_arena_create_k");
89+
die(mps_fmt_create_A(&format, arena, &fmtA), "create format");
90+
die(mps_chain_create(&chain, arena, 2, gen_params), "mps_chain_create");
91+
die(mps_thread_reg(&thread, arena), "mps_thread_reg");
92+
die(mps_root_create_thread(&root, arena, thread, stack_pointer), "mps_root_create_thread");
93+
MPS_ARGS_BEGIN(args) {
94+
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format);
95+
MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
96+
die(mps_pool_create_k(&pool, arena, mps_class_amc(), args), "mps_pool_create_k");
97+
} MPS_ARGS_END(args);
98+
99+
die(mps_ap_create_k(&ap, pool, mps_args_none), "mps_ap_create_k");
100+
101+
/* Allocate an object that we store the big object inside. To make
102+
* it less likely that pinning it affects how the MPS behaves. */
103+
object = allocone(ap, 1);
104+
create_large(ap, object);
105+
106+
/* Allocate some other objects and ask for a small amount of
107+
* collection work. This to encourage the MPS to raise a barrier on
108+
* the large allocation. */
109+
for (i = 0; i < NUM_STEPS; i++) {
110+
for (j = 0; j < NUM_ALLOCS; j++)
111+
allocone(ap, 100);
112+
113+
/* Ask the MPS to do a small amount of GC work. */
114+
mps_arena_step(arena, 0.0001, 10000);
115+
}
116+
117+
/* Tear down MPS data structures. */
118+
mps_arena_park(arena);
119+
mps_ap_destroy(ap);
120+
mps_root_destroy(root);
121+
mps_thread_dereg(thread);
122+
mps_pool_destroy(pool);
123+
mps_chain_destroy(chain);
124+
mps_fmt_destroy(format);
125+
mps_arena_destroy(arena);
126+
}
127+
128+
#else
129+
130+
static void test(void *stack_pointer)
131+
{
132+
/* nothing to do on 32-bit systems */
133+
}
134+
135+
#endif
136+
137+
int main(void)
138+
{
139+
run_test(test);
140+
pass();
141+
return 0;
142+
}

0 commit comments

Comments
 (0)