]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Example torture memory allocator with memory wiping and check for | |
3 | * out-of-bounds writes. | |
4 | * | |
5 | * Allocation structure: | |
6 | * | |
7 | * [ alloc_hdr | red zone before | user area | red zone after ] | |
8 | * | |
9 | * ^ ^ | |
10 | * | `--- pointer returned to Duktape | |
11 | * `--- underlying malloc ptr | |
12 | */ | |
13 | ||
14 | #include "duktape.h" | |
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <string.h> | |
18 | #include <stdint.h> | |
19 | ||
20 | #define RED_ZONE_SIZE 16 | |
21 | #define RED_ZONE_BYTE 0x5a | |
22 | #define INIT_BYTE 0xa5 | |
23 | #define WIPE_BYTE 0x27 | |
24 | ||
25 | typedef struct { | |
26 | /* The double value in the union is there to ensure alignment is | |
27 | * good for IEEE doubles too. In many 32-bit environments 4 bytes | |
28 | * would be sufficiently aligned and the double value is unnecessary. | |
29 | */ | |
30 | union { | |
31 | size_t sz; | |
32 | double d; | |
33 | } u; | |
34 | } alloc_hdr; | |
35 | ||
36 | static void check_red_zone(alloc_hdr *hdr) { | |
37 | size_t size; | |
38 | int i; | |
39 | int err; | |
40 | unsigned char *p; | |
41 | unsigned char *userptr; | |
42 | ||
43 | size = hdr->u.sz; | |
44 | userptr = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE; | |
45 | ||
46 | err = 0; | |
47 | p = (unsigned char *) hdr + sizeof(alloc_hdr); | |
48 | for (i = 0; i < RED_ZONE_SIZE; i++) { | |
49 | if (p[i] != RED_ZONE_BYTE) { | |
50 | err = 1; | |
51 | } | |
52 | } | |
53 | if (err) { | |
54 | fprintf(stderr, "RED ZONE CORRUPTED BEFORE ALLOC: hdr=%p ptr=%p size=%ld\n", | |
55 | (void *) hdr, (void *) userptr, (long) size); | |
56 | fflush(stderr); | |
57 | } | |
58 | ||
59 | err = 0; | |
60 | p = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE + size; | |
61 | for (i = 0; i < RED_ZONE_SIZE; i++) { | |
62 | if (p[i] != RED_ZONE_BYTE) { | |
63 | err = 1; | |
64 | } | |
65 | } | |
66 | if (err) { | |
67 | fprintf(stderr, "RED ZONE CORRUPTED AFTER ALLOC: hdr=%p ptr=%p size=%ld\n", | |
68 | (void *) hdr, (void *) userptr, (long) size); | |
69 | fflush(stderr); | |
70 | } | |
71 | } | |
72 | ||
73 | void *duk_alloc_torture(void *udata, duk_size_t size) { | |
74 | unsigned char *p; | |
75 | ||
76 | (void) udata; /* Suppress warning. */ | |
77 | ||
78 | if (size == 0) { | |
79 | return NULL; | |
80 | } | |
81 | ||
82 | p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
83 | if (!p) { | |
84 | return NULL; | |
85 | } | |
86 | ||
87 | ((alloc_hdr *) (void *) p)->u.sz = size; | |
88 | p += sizeof(alloc_hdr); | |
89 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
90 | p += RED_ZONE_SIZE; | |
91 | memset((void *) p, INIT_BYTE, size); | |
92 | p += size; | |
93 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
94 | p -= size; | |
95 | return (void *) p; | |
96 | } | |
97 | ||
98 | void *duk_realloc_torture(void *udata, void *ptr, duk_size_t size) { | |
99 | unsigned char *p, *old_p; | |
100 | size_t old_size; | |
101 | ||
102 | (void) udata; /* Suppress warning. */ | |
103 | ||
104 | /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize | |
105 | * platform assumptions. You can get away with much less in specific | |
106 | * well-behaving environments. | |
107 | */ | |
108 | ||
109 | if (ptr) { | |
110 | old_p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE; | |
111 | old_size = ((alloc_hdr *) (void *) old_p)->u.sz; | |
112 | check_red_zone((alloc_hdr *) (void *) old_p); | |
113 | ||
114 | if (size == 0) { | |
115 | memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
116 | free((void *) old_p); | |
117 | return NULL; | |
118 | } else { | |
119 | /* Force address change on every realloc. */ | |
120 | p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
121 | if (!p) { | |
122 | return NULL; | |
123 | } | |
124 | ||
125 | ((alloc_hdr *) (void *) p)->u.sz = size; | |
126 | p += sizeof(alloc_hdr); | |
127 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
128 | p += RED_ZONE_SIZE; | |
129 | if (size > old_size) { | |
130 | memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), old_size); | |
131 | memset((void *) (p + old_size), INIT_BYTE, size - old_size); | |
132 | } else { | |
133 | memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), size); | |
134 | } | |
135 | p += size; | |
136 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
137 | p -= size; | |
138 | ||
139 | memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
140 | free((void *) old_p); | |
141 | ||
142 | return (void *) p; | |
143 | } | |
144 | } else { | |
145 | if (size == 0) { | |
146 | return NULL; | |
147 | } else { | |
148 | p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
149 | if (!p) { | |
150 | return NULL; | |
151 | } | |
152 | ||
153 | ((alloc_hdr *) (void *) p)->u.sz = size; | |
154 | p += sizeof(alloc_hdr); | |
155 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
156 | p += RED_ZONE_SIZE; | |
157 | memset((void *) p, INIT_BYTE, size); | |
158 | p += size; | |
159 | memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); | |
160 | p -= size; | |
161 | return (void *) p; | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
166 | void duk_free_torture(void *udata, void *ptr) { | |
167 | unsigned char *p; | |
168 | size_t old_size; | |
169 | ||
170 | (void) udata; /* Suppress warning. */ | |
171 | ||
172 | if (!ptr) { | |
173 | return; | |
174 | } | |
175 | ||
176 | p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE; | |
177 | old_size = ((alloc_hdr *) (void *) p)->u.sz; | |
178 | ||
179 | check_red_zone((alloc_hdr *) (void *) p); | |
180 | memset((void *) p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); | |
181 | free((void *) p); | |
182 | } |