Print this page
XXXX all calloc() implementations should check overflow
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/rtld/common/malloc.c
+++ new/usr/src/cmd/sgs/rtld/common/malloc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Copyright (c) 1988 AT&T
29 29 * All Rights Reserved
30 30 */
31 31
32 32 /*
33 33 * Simplified version of malloc(), calloc() and free(), to be linked with
34 34 * utilities that use [s]brk() and do not define their own version of the
35 35 * routines.
36 36 * The algorithm maps /dev/zero to get extra memory space.
37 37 * Each call to mmap() creates a page. The pages are linked in a list.
38 38 * Each page is divided in blocks. There is at least one block in a page.
39 39 * New memory chunks are allocated on a first-fit basis.
40 40 * Freed blocks are joined in larger blocks. Free pages are unmapped.
41 41 */
42 42
43 43 #include <stdlib.h>
44 44 #include <sys/types.h>
45 45 #include <sys/mman.h>
46 46 #include <sys/debug.h>
47 47 #include <memory.h>
48 48 #include "_rtld.h"
49 49 #include "msg.h"
50 50
51 51 struct block {
52 52 size_t size; /* Space available for user */
53 53 struct page *page; /* Backwards reference to page */
54 54 int status;
55 55 struct block *next;
56 56 void * memstart[1];
57 57 };
58 58
59 59 struct page {
60 60 size_t size; /* Total page size (incl. header) */
61 61 struct page *next;
62 62 struct block block[1];
63 63 };
64 64
65 65 #define FREE 0
66 66 #define BUSY 1
67 67
68 68 #define HDR_BLOCK (sizeof (struct block) - sizeof (void *))
69 69 #define HDR_PAGE (sizeof (struct page) - sizeof (void *))
70 70
71 71 static struct page *memstart;
72 72
73 73 #if DEBUG
74 74 /*
75 75 * When built for debugging, scribble a pattern over newly allocated and
76 76 * freed memory.
77 77 */
78 78 #define NEWMEM 0
79 79 #define FREMEM 1
80 80
81 81 /* LINTED */
82 82 const ulong_t patterns[] = {
83 83 (ulong_t)0xbaddcafebaddcafeULL, (ulong_t)0xdeadbeefdeadbeefULL
84 84 };
85 85
86 86 static void
87 87 scribble(ulong_t *membgn, int pattern, size_t size)
88 88 {
89 89 size_t memsize = size / sizeof (ulong_t);
90 90
91 91 while (memsize--) {
92 92 if (pattern == FREMEM)
93 93 ASSERT(*membgn != patterns[pattern]);
94 94 *membgn++ = patterns[pattern];
95 95 }
96 96 }
97 97 #endif
98 98
99 99 /*
100 100 * Defragmentation
101 101 */
102 102 void
103 103 defrag()
104 104 {
105 105 struct page *page;
106 106 Aliste idx;
107 107
108 108 for (APLIST_TRAVERSE(free_alp, idx, page)) {
109 109 struct block *block;
110 110
111 111 for (block = page->block; block; block = block->next) {
112 112 struct block *block2;
113 113
114 114 if (block->status == BUSY)
115 115 continue;
116 116 for (block2 = block->next; block2 &&
117 117 block2->status == FREE; block2 = block2->next) {
118 118 block->next = block2->next;
119 119 block->size += block2->size + HDR_BLOCK;
120 120 }
121 121 }
122 122
123 123 /*
124 124 * If a page becomes free, leave it, and save the unmapping
125 125 * expense, as we'll probably come back and reclaim the page
126 126 * for later malloc activity.
127 127 *
128 128 * Free the defrag index.
129 129 */
130 130 aplist_delete(free_alp, &idx);
131 131 }
132 132 }
133 133
134 134 static void
135 135 split(struct block *block, size_t size)
136 136 {
137 137 if (block->size > size + sizeof (struct block)) {
138 138 struct block *newblock;
139 139 /* LINTED */
140 140 newblock = (struct block *)
141 141 ((char *)block + HDR_BLOCK + size);
142 142 newblock->next = block->next;
143 143 block->next = newblock;
144 144 newblock->status = FREE;
145 145 newblock->page = block->page;
146 146 newblock->size = block->size - size - HDR_BLOCK;
147 147 block->size = size;
148 148 }
149 149 }
150 150
151 151 #include <stdio.h>
152 152
153 153 /*
154 154 * Replace both malloc() and lmalloc() (libc's private memory allocator).
155 155 * They are both private here.
156 156 */
157 157 #pragma weak lmalloc = malloc
158 158 void *
159 159 malloc(size_t size)
160 160 {
161 161 struct block *block;
162 162 struct page *page;
163 163
164 164 size = S_DROUND(size);
165 165
166 166 /*
167 167 * Try to locate necessary space
168 168 */
169 169 for (page = memstart; page; page = page->next) {
170 170 for (block = page->block; block; block = block->next) {
171 171 if ((block->status == FREE) && (block->size >= size))
172 172 goto found;
173 173 }
174 174 }
175 175 found:
176 176 /*
177 177 * Need to allocate a new page
178 178 */
179 179 if (!page) {
180 180 size_t totsize = size + HDR_PAGE;
181 181 size_t totpage = S_ROUND(totsize, syspagsz);
182 182
183 183 if ((page = dz_map(0, 0, totpage,
184 184 PROT_READ | PROT_WRITE | PROT_EXEC,
185 185 MAP_PRIVATE)) == MAP_FAILED)
186 186 return (0);
187 187
188 188 page->next = memstart;
189 189 memstart = page;
190 190 page->size = totpage;
191 191 block = page->block;
192 192 block->next = 0;
193 193 block->status = FREE;
194 194 block->size = totpage - HDR_PAGE;
195 195 block->page = page;
196 196 }
197 197
198 198 split(block, size);
199 199 #if DEBUG
↓ open down ↓ |
199 lines elided |
↑ open up ↑ |
200 200 scribble((ulong_t *)&block->memstart, NEWMEM, block->size);
201 201 #endif
202 202 block->status = BUSY;
203 203 return (&block->memstart);
204 204 }
205 205
206 206 void *
207 207 calloc(size_t num, size_t size)
208 208 {
209 209 void * mp;
210 + size_t total;
210 211
211 - num *= size;
212 - if ((mp = malloc(num)) == NULL)
212 + if (num == 0 || size == 0) {
213 + total = 0;
214 + } else {
215 + total = num * size;
216 +
217 + /* check for overflow */
218 + if (total / num != size) {
219 + errno = ENOMEM;
220 + return (NULL);
221 + }
222 + }
223 +
224 + if ((mp = malloc(total)) == NULL)
213 225 return (NULL);
214 - (void) memset(mp, 0, num);
226 + (void) memset(mp, 0, total);
215 227 return (mp);
216 228 }
217 229
218 230 void *
219 231 realloc(void *ptr, size_t size)
220 232 {
221 233 struct block *block;
222 234 size_t osize;
223 235 void * newptr;
224 236
225 237 if (ptr == NULL)
226 238 return (malloc(size));
227 239
228 240 /* LINTED */
229 241 block = (struct block *)((char *)ptr - HDR_BLOCK);
230 242 size = S_DROUND(size);
231 243 osize = block->size;
232 244
233 245 /*
234 246 * Join block with next one if it is free
235 247 */
236 248 if (block->next && block->next->status == FREE) {
237 249 block->size += block->next->size + HDR_BLOCK;
238 250 block->next = block->next->next;
239 251 }
240 252
241 253 if (size <= block->size) {
242 254 split(block, size);
243 255 #if DEBUG
244 256 if (block->size > osize)
245 257 scribble((ulong_t *)((char *)ptr + osize), NEWMEM,
246 258 (block->size - osize));
247 259 #endif
248 260 return (ptr);
249 261 }
250 262
251 263 if ((newptr = malloc(size)) == NULL)
252 264 return (NULL);
253 265 (void) memcpy(newptr, ptr, osize);
254 266 block->status = FREE;
255 267
256 268 /*
257 269 * Add the free block to the free APlist for later defragmentation.
258 270 * However, this addition can only be achieved if there is room on the
259 271 * free APlist. The APlist can't be allowed to grow, as the growth
260 272 * requires a realloc(), which would recurse back here, resulting in an
261 273 * infinite loop. If the free APlist is full, defrag() now. This
262 274 * defragmentation might not be able to collapse any free space, but
263 275 * the free APlist will be cleared as part of the processing, ensuring
264 276 * room for the addition.
265 277 */
266 278 if (free_alp && (aplist_nitems(free_alp) >= aplist_arritems(free_alp)))
267 279 defrag();
268 280 (void) aplist_test(&free_alp, block->page, AL_CNT_FREELIST);
269 281 return (newptr);
270 282 }
271 283
272 284 /*
273 285 * Replace both free() and lfree() (libc's private memory allocator).
274 286 * They are both private here.
275 287 */
276 288 void
277 289 free(void *ptr)
278 290 {
279 291 struct block *block;
280 292
281 293 if (ptr == NULL)
282 294 return;
283 295
284 296 /* LINTED */
285 297 block = (struct block *)((char *)ptr - HDR_BLOCK);
286 298 block->status = FREE;
287 299 #if DEBUG
288 300 scribble((ulong_t *)&block->memstart, FREMEM, block->size);
289 301 #endif
290 302 (void) aplist_test(&free_alp, block->page, AL_CNT_FREELIST);
291 303 }
292 304
293 305 /* ARGSUSED1 */
294 306 void
295 307 lfree(void *ptr, size_t size)
296 308 {
297 309 free(ptr);
298 310 }
299 311
300 312 /*
301 313 * We can use any memory after ld.so.1's .bss up until the next page boundary
302 314 * as allocatable memory.
303 315 */
304 316 void
305 317 addfree(void *ptr, size_t bytes)
306 318 {
307 319 struct block *block;
308 320 struct page *page;
309 321
310 322 if (bytes <= sizeof (struct page))
311 323 return;
312 324 page = ptr;
313 325 page->next = memstart;
314 326 memstart = page;
315 327 page->size = bytes;
316 328 block = page->block;
317 329 block->next = 0;
318 330 block->status = FREE;
319 331 block->size = bytes - HDR_PAGE;
320 332 block->page = page;
321 333 }
↓ open down ↓ |
97 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX