more tests
[tinycc.git] / bcheck.c
blob01e98ff4c37063e57d14c12e81145544ae12c57d
1 /*
2 * Tiny C Memory and bounds checker
3 *
4 * Copyright (c) 2002 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <malloc.h>
26 //#define BOUND_DEBUG
28 /* define so that bound array is static (faster, but use memory if
29 bound checking not used) */
30 //#define BOUND_STATIC
32 /* use malloc hooks. Currently the code cannot be reliable if no hooks */
33 #define CONFIG_TCC_MALLOC_HOOKS
35 #define BOUND_T1_BITS 13
36 #define BOUND_T2_BITS 11
37 #define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
39 #define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
40 #define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
41 #define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
42 #define BOUND_E_BITS 4
44 #define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
45 #define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
48 /* this pointer is generated when bound check is incorrect */
49 #define INVALID_POINTER ((void *)(-2))
50 /* size of an empty region */
51 #define EMPTY_SIZE 0xffffffff
52 /* size of an invalid region */
53 #define INVALID_SIZE 0
55 typedef struct BoundEntry {
56 unsigned long start;
57 unsigned long size;
58 struct BoundEntry *next;
59 unsigned long is_invalid; /* true if pointers outside region are invalid */
60 } BoundEntry;
62 /* external interface */
63 void __bound_init(void);
64 void __bound_new_region(void *p, unsigned long size);
65 int __bound_delete_region(void *p);
67 /* currently, tcc cannot compile that because we use unsupported GNU C
68 extensions */
69 #if !defined(__TINYC__)
70 void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
71 void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
72 void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
73 void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
74 void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
75 void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
76 void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
77 void __bound_local_new(void *p) __attribute__((regparm(1)));
78 void __bound_local_delete(void *p) __attribute__((regparm(1)));
79 #endif
80 static void *get_caller_pc(int n);
82 void *__bound_malloc(size_t size, const void *caller);
83 void *__bound_memalign(size_t size, size_t align, const void *caller);
84 void __bound_free(void *ptr, const void *caller);
85 void *__bound_realloc(void *ptr, size_t size, const void *caller);
86 static void *libc_malloc(size_t size);
87 static void libc_free(void *ptr);
88 static void install_malloc_hooks(void);
89 static void restore_malloc_hooks(void);
91 #ifdef CONFIG_TCC_MALLOC_HOOKS
92 static void *saved_malloc_hook;
93 static void *saved_free_hook;
94 static void *saved_realloc_hook;
95 static void *saved_memalign_hook;
96 #endif
98 extern char _end;
100 /* TCC defines: */
101 extern char __bounds_start; /* start of static bounds table */
102 /* runtime error output */
103 extern void rt_error(unsigned long pc, const char *fmt, ...);
105 #ifdef BOUND_STATIC
106 static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
107 #else
108 static BoundEntry **__bound_t1; /* page table */
109 #endif
110 static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
111 static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
113 static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
115 unsigned long addr, tmp;
116 BoundEntry *e;
118 e = e1;
119 while (e != NULL) {
120 addr = (unsigned long)p;
121 addr -= e->start;
122 if (addr <= e->size) {
123 /* put region at the head */
124 tmp = e1->start;
125 e1->start = e->start;
126 e->start = tmp;
127 tmp = e1->size;
128 e1->size = e->size;
129 e->size = tmp;
130 return e1;
132 e = e->next;
134 /* no entry found: return empty entry or invalid entry */
135 if (e1->is_invalid)
136 return __bound_invalid_t2;
137 else
138 return __bound_empty_t2;
141 /* print a bound error message */
142 static void bound_error(const void *caller, const char *fmt, ...)
144 rt_error((unsigned long)caller, "%s", fmt);
147 static void bound_alloc_error(void)
149 bound_error(NULL, "not enough memory for bound checking code");
152 /* currently, tcc cannot compile that because we use GNUC extensions */
153 #if !defined(__TINYC__)
155 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
156 the end of a region in this case */
157 void *__bound_ptr_add(void *p, int offset)
159 unsigned long addr = (unsigned long)p;
160 BoundEntry *e;
161 #if defined(BOUND_DEBUG)
162 printf("add: 0x%x %d\n", (int)p, offset);
163 #endif
165 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
166 e = (BoundEntry *)((char *)e +
167 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
168 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
169 addr -= e->start;
170 if (addr > e->size) {
171 e = __bound_find_region(e, p);
172 addr = (unsigned long)p - e->start;
174 addr += offset;
175 if (addr > e->size)
176 return INVALID_POINTER; /* return an invalid pointer */
177 return p + offset;
180 /* return '(p + offset)' for pointer indirection (the resulting must
181 be strictly inside the region */
182 #define BOUND_PTR_INDIR(dsize) \
183 void *__bound_ptr_indir ## dsize (void *p, int offset) \
185 unsigned long addr = (unsigned long)p; \
186 BoundEntry *e; \
188 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
189 e = (BoundEntry *)((char *)e + \
190 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
191 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
192 addr -= e->start; \
193 if (addr > e->size) { \
194 e = __bound_find_region(e, p); \
195 addr = (unsigned long)p - e->start; \
197 addr += offset + dsize; \
198 if (addr > e->size) \
199 return INVALID_POINTER; /* return an invalid pointer */ \
200 return p + offset; \
203 #ifdef __i386__
205 /* return the PC of the N'th caller (N=1: first caller) */
206 static void *get_caller_pc(int n)
208 unsigned long fp;
209 int i;
211 __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp));
212 for(i=0;i<n;i++)
213 fp = ((unsigned long *)fp)[0];
214 return ((void **)fp)[1];
217 /* return the frame pointer of the caller */
218 #define GET_CALLER_FP(fp)\
220 unsigned long *fp1;\
221 __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
222 fp = fp1[0];\
224 #else
225 #error put code to extract the calling frame pointer
226 #endif
228 /* called when entering a function to add all the local regions */
229 void __bound_local_new(void *p1)
231 unsigned long addr, size, fp, *p = p1;
232 GET_CALLER_FP(fp);
233 for(;;) {
234 addr = p[0];
235 if (addr == 0)
236 break;
237 addr += fp;
238 size = p[1];
239 p += 2;
240 __bound_new_region((void *)addr, size);
244 /* called when leaving a function to delete all the local regions */
245 void __bound_local_delete(void *p1)
247 unsigned long addr, fp, *p = p1;
248 GET_CALLER_FP(fp);
249 for(;;) {
250 addr = p[0];
251 if (addr == 0)
252 break;
253 addr += fp;
254 p += 2;
255 __bound_delete_region((void *)addr);
259 #else
261 void __bound_local_new(void *p)
264 void __bound_local_delete(void *p)
268 void *__bound_ptr_add(void *p, int offset)
270 return p + offset;
273 #define BOUND_PTR_INDIR(dsize) \
274 void *__bound_ptr_indir ## dsize (void *p, int offset) \
276 return p + offset; \
279 static void *get_caller_pc(int n)
281 return 0;
283 #endif
285 BOUND_PTR_INDIR(1)
286 BOUND_PTR_INDIR(2)
287 BOUND_PTR_INDIR(4)
288 BOUND_PTR_INDIR(8)
289 BOUND_PTR_INDIR(12)
290 BOUND_PTR_INDIR(16)
292 static BoundEntry *__bound_new_page(void)
294 BoundEntry *page;
295 int i;
297 page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
298 if (!page)
299 bound_alloc_error();
300 for(i=0;i<BOUND_T2_SIZE;i++) {
301 /* put empty entries */
302 page[i].start = 0;
303 page[i].size = EMPTY_SIZE;
304 page[i].next = NULL;
305 page[i].is_invalid = 0;
307 return page;
310 /* currently we use malloc(). Should use bound_new_page() */
311 static BoundEntry *bound_new_entry(void)
313 BoundEntry *e;
314 e = libc_malloc(sizeof(BoundEntry));
315 return e;
318 static void bound_free_entry(BoundEntry *e)
320 libc_free(e);
323 static inline BoundEntry *get_page(int index)
325 BoundEntry *page;
326 page = __bound_t1[index];
327 if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
328 /* create a new page if necessary */
329 page = __bound_new_page();
330 __bound_t1[index] = page;
332 return page;
335 /* mark a region as being invalid (can only be used during init) */
336 static void mark_invalid(unsigned long addr, unsigned long size)
338 unsigned long start, end;
339 BoundEntry *page;
340 int t1_start, t1_end, i, j, t2_start, t2_end;
342 start = addr;
343 end = addr + size;
345 t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
346 if (end != 0)
347 t2_end = end >> BOUND_T3_BITS;
348 else
349 t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
351 #if 0
352 printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
353 #endif
355 /* first we handle full pages */
356 t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
357 t1_end = t2_end >> BOUND_T2_BITS;
359 i = t2_start & (BOUND_T2_SIZE - 1);
360 j = t2_end & (BOUND_T2_SIZE - 1);
362 if (t1_start == t1_end) {
363 page = get_page(t2_start >> BOUND_T2_BITS);
364 for(; i < j; i++) {
365 page[i].size = INVALID_SIZE;
366 page[i].is_invalid = 1;
368 } else {
369 if (i > 0) {
370 page = get_page(t2_start >> BOUND_T2_BITS);
371 for(; i < BOUND_T2_SIZE; i++) {
372 page[i].size = INVALID_SIZE;
373 page[i].is_invalid = 1;
376 for(i = t1_start; i < t1_end; i++) {
377 __bound_t1[i] = __bound_invalid_t2;
379 if (j != 0) {
380 page = get_page(t1_end);
381 for(i = 0; i < j; i++) {
382 page[i].size = INVALID_SIZE;
383 page[i].is_invalid = 1;
389 void __bound_init(void)
391 int i;
392 BoundEntry *page;
393 unsigned long start, size;
394 int *p;
396 /* save malloc hooks and install bound check hooks */
397 install_malloc_hooks();
399 #ifndef BOUND_STATIC
400 __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
401 if (!__bound_t1)
402 bound_alloc_error();
403 #endif
404 __bound_empty_t2 = __bound_new_page();
405 for(i=0;i<BOUND_T1_SIZE;i++) {
406 __bound_t1[i] = __bound_empty_t2;
409 page = __bound_new_page();
410 for(i=0;i<BOUND_T2_SIZE;i++) {
411 /* put invalid entries */
412 page[i].start = 0;
413 page[i].size = INVALID_SIZE;
414 page[i].next = NULL;
415 page[i].is_invalid = 1;
417 __bound_invalid_t2 = page;
419 /* invalid pointer zone */
420 start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
421 size = BOUND_T23_SIZE;
422 mark_invalid(start, size);
424 #if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
425 /* malloc zone is also marked invalid. can only use that with
426 hooks because all libs should use the same malloc. The solution
427 would be to build a new malloc for tcc. */
428 start = (unsigned long)&_end;
429 size = 128 * 0x100000;
430 mark_invalid(start, size);
431 #endif
433 /* add all static bound check values */
434 p = (int *)&__bounds_start;
435 while (p[0] != 0) {
436 __bound_new_region((void *)p[0], p[1]);
437 p += 2;
441 static inline void add_region(BoundEntry *e,
442 unsigned long start, unsigned long size)
444 BoundEntry *e1;
445 if (e->start == 0) {
446 /* no region : add it */
447 e->start = start;
448 e->size = size;
449 } else {
450 /* already regions in the list: add it at the head */
451 e1 = bound_new_entry();
452 e1->start = e->start;
453 e1->size = e->size;
454 e1->next = e->next;
455 e->start = start;
456 e->size = size;
457 e->next = e1;
461 /* create a new region. It should not already exist in the region list */
462 void __bound_new_region(void *p, unsigned long size)
464 unsigned long start, end;
465 BoundEntry *page, *e, *e2;
466 int t1_start, t1_end, i, t2_start, t2_end;
468 start = (unsigned long)p;
469 end = start + size;
470 t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
471 t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
473 /* start */
474 page = get_page(t1_start);
475 t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
476 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
477 t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
478 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
479 #ifdef BOUND_DEBUG
480 printf("new %lx %lx %x %x %x %x\n",
481 start, end, t1_start, t1_end, t2_start, t2_end);
482 #endif
484 e = (BoundEntry *)((char *)page + t2_start);
485 add_region(e, start, size);
487 if (t1_end == t1_start) {
488 /* same ending page */
489 e2 = (BoundEntry *)((char *)page + t2_end);
490 if (e2 > e) {
491 e++;
492 for(;e<e2;e++) {
493 e->start = start;
494 e->size = size;
496 add_region(e, start, size);
498 } else {
499 /* mark until end of page */
500 e2 = page + BOUND_T2_SIZE;
501 e++;
502 for(;e<e2;e++) {
503 e->start = start;
504 e->size = size;
506 /* mark intermediate pages, if any */
507 for(i=t1_start+1;i<t1_end;i++) {
508 page = get_page(i);
509 e2 = page + BOUND_T2_SIZE;
510 for(e=page;e<e2;e++) {
511 e->start = start;
512 e->size = size;
515 /* last page */
516 page = get_page(t1_end);
517 e2 = (BoundEntry *)((char *)page + t2_end);
518 for(e=page;e<e2;e++) {
519 e->start = start;
520 e->size = size;
522 add_region(e, start, size);
526 /* delete a region */
527 static inline void delete_region(BoundEntry *e,
528 void *p, unsigned long empty_size)
530 unsigned long addr;
531 BoundEntry *e1;
533 addr = (unsigned long)p;
534 addr -= e->start;
535 if (addr <= e->size) {
536 /* region found is first one */
537 e1 = e->next;
538 if (e1 == NULL) {
539 /* no more region: mark it empty */
540 e->start = 0;
541 e->size = empty_size;
542 } else {
543 /* copy next region in head */
544 e->start = e1->start;
545 e->size = e1->size;
546 e->next = e1->next;
547 bound_free_entry(e1);
549 } else {
550 /* find the matching region */
551 for(;;) {
552 e1 = e;
553 e = e->next;
554 /* region not found: do nothing */
555 if (e == NULL)
556 break;
557 addr = (unsigned long)p - e->start;
558 if (addr <= e->size) {
559 /* found: remove entry */
560 e1->next = e->next;
561 bound_free_entry(e);
562 break;
568 /* WARNING: 'p' must be the starting point of the region. */
569 /* return non zero if error */
570 int __bound_delete_region(void *p)
572 unsigned long start, end, addr, size, empty_size;
573 BoundEntry *page, *e, *e2;
574 int t1_start, t1_end, t2_start, t2_end, i;
576 start = (unsigned long)p;
577 t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
578 t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
579 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
581 /* find region size */
582 page = __bound_t1[t1_start];
583 e = (BoundEntry *)((char *)page + t2_start);
584 addr = start - e->start;
585 if (addr > e->size)
586 e = __bound_find_region(e, p);
587 /* test if invalid region */
588 if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
589 return -1;
590 /* compute the size we put in invalid regions */
591 if (e->is_invalid)
592 empty_size = INVALID_SIZE;
593 else
594 empty_size = EMPTY_SIZE;
595 size = e->size;
596 end = start + size;
598 /* now we can free each entry */
599 t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
600 t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
601 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
603 delete_region(e, p, empty_size);
604 if (t1_end == t1_start) {
605 /* same ending page */
606 e2 = (BoundEntry *)((char *)page + t2_end);
607 if (e2 > e) {
608 e++;
609 for(;e<e2;e++) {
610 e->start = 0;
611 e->size = empty_size;
613 delete_region(e, p, empty_size);
615 } else {
616 /* mark until end of page */
617 e2 = page + BOUND_T2_SIZE;
618 e++;
619 for(;e<e2;e++) {
620 e->start = 0;
621 e->size = empty_size;
623 /* mark intermediate pages, if any */
624 /* XXX: should free them */
625 for(i=t1_start+1;i<t1_end;i++) {
626 page = get_page(i);
627 e2 = page + BOUND_T2_SIZE;
628 for(e=page;e<e2;e++) {
629 e->start = 0;
630 e->size = empty_size;
633 /* last page */
634 page = get_page(t2_end);
635 e2 = (BoundEntry *)((char *)page + t2_end);
636 for(e=page;e<e2;e++) {
637 e->start = 0;
638 e->size = empty_size;
640 delete_region(e, p, empty_size);
642 return 0;
645 /* return the size of the region starting at p, or EMPTY_SIZE if non
646 existant region. */
647 static unsigned long get_region_size(void *p)
649 unsigned long addr = (unsigned long)p;
650 BoundEntry *e;
652 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
653 e = (BoundEntry *)((char *)e +
654 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
655 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
656 addr -= e->start;
657 if (addr > e->size)
658 e = __bound_find_region(e, p);
659 if (e->start != (unsigned long)p)
660 return EMPTY_SIZE;
661 return e->size;
664 /* patched memory functions */
666 static void install_malloc_hooks(void)
668 #ifdef CONFIG_TCC_MALLOC_HOOKS
669 saved_malloc_hook = __malloc_hook;
670 saved_free_hook = __free_hook;
671 saved_realloc_hook = __realloc_hook;
672 saved_memalign_hook = __memalign_hook;
673 __malloc_hook = __bound_malloc;
674 __free_hook = __bound_free;
675 __realloc_hook = __bound_realloc;
676 __memalign_hook = __bound_memalign;
677 #endif
680 static void restore_malloc_hooks(void)
682 #ifdef CONFIG_TCC_MALLOC_HOOKS
683 __malloc_hook = saved_malloc_hook;
684 __free_hook = saved_free_hook;
685 __realloc_hook = saved_realloc_hook;
686 __memalign_hook = saved_memalign_hook;
687 #endif
690 static void *libc_malloc(size_t size)
692 void *ptr;
693 restore_malloc_hooks();
694 ptr = malloc(size);
695 install_malloc_hooks();
696 return ptr;
699 static void libc_free(void *ptr)
701 restore_malloc_hooks();
702 free(ptr);
703 install_malloc_hooks();
706 /* XXX: we should use a malloc which ensure that it is unlikely that
707 two malloc'ed data have the same address if 'free' are made in
708 between. */
709 void *__bound_malloc(size_t size, const void *caller)
711 void *ptr;
713 /* we allocate one more byte to ensure the regions will be
714 separated by at least one byte. With the glibc malloc, it may
715 be in fact not necessary */
716 ptr = libc_malloc(size + 1);
718 if (!ptr)
719 return NULL;
720 __bound_new_region(ptr, size);
721 return ptr;
724 void *__bound_memalign(size_t size, size_t align, const void *caller)
726 void *ptr;
728 restore_malloc_hooks();
730 /* we allocate one more byte to ensure the regions will be
731 separated by at least one byte. With the glibc malloc, it may
732 be in fact not necessary */
733 ptr = memalign(size + 1, align);
735 install_malloc_hooks();
737 if (!ptr)
738 return NULL;
739 __bound_new_region(ptr, size);
740 return ptr;
743 void __bound_free(void *ptr, const void *caller)
745 if (ptr == NULL)
746 return;
747 if (__bound_delete_region(ptr) != 0)
748 bound_error(caller, "freeing invalid region");
750 libc_free(ptr);
753 void *__bound_realloc(void *ptr, size_t size, const void *caller)
755 void *ptr1;
756 int old_size;
758 if (size == 0) {
759 __bound_free(ptr, caller);
760 return NULL;
761 } else {
762 ptr1 = __bound_malloc(size, caller);
763 if (ptr == NULL || ptr1 == NULL)
764 return ptr1;
765 old_size = get_region_size(ptr);
766 if (old_size == EMPTY_SIZE)
767 bound_error(caller, "realloc'ing invalid pointer");
768 memcpy(ptr1, ptr, old_size);
769 __bound_free(ptr, caller);
770 return ptr1;
774 #ifndef CONFIG_TCC_MALLOC_HOOKS
775 void *__bound_calloc(size_t nmemb, size_t size)
777 void *ptr;
778 size = size * nmemb;
779 ptr = __bound_malloc(size);
780 if (!ptr)
781 return NULL;
782 memset(ptr, 0, size);
783 return ptr;
785 #endif
787 #if 0
788 static void bound_dump(void)
790 BoundEntry *page, *e;
791 int i, j;
793 printf("region dump:\n");
794 for(i=0;i<BOUND_T1_SIZE;i++) {
795 page = __bound_t1[i];
796 for(j=0;j<BOUND_T2_SIZE;j++) {
797 e = page + j;
798 /* do not print invalid or empty entries */
799 if (e->size != EMPTY_SIZE && e->start != 0) {
800 printf("%08x:",
801 (i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
802 (j << BOUND_T3_BITS));
803 do {
804 printf(" %08lx:%08lx", e->start, e->start + e->size);
805 e = e->next;
806 } while (e != NULL);
807 printf("\n");
812 #endif
814 /* some useful checked functions */
816 /* check that (p ... p + size - 1) lies inside 'p' region, if any */
817 static void __bound_check(const void *p, size_t size)
819 if (size == 0)
820 return;
821 p = __bound_ptr_add((void *)p, size);
822 if (p == INVALID_POINTER)
823 bound_error(get_caller_pc(2), "invalid pointer");
826 void *__bound_memcpy(void *dst, const void *src, size_t size)
828 __bound_check(dst, size);
829 __bound_check(src, size);
830 /* check also region overlap */
831 if (src >= dst && src < dst + size)
832 bound_error(get_caller_pc(1), "overlapping regions in memcpy()");
833 return memcpy(dst, src, size);
836 void *__bound_memmove(void *dst, const void *src, size_t size)
838 __bound_check(dst, size);
839 __bound_check(src, size);
840 return memmove(dst, src, size);
843 void *__bound_memset(void *dst, int c, size_t size)
845 __bound_check(dst, size);
846 return memset(dst, c, size);
849 /* XXX: could be optimized */
850 int __bound_strlen(const char *s)
852 const char *p;
853 int len;
855 len = 0;
856 for(;;) {
857 p = __bound_ptr_indir1((char *)s, len);
858 if (p == INVALID_POINTER)
859 bound_error(get_caller_pc(1), "bad pointer in strlen()");
860 if (*p == '\0')
861 break;
862 len++;
864 return len;
867 char *__bound_strcpy(char *dst, const char *src)
869 int len;
870 len = __bound_strlen(src);
871 return __bound_memcpy(dst, src, len + 1);