History

new subdirs: include, lib, tests

grischka committed 17 years ago

Commit ea5e81b1 parent e8a52a816 files · +0 −6Browse files

Showing the changes to lib/bcheck.c (1 of 16 files). Show all

Unified · Split

lib/bcheck.c+868−0
@@ -0,0 +1,868 @@
1+/*
2+ * Tiny C Memory and bounds checker
3+ *
4+ * Copyright (c) 2002 Fabrice Bellard
5+ *
6+ * This library is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2 of the License, or (at your option) any later version.
10+ *
11+ * This library 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 GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with this library; if not, write to the Free Software
18+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+ */
20+#include <stdlib.h>
21+#include <stdio.h>
22+#include <stdarg.h>
23+#include <string.h>
24+#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
25+#include <malloc.h>
26+#endif
27+
28+//#define BOUND_DEBUG
29+
30+/* define so that bound array is static (faster, but use memory if
31+ bound checking not used) */
32+//#define BOUND_STATIC
33+
34+/* use malloc hooks. Currently the code cannot be reliable if no hooks */
35+#define CONFIG_TCC_MALLOC_HOOKS
36+
37+#define HAVE_MEMALIGN
38+
39+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
40+ || defined(__UCLIBC__) || defined(__OpenBSD__)
41+#warning Bound checking not fully supported in this environment.
42+#undef CONFIG_TCC_MALLOC_HOOKS
43+#undef HAVE_MEMALIGN
44+#endif
45+
46+#define BOUND_T1_BITS 13
47+#define BOUND_T2_BITS 11
48+#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
49+
50+#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
51+#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
52+#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
53+#define BOUND_E_BITS 4
54+
55+#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
56+#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
57+
58+
59+/* this pointer is generated when bound check is incorrect */
60+#define INVALID_POINTER ((void *)(-2))
61+/* size of an empty region */
62+#define EMPTY_SIZE 0xffffffff
63+/* size of an invalid region */
64+#define INVALID_SIZE 0
65+
66+typedef struct BoundEntry {
67+ unsigned long start;
68+ unsigned long size;
69+ struct BoundEntry *next;
70+ unsigned long is_invalid; /* true if pointers outside region are invalid */
71+} BoundEntry;
72+
73+/* external interface */
74+void __bound_init(void);
75+void __bound_new_region(void *p, unsigned long size);
76+int __bound_delete_region(void *p);
77+
78+#define FASTCALL __attribute__((regparm(3)))
79+
80+void *__bound_malloc(size_t size, const void *caller);
81+void *__bound_memalign(size_t size, size_t align, const void *caller);
82+void __bound_free(void *ptr, const void *caller);
83+void *__bound_realloc(void *ptr, size_t size, const void *caller);
84+static void *libc_malloc(size_t size);
85+static void libc_free(void *ptr);
86+static void install_malloc_hooks(void);
87+static void restore_malloc_hooks(void);
88+
89+#ifdef CONFIG_TCC_MALLOC_HOOKS
90+static void *saved_malloc_hook;
91+static void *saved_free_hook;
92+static void *saved_realloc_hook;
93+static void *saved_memalign_hook;
94+#endif
95+
96+/* linker definitions */
97+extern char _end;
98+
99+/* TCC definitions */
100+extern char __bounds_start; /* start of static bounds table */
101+/* error message, just for TCC */
102+const char *__bound_error_msg;
103+
104+/* runtime error output */
105+extern void rt_error(unsigned long pc, const char *fmt, ...);
106+
107+#ifdef BOUND_STATIC
108+static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
109+#else
110+static BoundEntry **__bound_t1; /* page table */
111+#endif
112+static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
113+static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
114+
115+static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
116+{
117+ unsigned long addr, tmp;
118+ BoundEntry *e;
119+
120+ e = e1;
121+ while (e != NULL) {
122+ addr = (unsigned long)p;
123+ addr -= e->start;
124+ if (addr <= e->size) {
125+ /* put region at the head */
126+ tmp = e1->start;
127+ e1->start = e->start;
128+ e->start = tmp;
129+ tmp = e1->size;
130+ e1->size = e->size;
131+ e->size = tmp;
132+ return e1;
133+ }
134+ e = e->next;
135+ }
136+ /* no entry found: return empty entry or invalid entry */
137+ if (e1->is_invalid)
138+ return __bound_invalid_t2;
139+ else
140+ return __bound_empty_t2;
141+}
142+
143+/* print a bound error message */
144+static void bound_error(const char *fmt, ...)
145+{
146+ __bound_error_msg = fmt;
147+ *(int *)0 = 0; /* force a runtime error */
148+}
149+
150+static void bound_alloc_error(void)
151+{
152+ bound_error("not enough memory for bound checking code");
153+}
154+
155+/* currently, tcc cannot compile that because we use GNUC extensions */
156+#if !defined(__TINYC__)
157+
158+/* return '(p + offset)' for pointer arithmetic (a pointer can reach
159+ the end of a region in this case */
160+void * FASTCALL __bound_ptr_add(void *p, int offset)
161+{
162+ unsigned long addr = (unsigned long)p;
163+ BoundEntry *e;
164+#if defined(BOUND_DEBUG)
165+ printf("add: 0x%x %d\n", (int)p, offset);
166+#endif
167+
168+ e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
169+ e = (BoundEntry *)((char *)e +
170+ ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
171+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
172+ addr -= e->start;
173+ if (addr > e->size) {
174+ e = __bound_find_region(e, p);
175+ addr = (unsigned long)p - e->start;
176+ }
177+ addr += offset;
178+ if (addr > e->size)
179+ return INVALID_POINTER; /* return an invalid pointer */
180+ return p + offset;
181+}
182+
183+/* return '(p + offset)' for pointer indirection (the resulting must
184+ be strictly inside the region */
185+#define BOUND_PTR_INDIR(dsize) \
186+void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
187+{ \
188+ unsigned long addr = (unsigned long)p; \
189+ BoundEntry *e; \
190+ \
191+ e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
192+ e = (BoundEntry *)((char *)e + \
193+ ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
194+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
195+ addr -= e->start; \
196+ if (addr > e->size) { \
197+ e = __bound_find_region(e, p); \
198+ addr = (unsigned long)p - e->start; \
199+ } \
200+ addr += offset + dsize; \
201+ if (addr > e->size) \
202+ return INVALID_POINTER; /* return an invalid pointer */ \
203+ return p + offset; \
204+}
205+
206+#ifdef __i386__
207+/* return the frame pointer of the caller */
208+#define GET_CALLER_FP(fp)\
209+{\
210+ unsigned long *fp1;\
211+ __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
212+ fp = fp1[0];\
213+}
214+#else
215+#error put code to extract the calling frame pointer
216+#endif
217+
218+/* called when entering a function to add all the local regions */
219+void FASTCALL __bound_local_new(void *p1)
220+{
221+ unsigned long addr, size, fp, *p = p1;
222+ GET_CALLER_FP(fp);
223+ for(;;) {
224+ addr = p[0];
225+ if (addr == 0)
226+ break;
227+ addr += fp;
228+ size = p[1];
229+ p += 2;
230+ __bound_new_region((void *)addr, size);
231+ }
232+}
233+
234+/* called when leaving a function to delete all the local regions */
235+void FASTCALL __bound_local_delete(void *p1)
236+{
237+ unsigned long addr, fp, *p = p1;
238+ GET_CALLER_FP(fp);
239+ for(;;) {
240+ addr = p[0];
241+ if (addr == 0)
242+ break;
243+ addr += fp;
244+ p += 2;
245+ __bound_delete_region((void *)addr);
246+ }
247+}
248+
249+#else
250+
251+void __bound_local_new(void *p)
252+{
253+}
254+void __bound_local_delete(void *p)
255+{
256+}
257+
258+void *__bound_ptr_add(void *p, int offset)
259+{
260+ return p + offset;
261+}
262+
263+#define BOUND_PTR_INDIR(dsize) \
264+void *__bound_ptr_indir ## dsize (void *p, int offset) \
265+{ \
266+ return p + offset; \
267+}
268+#endif
269+
270+BOUND_PTR_INDIR(1)
271+BOUND_PTR_INDIR(2)
272+BOUND_PTR_INDIR(4)
273+BOUND_PTR_INDIR(8)
274+BOUND_PTR_INDIR(12)
275+BOUND_PTR_INDIR(16)
276+
277+static BoundEntry *__bound_new_page(void)
278+{
279+ BoundEntry *page;
280+ int i;
281+
282+ page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
283+ if (!page)
284+ bound_alloc_error();
285+ for(i=0;i<BOUND_T2_SIZE;i++) {
286+ /* put empty entries */
287+ page[i].start = 0;
288+ page[i].size = EMPTY_SIZE;
289+ page[i].next = NULL;
290+ page[i].is_invalid = 0;
291+ }
292+ return page;
293+}
294+
295+/* currently we use malloc(). Should use bound_new_page() */
296+static BoundEntry *bound_new_entry(void)
297+{
298+ BoundEntry *e;
299+ e = libc_malloc(sizeof(BoundEntry));
300+ return e;
301+}
302+
303+static void bound_free_entry(BoundEntry *e)
304+{
305+ libc_free(e);
306+}
307+
308+static inline BoundEntry *get_page(int index)
309+{
310+ BoundEntry *page;
311+ page = __bound_t1[index];
312+ if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
313+ /* create a new page if necessary */
314+ page = __bound_new_page();
315+ __bound_t1[index] = page;
316+ }
317+ return page;
318+}
319+
320+/* mark a region as being invalid (can only be used during init) */
321+static void mark_invalid(unsigned long addr, unsigned long size)
322+{
323+ unsigned long start, end;
324+ BoundEntry *page;
325+ int t1_start, t1_end, i, j, t2_start, t2_end;
326+
327+ start = addr;
328+ end = addr + size;
329+
330+ t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
331+ if (end != 0)
332+ t2_end = end >> BOUND_T3_BITS;
333+ else
334+ t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
335+
336+#if 0
337+ printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
338+#endif
339+
340+ /* first we handle full pages */
341+ t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
342+ t1_end = t2_end >> BOUND_T2_BITS;
343+
344+ i = t2_start & (BOUND_T2_SIZE - 1);
345+ j = t2_end & (BOUND_T2_SIZE - 1);
346+
347+ if (t1_start == t1_end) {
348+ page = get_page(t2_start >> BOUND_T2_BITS);
349+ for(; i < j; i++) {
350+ page[i].size = INVALID_SIZE;
351+ page[i].is_invalid = 1;
352+ }
353+ } else {
354+ if (i > 0) {
355+ page = get_page(t2_start >> BOUND_T2_BITS);
356+ for(; i < BOUND_T2_SIZE; i++) {
357+ page[i].size = INVALID_SIZE;
358+ page[i].is_invalid = 1;
359+ }
360+ }
361+ for(i = t1_start; i < t1_end; i++) {
362+ __bound_t1[i] = __bound_invalid_t2;
363+ }
364+ if (j != 0) {
365+ page = get_page(t1_end);
366+ for(i = 0; i < j; i++) {
367+ page[i].size = INVALID_SIZE;
368+ page[i].is_invalid = 1;
369+ }
370+ }
371+ }
372+}
373+
374+void __bound_init(void)
375+{
376+ int i;
377+ BoundEntry *page;
378+ unsigned long start, size;
379+ int *p;
380+
381+ /* save malloc hooks and install bound check hooks */
382+ install_malloc_hooks();
383+
384+#ifndef BOUND_STATIC
385+ __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
386+ if (!__bound_t1)
387+ bound_alloc_error();
388+#endif
389+ __bound_empty_t2 = __bound_new_page();
390+ for(i=0;i<BOUND_T1_SIZE;i++) {
391+ __bound_t1[i] = __bound_empty_t2;
392+ }
393+
394+ page = __bound_new_page();
395+ for(i=0;i<BOUND_T2_SIZE;i++) {
396+ /* put invalid entries */
397+ page[i].start = 0;
398+ page[i].size = INVALID_SIZE;
399+ page[i].next = NULL;
400+ page[i].is_invalid = 1;
401+ }
402+ __bound_invalid_t2 = page;
403+
404+ /* invalid pointer zone */
405+ start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
406+ size = BOUND_T23_SIZE;
407+ mark_invalid(start, size);
408+
409+#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
410+ /* malloc zone is also marked invalid. can only use that with
411+ hooks because all libs should use the same malloc. The solution
412+ would be to build a new malloc for tcc. */
413+ start = (unsigned long)&_end;
414+ size = 128 * 0x100000;
415+ mark_invalid(start, size);
416+#endif
417+
418+ /* add all static bound check values */
419+ p = (int *)&__bounds_start;
420+ while (p[0] != 0) {
421+ __bound_new_region((void *)p[0], p[1]);
422+ p += 2;
423+ }
424+}
425+
426+static inline void add_region(BoundEntry *e,
427+ unsigned long start, unsigned long size)
428+{
429+ BoundEntry *e1;
430+ if (e->start == 0) {
431+ /* no region : add it */
432+ e->start = start;
433+ e->size = size;
434+ } else {
435+ /* already regions in the list: add it at the head */
436+ e1 = bound_new_entry();
437+ e1->start = e->start;
438+ e1->size = e->size;
439+ e1->next = e->next;
440+ e->start = start;
441+ e->size = size;
442+ e->next = e1;
443+ }
444+}
445+
446+/* create a new region. It should not already exist in the region list */
447+void __bound_new_region(void *p, unsigned long size)
448+{
449+ unsigned long start, end;
450+ BoundEntry *page, *e, *e2;
451+ int t1_start, t1_end, i, t2_start, t2_end;
452+
453+ start = (unsigned long)p;
454+ end = start + size;
455+ t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
456+ t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
457+
458+ /* start */
459+ page = get_page(t1_start);
460+ t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
461+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
462+ t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
463+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
464+#ifdef BOUND_DEBUG
465+ printf("new %lx %lx %x %x %x %x\n",
466+ start, end, t1_start, t1_end, t2_start, t2_end);
467+#endif
468+
469+ e = (BoundEntry *)((char *)page + t2_start);
470+ add_region(e, start, size);
471+
472+ if (t1_end == t1_start) {
473+ /* same ending page */
474+ e2 = (BoundEntry *)((char *)page + t2_end);
475+ if (e2 > e) {
476+ e++;
477+ for(;e<e2;e++) {
478+ e->start = start;
479+ e->size = size;
480+ }
481+ add_region(e, start, size);
482+ }
483+ } else {
484+ /* mark until end of page */
485+ e2 = page + BOUND_T2_SIZE;
486+ e++;
487+ for(;e<e2;e++) {
488+ e->start = start;
489+ e->size = size;
490+ }
491+ /* mark intermediate pages, if any */
492+ for(i=t1_start+1;i<t1_end;i++) {
493+ page = get_page(i);
494+ e2 = page + BOUND_T2_SIZE;
495+ for(e=page;e<e2;e++) {
496+ e->start = start;
497+ e->size = size;
498+ }
499+ }
500+ /* last page */
501+ page = get_page(t1_end);
502+ e2 = (BoundEntry *)((char *)page + t2_end);
503+ for(e=page;e<e2;e++) {
504+ e->start = start;
505+ e->size = size;
506+ }
507+ add_region(e, start, size);
508+ }
509+}
510+
511+/* delete a region */
512+static inline void delete_region(BoundEntry *e,
513+ void *p, unsigned long empty_size)
514+{
515+ unsigned long addr;
516+ BoundEntry *e1;
517+
518+ addr = (unsigned long)p;
519+ addr -= e->start;
520+ if (addr <= e->size) {
521+ /* region found is first one */
522+ e1 = e->next;
523+ if (e1 == NULL) {
524+ /* no more region: mark it empty */
525+ e->start = 0;
526+ e->size = empty_size;
527+ } else {
528+ /* copy next region in head */
529+ e->start = e1->start;
530+ e->size = e1->size;
531+ e->next = e1->next;
532+ bound_free_entry(e1);
533+ }
534+ } else {
535+ /* find the matching region */
536+ for(;;) {
537+ e1 = e;
538+ e = e->next;
539+ /* region not found: do nothing */
540+ if (e == NULL)
541+ break;
542+ addr = (unsigned long)p - e->start;
543+ if (addr <= e->size) {
544+ /* found: remove entry */
545+ e1->next = e->next;
546+ bound_free_entry(e);
547+ break;
548+ }
549+ }
550+ }
551+}
552+
553+/* WARNING: 'p' must be the starting point of the region. */
554+/* return non zero if error */
555+int __bound_delete_region(void *p)
556+{
557+ unsigned long start, end, addr, size, empty_size;
558+ BoundEntry *page, *e, *e2;
559+ int t1_start, t1_end, t2_start, t2_end, i;
560+
561+ start = (unsigned long)p;
562+ t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
563+ t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
564+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
565+
566+ /* find region size */
567+ page = __bound_t1[t1_start];
568+ e = (BoundEntry *)((char *)page + t2_start);
569+ addr = start - e->start;
570+ if (addr > e->size)
571+ e = __bound_find_region(e, p);
572+ /* test if invalid region */
573+ if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
574+ return -1;
575+ /* compute the size we put in invalid regions */
576+ if (e->is_invalid)
577+ empty_size = INVALID_SIZE;
578+ else
579+ empty_size = EMPTY_SIZE;
580+ size = e->size;
581+ end = start + size;
582+
583+ /* now we can free each entry */
584+ t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
585+ t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
586+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
587+
588+ delete_region(e, p, empty_size);
589+ if (t1_end == t1_start) {
590+ /* same ending page */
591+ e2 = (BoundEntry *)((char *)page + t2_end);
592+ if (e2 > e) {
593+ e++;
594+ for(;e<e2;e++) {
595+ e->start = 0;
596+ e->size = empty_size;
597+ }
598+ delete_region(e, p, empty_size);
599+ }
600+ } else {
601+ /* mark until end of page */
602+ e2 = page + BOUND_T2_SIZE;
603+ e++;
604+ for(;e<e2;e++) {
605+ e->start = 0;
606+ e->size = empty_size;
607+ }
608+ /* mark intermediate pages, if any */
609+ /* XXX: should free them */
610+ for(i=t1_start+1;i<t1_end;i++) {
611+ page = get_page(i);
612+ e2 = page + BOUND_T2_SIZE;
613+ for(e=page;e<e2;e++) {
614+ e->start = 0;
615+ e->size = empty_size;
616+ }
617+ }
618+ /* last page */
619+ page = get_page(t2_end);
620+ e2 = (BoundEntry *)((char *)page + t2_end);
621+ for(e=page;e<e2;e++) {
622+ e->start = 0;
623+ e->size = empty_size;
624+ }
625+ delete_region(e, p, empty_size);
626+ }
627+ return 0;
628+}
629+
630+/* return the size of the region starting at p, or EMPTY_SIZE if non
631+ existant region. */
632+static unsigned long get_region_size(void *p)
633+{
634+ unsigned long addr = (unsigned long)p;
635+ BoundEntry *e;
636+
637+ e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
638+ e = (BoundEntry *)((char *)e +
639+ ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
640+ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
641+ addr -= e->start;
642+ if (addr > e->size)
643+ e = __bound_find_region(e, p);
644+ if (e->start != (unsigned long)p)
645+ return EMPTY_SIZE;
646+ return e->size;
647+}
648+
649+/* patched memory functions */
650+
651+static void install_malloc_hooks(void)
652+{
653+#ifdef CONFIG_TCC_MALLOC_HOOKS
654+ saved_malloc_hook = __malloc_hook;
655+ saved_free_hook = __free_hook;
656+ saved_realloc_hook = __realloc_hook;
657+ saved_memalign_hook = __memalign_hook;
658+ __malloc_hook = __bound_malloc;
659+ __free_hook = __bound_free;
660+ __realloc_hook = __bound_realloc;
661+ __memalign_hook = __bound_memalign;
662+#endif
663+}
664+
665+static void restore_malloc_hooks(void)
666+{
667+#ifdef CONFIG_TCC_MALLOC_HOOKS
668+ __malloc_hook = saved_malloc_hook;
669+ __free_hook = saved_free_hook;
670+ __realloc_hook = saved_realloc_hook;
671+ __memalign_hook = saved_memalign_hook;
672+#endif
673+}
674+
675+static void *libc_malloc(size_t size)
676+{
677+ void *ptr;
678+ restore_malloc_hooks();
679+ ptr = malloc(size);
680+ install_malloc_hooks();
681+ return ptr;
682+}
683+
684+static void libc_free(void *ptr)
685+{
686+ restore_malloc_hooks();
687+ free(ptr);
688+ install_malloc_hooks();
689+}
690+
691+/* XXX: we should use a malloc which ensure that it is unlikely that
692+ two malloc'ed data have the same address if 'free' are made in
693+ between. */
694+void *__bound_malloc(size_t size, const void *caller)
695+{
696+ void *ptr;
697+
698+ /* we allocate one more byte to ensure the regions will be
699+ separated by at least one byte. With the glibc malloc, it may
700+ be in fact not necessary */
701+ ptr = libc_malloc(size + 1);
702+
703+ if (!ptr)
704+ return NULL;
705+ __bound_new_region(ptr, size);
706+ return ptr;
707+}
708+
709+void *__bound_memalign(size_t size, size_t align, const void *caller)
710+{
711+ void *ptr;
712+
713+ restore_malloc_hooks();
714+
715+#ifndef HAVE_MEMALIGN
716+ if (align > 4) {
717+ /* XXX: handle it ? */
718+ ptr = NULL;
719+ } else {
720+ /* we suppose that malloc aligns to at least four bytes */
721+ ptr = malloc(size + 1);
722+ }
723+#else
724+ /* we allocate one more byte to ensure the regions will be
725+ separated by at least one byte. With the glibc malloc, it may
726+ be in fact not necessary */
727+ ptr = memalign(size + 1, align);
728+#endif
729+
730+ install_malloc_hooks();
731+
732+ if (!ptr)
733+ return NULL;
734+ __bound_new_region(ptr, size);
735+ return ptr;
736+}
737+
738+void __bound_free(void *ptr, const void *caller)
739+{
740+ if (ptr == NULL)
741+ return;
742+ if (__bound_delete_region(ptr) != 0)
743+ bound_error("freeing invalid region");
744+
745+ libc_free(ptr);
746+}
747+
748+void *__bound_realloc(void *ptr, size_t size, const void *caller)
749+{
750+ void *ptr1;
751+ int old_size;
752+
753+ if (size == 0) {
754+ __bound_free(ptr, caller);
755+ return NULL;
756+ } else {
757+ ptr1 = __bound_malloc(size, caller);
758+ if (ptr == NULL || ptr1 == NULL)
759+ return ptr1;
760+ old_size = get_region_size(ptr);
761+ if (old_size == EMPTY_SIZE)
762+ bound_error("realloc'ing invalid pointer");
763+ memcpy(ptr1, ptr, old_size);
764+ __bound_free(ptr, caller);
765+ return ptr1;
766+ }
767+}
768+
769+#ifndef CONFIG_TCC_MALLOC_HOOKS
770+void *__bound_calloc(size_t nmemb, size_t size)
771+{
772+ void *ptr;
773+ size = size * nmemb;
774+ ptr = __bound_malloc(size, NULL);
775+ if (!ptr)
776+ return NULL;
777+ memset(ptr, 0, size);
778+ return ptr;
779+}
780+#endif
781+
782+#if 0
783+static void bound_dump(void)
784+{
785+ BoundEntry *page, *e;
786+ int i, j;
787+
788+ printf("region dump:\n");
789+ for(i=0;i<BOUND_T1_SIZE;i++) {
790+ page = __bound_t1[i];
791+ for(j=0;j<BOUND_T2_SIZE;j++) {
792+ e = page + j;
793+ /* do not print invalid or empty entries */
794+ if (e->size != EMPTY_SIZE && e->start != 0) {
795+ printf("%08x:",
796+ (i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
797+ (j << BOUND_T3_BITS));
798+ do {
799+ printf(" %08lx:%08lx", e->start, e->start + e->size);
800+ e = e->next;
801+ } while (e != NULL);
802+ printf("\n");
803+ }
804+ }
805+ }
806+}
807+#endif
808+
809+/* some useful checked functions */
810+
811+/* check that (p ... p + size - 1) lies inside 'p' region, if any */
812+static void __bound_check(const void *p, size_t size)
813+{
814+ if (size == 0)
815+ return;
816+ p = __bound_ptr_add((void *)p, size);
817+ if (p == INVALID_POINTER)
818+ bound_error("invalid pointer");
819+}
820+
821+void *__bound_memcpy(void *dst, const void *src, size_t size)
822+{
823+ __bound_check(dst, size);
824+ __bound_check(src, size);
825+ /* check also region overlap */
826+ if (src >= dst && src < dst + size)
827+ bound_error("overlapping regions in memcpy()");
828+ return memcpy(dst, src, size);
829+}
830+
831+void *__bound_memmove(void *dst, const void *src, size_t size)
832+{
833+ __bound_check(dst, size);
834+ __bound_check(src, size);
835+ return memmove(dst, src, size);
836+}
837+
838+void *__bound_memset(void *dst, int c, size_t size)
839+{
840+ __bound_check(dst, size);
841+ return memset(dst, c, size);
842+}
843+
844+/* XXX: could be optimized */
845+int __bound_strlen(const char *s)
846+{
847+ const char *p;
848+ int len;
849+
850+ len = 0;
851+ for(;;) {
852+ p = __bound_ptr_indir1((char *)s, len);
853+ if (p == INVALID_POINTER)
854+ bound_error("bad pointer in strlen()");
855+ if (*p == '\0')
856+ break;
857+ len++;
858+ }
859+ return len;
860+}
861+
862+char *__bound_strcpy(char *dst, const char *src)
863+{
864+ int len;
865+ len = __bound_strlen(src);
866+ return __bound_memcpy(dst, src, len + 1);
867+}
868+

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t