History

Update bound checking code.

Add __attribute__((constructor)) to __bounds_init. - remove tcc_add_bcheck from i386-link.c and x86_64-link.c - add simplified tcc_add_bcheck to tccelf.c - Update tccrun.c to call constructor/destructor. Set dynsym sh_info to number of local symbols in tccelf.c Reduce stack size when bounds checking is enabled. Added variable TCC_LIBBCHECK for windows support. Add signal stack to detect stack overflow. Add all & parameters in lbound_section and remove them if not used. Close fd in tcc_relocate in tccrun.c Fix section type constructor/destructor in tccelf.c Add check code in tests/boundtest.c for mem/str functions. Remove -ba from documentation. Add bounds check signal info in documentation. bcheck.c: - Fix initial_pool alignment. . Fix printf statements. . Add prototypes for all external interface functions. - Add TCC_BOUNDS_WARN_POINTER_ADD environment variable. . Add ctype and errno data. - Fix alloca when multithreading is used. - Add lock for __bound_checking and __bound_never_fatal. - Catch pthread_create and use locks when called. - Detect in loaded in shared lib and use locks when found - Use spin locks instead of semaphore locks. - Make spin locked code as small as possible. - Fix mem/str functions checking. - Fix overlap checking mem/str functions.

herman ten brugge committed 6 years ago

Commit 38776181 parent 0d6801b13 files · +1197 −606Browse files

Unified · Split

13 files
  1. i386-gen.c +7 −2
  2. i386-link.c +0 −75
  3. lib/bcheck.c +732 −394
  4. tcc-doc.texi +38 −5
  5. tcc.h +8 −0
  6. tccelf.c +29 −4
  7. tccgen.c +122 −18
  8. tccpe.c +1 −1
  9. tccrun.c +48 −18
  10. tests/Makefile +1 −1
  11. tests/boundtest.c +197 −0
  12. x86_64-gen.c +14 −3
  13. x86_64-link.c +0 −85
i386-gen.c+7−2
@@ -95,7 +95,6 @@ ST_DATA const int reg_classes[NB_REGS] = { · 94 unmodified lines
9595 static unsigned long func_sub_sp_offset;
9696 static int func_ret_sub;
9797 #ifdef CONFIG_TCC_BCHECK
98−static addr_t func_bound_offset;
9998 static unsigned long func_bound_ind;
10099 #endif
101100
@@ -402,8 +401,10 @@ ST_FUNC void gfunc_call(int nb_args) · 300 unmodified lines
402401 Sym *func_sym;
403402
404403 #ifdef CONFIG_TCC_BCHECK
405− if (tcc_state->do_bounds_check)
404+ if (tcc_state->do_bounds_check) {
405+ save_temp_local (nb_args);
406406 gbound_args(nb_args);
407+ }
407408 #endif
408409
409410 args_size = 0;
@@ -485,6 +486,10 @@ ST_FUNC void gfunc_call(int nb_args) · 75 unmodified lines
485486 if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
486487 gadd_sp(args_size);
487488 vtop--;
489+#ifdef CONFIG_TCC_BCHECK
490+ if (tcc_state->do_bounds_check)
491+ restore_temp_local ();
492+#endif
488493 }
489494
490495 #ifdef TCC_TARGET_PE
i386-link.c+0−75
@@ -235,79 +235,4 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t · 234 unmodified lines
235235 }
236236 }
237237
238−#ifdef CONFIG_TCC_BCHECK
239−ST_FUNC void tcc_add_bcheck(TCCState *s1)
240−{
241− addr_t *ptr;
242− int loc_glob;
243− int sym_index;
244− int bsym_index;
245−
246− if (0 == s1->do_bounds_check)
247− return;
248− /* XXX: add an object file to do that */
249− ptr = section_ptr_add(bounds_section, sizeof(*ptr));
250− *ptr = 0;
251− loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
252− bsym_index = set_elf_sym(symtab_section, 0, 0,
253− ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
254− bounds_section->sh_num, "__bounds_start");
255− /* pull bcheck.o from libtcc1.a */
256− sym_index = set_elf_sym(symtab_section, 0, 0,
257− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
258− SHN_UNDEF, "__bound_init");
259− if (s1->output_type != TCC_OUTPUT_MEMORY) {
260− /* add 'call __bound_init()' in .init section */
261− Section *init_section = find_section(s1, ".init");
262− unsigned char *pinit;
263−#ifdef TCC_TARGET_PE
264− pinit = section_ptr_add(init_section, 3);
265− pinit[0] = 0x55; /* push %rbp */
266− pinit[1] = 0x89; /* mov %esp,%ebp */
267− pinit[2] = 0xe5;
268−#endif
269− pinit = section_ptr_add(init_section, 5);
270− pinit[0] = 0xe8;
271− write32le(pinit + 1, -4);
272− put_elf_reloc(symtab_section, init_section,
273− init_section->data_offset - 4, R_386_PC32, sym_index);
274− /* R_386_PC32 = R_X86_64_PC32 = 2 */
275− pinit = section_ptr_add(init_section, 6);
276− pinit[0] = 0xb8; /* mov xx,%eax */
277− write32le(pinit + 1, 0);
278− pinit[5] = 0x50; /* push %eax */
279− put_elf_reloc(symtab_section, init_section,
280− init_section->data_offset - 5, R_386_32, bsym_index);
281− sym_index = set_elf_sym(symtab_section, 0, 0,
282− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
283− SHN_UNDEF, "__bounds_add_static_var");
284− pinit = section_ptr_add(init_section, 5);
285− pinit[0] = 0xe8;
286− write32le(pinit + 1, -4);
287− put_elf_reloc(symtab_section, init_section,
288− init_section->data_offset - 4, R_386_PC32, sym_index);
289− /* R_386_PC32 = R_X86_64_PC32 = 2 */
290− pinit = section_ptr_add(init_section, 3);
291− pinit[0] = 0x83; /* add $0x4,%esp */
292− pinit[1] = 0xc4;
293− pinit[2] = 0x04;
294−#ifdef TCC_TARGET_PE
295− {
296− int init_index = set_elf_sym(symtab_section,
297− 0, 0,
298− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
299− init_section->sh_num, "__init_start");
300− Sym sym;
301− init_section->sh_flags |= SHF_EXECINSTR;
302− pinit = section_ptr_add(init_section, 2);
303− pinit[0] = 0xc9; /* leave */
304− pinit[1] = 0xc3; /* ret */
305− sym.c = init_index;
306− add_init_array (s1, &sym);
307− }
308−#endif
309− }
310−}
311−#endif
312−
313238 #endif /* !TARGET_DEFS_ONLY */
lib/bcheck.c+732−394
@@ -34,17 +34,20 @@ · 33 unmodified lines
3434 #include <unistd.h>
3535 #endif
3636
37−#define BOUND_DEBUG
38−#define BOUND_STATISTIC
37+#define BOUND_DEBUG (1)
38+#define BOUND_STATISTIC (1)
3939
40−#ifdef BOUND_DEBUG
41− #define dprintf(a...) if (print_calls) fprintf(a)
40+#if BOUND_DEBUG
41+ #define dprintf(a...) if (print_calls) fprintf(a)
4242 #else
4343 #define dprintf(a...)
4444 #endif
4545
46−/* Check memalign */
47−#define HAVE_MEMALIGN
46+#ifdef __attribute__
47+ /* an __attribute__ macro is defined in the system headers */
48+ #undef __attribute__
49+#endif
50+#define FASTCALL __attribute__((regparm(3)))
4851
4952 #if defined(__FreeBSD__) \
5053 || defined(__FreeBSD_kernel__) \
@@ -52,43 +55,76 @@ · 1 unmodified line
5255 || defined(__OpenBSD__) \
5356 || defined(__NetBSD__) \
5457 || defined(__dietlibc__)
55−#undef HAVE_MEMALIGN
58+
5659 #define INIT_SEM()
5760 #define EXIT_SEM()
5861 #define WAIT_SEM()
5962 #define POST_SEM()
60−#define HAS_ENVIRON 0
61−#define MALLOC_REDIR (0)
63+#define HAVE_MEMALIGN (0)
64+#define HAS_ENVIRON (0)
65+#define MALLOC_REDIR (0)
66+#define HAVE_PTHREAD_CREATE (0)
67+#define HAVE_CTYPE (0)
68+#define HAVE_ERRNO (0)
69+
6270 #elif defined(_WIN32)
71+
6372 #include <windows.h>
64−#undef HAVE_MEMALIGN
6573 static CRITICAL_SECTION bounds_sem;
66−#define INIT_SEM() InitializeCriticalSection(&bounds_sem)
67−#define EXIT_SEM() DeleteCriticalSection(&bounds_sem)
68−#define WAIT_SEM() EnterCriticalSection(&bounds_sem)
69−#define POST_SEM() LeaveCriticalSection(&bounds_sem)
70−#define HAS_ENVIRON 0
71−#define MALLOC_REDIR (0)
74+#define INIT_SEM() InitializeCriticalSection(&bounds_sem)
75+#define EXIT_SEM() DeleteCriticalSection(&bounds_sem)
76+#define WAIT_SEM() EnterCriticalSection(&bounds_sem)
77+#define POST_SEM() LeaveCriticalSection(&bounds_sem)
78+#define HAVE_MEMALIGN (0)
79+#define HAS_ENVIRON (0)
80+#define MALLOC_REDIR (0)
81+#define HAVE_PTHREAD_CREATE (0)
82+#define HAVE_CTYPE (0)
83+#define HAVE_ERRNO (0)
84+
7285 #else
86+
87+#define __USE_GNU /* get RTLD_NEXT */
7388 #include <sys/mman.h>
89+#include <ctype.h>
90+#include <pthread.h>
91+#include <dlfcn.h>
7492 #include <errno.h>
93+#if 0
7594 #include <semaphore.h>
7695 static sem_t bounds_sem;
77−#define INIT_SEM() sem_init (&bounds_sem, 0, 1)
78−#define EXIT_SEM() sem_destroy (&bounds_sem)
79−#define WAIT_SEM() while (sem_wait (&bounds_sem) < 0 && errno == EINTR);
80−#define POST_SEM() sem_post (&bounds_sem)
81−#define HAS_ENVIRON 0 /* Disabled for now */
82−#define __USE_GNU /* get RTLD_NEXT */
83−#include <dlfcn.h>
84−#define MALLOC_REDIR (1)
85−static void *(*malloc_redir) (size_t) = NULL;
86−static void *(*calloc_redir) (size_t, size_t) = NULL;
87−static void (*free_redir) (void *) = NULL;
88−static void *(*realloc_redir) (void *, size_t) = NULL;
89−static void *(*memalign_redir) (size_t, size_t) = NULL;
90−static int pool_index = 0;
91−static unsigned char initial_pool[256];
96+#define INIT_SEM() sem_init (&bounds_sem, 0, 1)
97+#define EXIT_SEM() sem_destroy (&bounds_sem)
98+#define WAIT_SEM() if (use_sem) while (sem_wait (&bounds_sem) < 0 \
99+ && errno == EINTR)
100+#define POST_SEM() if (use_sem) sem_post (&bounds_sem)
101+#else
102+static pthread_spinlock_t bounds_spin;
103+/* about 25% faster then semaphore. */
104+#define INIT_SEM() pthread_spin_init (&bounds_spin, 0)
105+#define EXIT_SEM() pthread_spin_destroy (&bounds_spin)
106+#define WAIT_SEM() if (use_sem) pthread_spin_lock (&bounds_spin)
107+#define POST_SEM() if (use_sem) pthread_spin_unlock (&bounds_spin)
108+#endif
109+#define HAVE_MEMALIGN (1)
110+#define HAS_ENVIRON (1)
111+#define MALLOC_REDIR (1)
112+#define HAVE_PTHREAD_CREATE (1)
113+#define HAVE_CTYPE (1)
114+#define HAVE_ERRNO (1)
115+
116+static void *(*malloc_redir) (size_t);
117+static void *(*calloc_redir) (size_t, size_t);
118+static void (*free_redir) (void *);
119+static void *(*realloc_redir) (void *, size_t);
120+static void *(*memalign_redir) (size_t, size_t);
121+static int (*pthread_create_redir) (pthread_t *thread,
122+ const pthread_attr_t *attr,
123+ void *(*start_routine)(void *), void *arg);
124+static unsigned int pool_index;
125+static unsigned char __attribute__((aligned(16))) initial_pool[256];
126+static unsigned char use_sem;
127+
92128 #endif
93129
94130 #define TCC_TYPE_NONE (0)
@@ -106,8 +142,8 @@ struct tree_node { · 11 unmodified lines
106142 Tree * left, * right;
107143 size_t start;
108144 size_t size;
109− size_t type;
110− size_t is_invalid; /* true if pointers outside region are invalid */
145+ unsigned char type;
146+ unsigned char is_invalid; /* true if pointers outside region are invalid */
111147 };
112148
113149 typedef struct alloca_list_struct {
@@ -116,6 +152,7 @@ typedef struct alloca_list_struct { · 2 unmodified lines
116152 struct alloca_list_struct *next;
117153 } alloca_list_type;
118154
155+#define BOUND_STATISTIC_SPLAY (0)
119156 static Tree * splay (size_t addr, Tree *t);
120157 static Tree * splay_end (size_t addr, Tree *t);
121158 static Tree * splay_insert(size_t addr, size_t size, Tree * t);
@@ -123,14 +160,38 @@ static Tree * splay_delete(size_t addr, Tree *t); · 1 unmodified line
123160 void splay_printtree(Tree * t, int d);
124161
125162 /* external interface */
163+void __bound_checking (int no_check);
164+void __bound_never_fatal (int no_check);
165+void * __bound_ptr_add(void *p, size_t offset);
166+void * __bound_ptr_indir1(void *p, size_t offset);
167+void * __bound_ptr_indir2(void *p, size_t offset);
168+void * __bound_ptr_indir4(void *p, size_t offset);
169+void * __bound_ptr_indir8(void *p, size_t offset);
170+void * __bound_ptr_indir12(void *p, size_t offset);
171+void * __bound_ptr_indir16(void *p, size_t offset);
172+void FASTCALL __bound_local_new(void *p1);
173+void FASTCALL __bound_local_delete(void *p1);
126174 void __bound_init(void);
175+void __bound_main_arg(char **p);
127176 void __bound_exit(void);
128−
129−#ifdef __attribute__
130− /* an __attribute__ macro is defined in the system headers */
131− #undef __attribute__
177+#if !defined(_WIN32)
178+void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
179+ off_t offset);
180+int __bound_munmap (void *start, size_t size);
132181 #endif
133−#define FASTCALL __attribute__((regparm(3)))
182+void __bound_new_region(void *p, size_t size);
183+void *__bound_memcpy(void *dst, const void *src, size_t size);
184+int __bound_memcmp(const void *s1, const void *s2, size_t size);
185+void *__bound_memmove(void *dst, const void *src, size_t size);
186+void *__bound_memset(void *dst, int c, size_t size);
187+int __bound_strlen(const char *s);
188+char *__bound_strcpy(char *dst, const char *src);
189+char *__bound_strncpy(char *dst, const char *src, size_t n);
190+int __bound_strcmp(const char *s1, const char *s2);
191+int __bound_strncmp(const char *s1, const char *s2, size_t n);
192+char *__bound_strcat(char *dest, const char *src);
193+char *__bound_strchr(const char *string, int ch);
194+char *__bound_strdup(const char *s);
134195
135196 #if !MALLOC_REDIR
136197 void *__bound_malloc(size_t size, const void *caller);
@@ -141,30 +202,30 @@ void *__bound_calloc(size_t nmemb, size_t size); · 4 unmodified lines
141202 #endif
142203
143204 #define FREE_REUSE_SIZE (100)
144−static int free_reuse_index = 0;
205+static unsigned int free_reuse_index;
145206 static void *free_reuse_list[FREE_REUSE_SIZE];
146207
147208 /* error message, just for TCC */
148209 const char *__bound_error_msg;
149210
150−/* runtime error output */
151−extern void rt_error(size_t pc, const char *fmt, ...);
152−
153211 static Tree *tree = NULL;
154212 #define TREE_REUSE (1)
155213 #if TREE_REUSE
156−static Tree *tree_free_list = NULL;
214+static Tree *tree_free_list;
157215 #endif
158−static alloca_list_type *alloca_list = NULL;
159−
160−static int inited = 0;
161−static int print_calls = 0;
162−static int print_heap = 0;
163−static int print_statistic = 0;
164−static int never_fatal = 0;
165−static int no_checking = 0;
166−
167−#ifdef BOUND_STATISTIC
216+static alloca_list_type *alloca_list;
217+
218+static unsigned char inited;
219+static unsigned char print_warn_ptr_add;
220+static unsigned char print_calls;
221+static unsigned char print_heap;
222+static unsigned char print_statistic;
223+static unsigned char no_strdup;
224+static signed char never_fatal;
225+static signed char no_checking = 1;
226+static char exec[100];
227+
228+#if BOUND_STATISTIC
168229 static unsigned long long bound_ptr_add_count;
169230 static unsigned long long bound_ptr_indir1_count;
170231 static unsigned long long bound_ptr_indir2_count;
@@ -194,46 +255,93 @@ static unsigned long long bound_strncmp_count; · 23 unmodified lines
194255 static unsigned long long bound_strcat_count;
195256 static unsigned long long bound_strchr_count;
196257 static unsigned long long bound_strdup_count;
197−#define INCR_COUNT(x) x++
258+static unsigned long long bound_not_found;
259+#define INCR_COUNT(x) ++x
198260 #else
199261 #define INCR_COUNT(x)
200262 #endif
263+#if BOUND_STATISTIC_SPLAY
264+static unsigned long long bound_splay;
265+static unsigned long long bound_splay_end;
266+static unsigned long long bound_splay_insert;
267+static unsigned long long bound_splay_delete;
268+#define INCR_COUNT_SPLAY(x) ++x
269+#else
270+#define INCR_COUNT_SPLAY(x)
271+#endif
201272
202−/* enable/disable checking. This can be used for signal handlers. */
273+/* currently only i386/x86_64 supported. Change for other platforms */
274+static void fetch_and_add(signed char* variable, signed char value)
275+{
276+#if defined __i386__ || defined __x86_64__
277+ __asm__ volatile("lock; addb %0, %1"
278+ : "+r" (value), "+m" (*variable) // input+output
279+ : // No input-only
280+ : "memory"
281+ );
282+#else
283+ *variable += value;
284+#endif
285+}
286+
287+/* enable/disable checking. This can be used in signal handlers. */
203288 void __bound_checking (int no_check)
204289 {
205− no_checking = no_check;
290+ fetch_and_add (&no_checking, no_check);
206291 }
207292
208−#define no_FASTCALL
209−//#define no_checking 1
293+/* enable/disable checking. This can be used in signal handlers. */
294+void __bound_never_fatal (int neverfatal)
295+{
296+ fetch_and_add (&never_fatal, neverfatal);
297+}
210298
211299 /* print a bound error message */
212−static void bound_error(const char *fmt, ...)
300+static void bound_error(const char *error)
213301 {
214− __bound_error_msg = fmt;
215− fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt);
302+ __bound_error_msg = error;
303+ fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error);
216304 if (never_fatal == 0)
217305 *(void **)0 = 0; /* force a runtime error */
218306 }
219307
220−static void bound_alloc_error(void)
308+static void bound_alloc_error(const char *s)
309+{
310+ fprintf(stderr,"FATAL: %s\n",s);
311+ exit (1);
312+}
313+
314+static void bound_not_found_warning(const char *file, const char *function,
315+ void *ptr)
316+{
317+ dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
318+}
319+
320+static void bound_ptr_add_warning(const char *file, const char *function,
321+ void *ptr)
221322 {
222− bound_error("not enough memory for bound checking code");
323+ fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
324+ exec, file, function, ptr);
325+}
326+
327+static void bound_ptr_indir_error(const char *file, const char *function,
328+ void *ptr)
329+{
330+ fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
331+ exec, file, function, ptr);
223332 }
224333
225334 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
226335 the end of a region in this case */
227−void * no_FASTCALL __bound_ptr_add(void *p, size_t offset)
336+void * __bound_ptr_add(void *p, size_t offset)
228337 {
229338 size_t addr = (size_t)p;
230339
231− if (no_checking) {
340+ if (no_checking)
232341 return p + offset;
233− }
234342
235− dprintf(stderr, "%s %s : %p 0x%x\n",
236− __FILE__, __FUNCTION__, p, (unsigned)offset);
343+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
344+ __FILE__, __FUNCTION__, p, (unsigned long)offset);
237345
238346 WAIT_SEM ();
239347 INCR_COUNT(bound_ptr_add_count);
@@ -250,18 +358,21 @@ void * no_FASTCALL __bound_ptr_add(void *p, size_t offset) · 10 unmodified lines
250358 addr -= tree->start;
251359 }
252360 if (addr <= tree->size) {
253− addr += offset;
254− if (tree->is_invalid || addr > tree->size) {
255− #if 0
256− fprintf(stderr,"%s %s : %p is outside of the region\n",
257− __FILE__, __FUNCTION__, p + offset);
258− #endif
259− if (never_fatal == 0) {
260− POST_SEM ();
361+ if (tree->is_invalid || addr + offset > tree->size) {
362+ POST_SEM ();
363+ if (print_warn_ptr_add)
364+ bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset);
365+ if (never_fatal <= 0)
261366 return INVALID_POINTER; /* return an invalid pointer */
262− }
367+ return p + offset;
263368 }
264369 }
370+ else if (p) { /* Allow NULL + offset. offsetoff is using it. */
371+ INCR_COUNT(bound_not_found);
372+ POST_SEM ();
373+ bound_not_found_warning (__FILE__, __FUNCTION__, p);
374+ return p + offset;
375+ }
265376 }
266377 POST_SEM ();
267378 return p + offset;
@@ -270,15 +381,15 @@ void * no_FASTCALL __bound_ptr_add(void *p, size_t offset) · 2 unmodified lines
270381 /* return '(p + offset)' for pointer indirection (the resulting must
271382 be strictly inside the region */
272383 #define BOUND_PTR_INDIR(dsize) \
273−void * no_FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
384+void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
274385 { \
275386 size_t addr = (size_t)p; \
276387 \
277− if (no_checking) { \
388+ if (no_checking) \
278389 return p + offset; \
279− } \
280− dprintf(stderr, "%s %s : %p 0x%x start\n", \
281− __FILE__, __FUNCTION__, p, (unsigned)offset); \
390+ \
391+ dprintf(stderr, "%s, %s(): %p 0x%lx\n", \
392+ __FILE__, __FUNCTION__, p, (unsigned long)offset); \
282393 WAIT_SEM (); \
283394 INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
284395 if (tree) { \
@@ -294,16 +405,21 @@ void * no_FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ · 9 unmodified lines
294405 addr -= tree->start; \
295406 } \
296407 if (addr <= tree->size) { \
297− addr += offset + dsize; \
298− if (tree->is_invalid || addr > tree->size) { \
299− fprintf(stderr,"%s %s : %p is outside of the region\n", \
300− __FILE__, __FUNCTION__, p + offset); \
301− if (never_fatal == 0) { \
302− POST_SEM (); \
408+ if (tree->is_invalid || addr + offset + dsize > tree->size) { \
409+ POST_SEM (); \
410+ bound_ptr_indir_error (__FILE__, __FUNCTION__, \
411+ p + offset); \
412+ if (never_fatal <= 0) \
303413 return INVALID_POINTER; /* return an invalid pointer */ \
304− } \
414+ return p + offset; \
305415 } \
306416 } \
417+ else { \
418+ INCR_COUNT(bound_not_found); \
419+ POST_SEM (); \
420+ bound_not_found_warning (__FILE__, __FUNCTION__, p); \
421+ return p + offset; \
422+ } \
307423 } \
308424 POST_SEM (); \
309425 return p + offset; \
@@ -334,90 +450,180 @@ BOUND_PTR_INDIR(16) · 24 unmodified lines
334450 /* called when entering a function to add all the local regions */
335451 void FASTCALL __bound_local_new(void *p1)
336452 {
337− size_t addr, size, fp, *p = p1;
453+ size_t addr, fp, *p = p1;
338454
339455 if (no_checking)
340456 return;
341457 GET_CALLER_FP(fp);
342− dprintf(stderr, "%s, %s local new p1=%p fp=%p\n",
343− __FILE__, __FUNCTION__, p, (void *)fp);
458+ dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
459+ __FILE__, __FUNCTION__, p, (void *)fp);
344460 WAIT_SEM ();
345− for(;;) {
346− addr = p[0];
347− if (addr == 0)
348− break;
461+ while ((addr = p[0])) {
349462 INCR_COUNT(bound_local_new_count);
350− if (addr == 1) {
351− dprintf(stderr, "%s, %s() alloca/vla used\n",
352− __FILE__, __FUNCTION__);
353− }
354− else {
355− addr += fp;
356− size = p[1];
357− dprintf(stderr, "%s, %s() (%p 0x%lx)\n",
358− __FILE__, __FUNCTION__, (void *) addr, (unsigned long) size);
359− tree = splay_insert(addr, size, tree);
360− }
463+ if (addr != 1)
464+ tree = splay_insert(addr + fp, p[1], tree);
361465 p += 2;
362466 }
363467 POST_SEM ();
468+#if BOUND_DEBUG
469+ if (print_calls) {
470+ p = p1;
471+ while ((addr = p[0])) {
472+ if (addr == 1) {
473+ dprintf(stderr, "%s, %s(): alloca/vla used\n",
474+ __FILE__, __FUNCTION__);
475+ }
476+ else {
477+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
478+ __FILE__, __FUNCTION__,
479+ (void *) (addr + fp), (unsigned long) p[1]);
480+ }
481+ p += 2;
482+ }
483+ }
484+#endif
364485 }
365486
366487 /* called when leaving a function to delete all the local regions */
367488 void FASTCALL __bound_local_delete(void *p1)
368489 {
369490 size_t addr, fp, *p = p1;
491+ alloca_list_type *free_list = NULL;
370492
371493 if (no_checking)
372494 return;
373495 GET_CALLER_FP(fp);
374− dprintf(stderr, "%s, %s local delete p1=%p fp=%p\n",
496+ dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
375497 __FILE__, __FUNCTION__, p, (void *)fp);
376498 WAIT_SEM ();
377− for(;;) {
378− addr = p[0];
379− if (addr == 0)
380− break;
499+ while ((addr = p[0])) {
381500 INCR_COUNT(bound_local_delete_count);
382501 if (addr == 1) {
383− while (alloca_list && alloca_list->fp == fp) {
384− alloca_list_type *next = alloca_list->next;
502+ alloca_list_type *last = NULL;
503+ alloca_list_type *cur = alloca_list;
504+
505+ while (cur) {
506+ if (cur->fp == fp) {
507+ if (last)
508+ last->next = cur->next;
509+ else
510+ alloca_list = cur->next;
511+ tree = splay_delete ((size_t) cur->p, tree);
512+ cur->next = free_list;
513+ free_list = cur;
514+ cur = last ? last->next : alloca_list;
515+ }
516+ else {
517+ last = cur;
518+ cur = cur->next;
519+ }
520+ }
521+ }
522+ else
523+ tree = splay_delete(addr + fp, tree);
524+ p += 2;
525+ }
526+ POST_SEM ();
527+ while (free_list) {
528+ alloca_list_type *next = free_list->next;
385529
386− dprintf(stderr, "%s, %s() remove alloca/vla %p\n",
387− __FILE__, __FUNCTION__, alloca_list->p);
388− tree = splay_delete ((size_t) alloca_list->p, tree);
530+ dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
531+ __FILE__, __FUNCTION__, free_list->p);
389532 #if MALLOC_REDIR
390− free_redir (alloca_list);
533+ free_redir (free_list);
391534 #else
392− free (alloca_list);
535+ free (free_list);
393536 #endif
394− alloca_list = next;
537+ free_list = next;
538+ }
539+#if BOUND_DEBUG
540+ if (print_calls) {
541+ p = p1;
542+ while ((addr = p[0])) {
543+ if (addr != 1) {
544+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
545+ __FILE__, __FUNCTION__,
546+ (void *) (addr + fp), (unsigned long) p[1]);
395547 }
548+ p+= 2;
396549 }
397− else {
398− addr += fp;
399− dprintf(stderr, "%s, %s() (%p 0x%lx)\n",
400− __FILE__, __FUNCTION__, (void *) addr, (unsigned long) p[1]);
401− tree = splay_delete(addr, tree);
550+ }
551+#endif
552+}
553+
554+/* used by alloca */
555+void __bound_new_region(void *p, size_t size)
556+{
557+ size_t fp;
558+ alloca_list_type *last;
559+ alloca_list_type *cur;
560+ alloca_list_type *new;
561+
562+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
563+ __FILE__, __FUNCTION__, p, (unsigned long)size);
564+ GET_CALLER_FP (fp);
565+#if MALLOC_REDIR
566+ new = malloc_redir (sizeof (alloca_list_type));
567+#else
568+ new = malloc (sizeof (alloca_list_type));
569+#endif
570+ WAIT_SEM ();
571+ INCR_COUNT(bound_alloca_count);
572+ last = NULL;
573+ cur = alloca_list;
574+ while (cur) {
575+ if (cur->fp == fp && cur->p == p) {
576+ if (last)
577+ last->next = cur->next;
578+ else
579+ alloca_list = cur->next;
580+ tree = splay_delete((size_t)p, tree);
581+ break;
402582 }
403− p += 2;
583+ last = cur;
584+ cur = cur->next;
585+ }
586+ if (no_checking == 0)
587+ tree = splay_insert((size_t)p, size, tree);
588+ if (new) {
589+ new->fp = fp;
590+ new->p = p;
591+ new->next = alloca_list;
592+ alloca_list = new;
404593 }
405594 POST_SEM ();
595+ if (cur) {
596+ dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
597+ __FILE__, __FUNCTION__, cur->p);
598+#if MALLOC_REDIR
599+ free_redir (cur);
600+#else
601+ free (cur);
602+#endif
603+ }
406604 }
407605
408−void __bound_init(void)
606+#if defined(__GNUC__) && (__GNUC__ >= 6)
607+#pragma GCC diagnostic pop
608+#endif
609+
610+void __attribute__((constructor)) __bound_init(void)
409611 {
612+ extern size_t __bounds_start[];
613+ size_t *p;
614+
410615 if (inited)
411616 return;
412617
413618 inited = 1;
414619
620+ print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
415621 print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL;
416622 print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL;
417623 print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
418624 never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
419625
420− dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
626+ dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
421627
422628 INIT_SEM ();
423629
@@ -428,7 +634,7 @@ void __bound_init(void) · 4 unmodified lines
428634 /* tcc -run required RTLD_DEFAULT. Normal usage requires RTLD_NEXT */
429635 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
430636 if (malloc_redir == NULL) {
431− dprintf(stderr, "%s, %s() use RTLD_DEFAULT\n",
637+ dprintf(stderr, "%s, %s(): use RTLD_DEFAULT\n",
432638 __FILE__, __FUNCTION__);
433639 addr = RTLD_DEFAULT;
434640 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
@@ -437,37 +643,109 @@ void __bound_init(void) · 2 unmodified lines
437643 *(void **) (&free_redir) = dlsym (addr, "free");
438644 *(void **) (&realloc_redir) = dlsym (addr, "realloc");
439645 *(void **) (&memalign_redir) = dlsym (addr, "memalign");
440− dprintf(stderr, "%s, %s() malloc_redir %p\n",
646+ dprintf(stderr, "%s, %s(): malloc_redir %p\n",
441647 __FILE__, __FUNCTION__, malloc_redir);
442− dprintf(stderr, "%s, %s() free_redir %p\n",
648+ dprintf(stderr, "%s, %s(): free_redir %p\n",
443649 __FILE__, __FUNCTION__, free_redir);
444− dprintf(stderr, "%s, %s() realloc_redir %p\n",
650+ dprintf(stderr, "%s, %s(): realloc_redir %p\n",
445651 __FILE__, __FUNCTION__, realloc_redir);
446− dprintf(stderr, "%s, %s() memalign_redir %p\n",
652+ dprintf(stderr, "%s, %s(): memalign_redir %p\n",
447653 __FILE__, __FUNCTION__, memalign_redir);
654+ if (malloc_redir == NULL || free_redir == NULL)
655+ bound_alloc_error ("Cannot redirect malloc/free");
656+#if HAVE_PTHREAD_CREATE
657+ *(void **) (&pthread_create_redir) = dlsym (addr, "pthread_create");
658+ dprintf(stderr, "%s, %s(): pthread_create_redir %p\n",
659+ __FILE__, __FUNCTION__, pthread_create_redir);
660+#endif
448661 }
449662 #endif
450663
451− tree = NULL;
664+#ifdef __linux__
665+ {
666+ FILE *fp;
667+ unsigned char found;
668+ unsigned long long start;
669+ unsigned long long end;
670+ unsigned long long ad =
671+ (unsigned long long) __builtin_return_address(0);
672+ char line[1000];
673+
674+ /* Display exec name. Usefull when a lot of code is compiled with tcc */
675+ fp = fopen ("/proc/self/comm", "r");
676+ if (fp) {
677+ memset (exec, 0, sizeof(exec));
678+ fread (exec, 1, sizeof(exec) - 2, fp);
679+ if (strchr(exec,'\n'))
680+ *strchr(exec,'\n') = '\0';
681+ strcat (exec, ":");
682+ fclose (fp);
683+ }
684+ /* check if dlopen is used (is threre a better way?) */
685+ found = 0;
686+ fp = fopen ("/proc/self/maps", "r");
687+ if (fp) {
688+ while (fgets (line, sizeof(line), fp)) {
689+ if (sscanf (line, "%Lx-%Lx", &start, &end) == 2 &&
690+ ad >= start && ad < end) {
691+ found = 1;
692+ break;
693+ }
694+ if (strstr (line,"[heap]"))
695+ break;
696+ }
697+ fclose (fp);
698+ }
699+ if (found == 0) {
700+ use_sem = 1;
701+ no_strdup = 1;
702+ }
703+ }
704+#endif
452705
453− /* save malloc hooks and install bound check hooks */
454− memset (free_reuse_list, 0, sizeof (free_reuse_list));
706+ WAIT_SEM ();
455707
456− dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
457−}
708+#if HAVE_CTYPE
709+ /* XXX: Does not work if locale is changed */
710+ tree = splay_insert((size_t) __ctype_b_loc(),
711+ sizeof (unsigned short *), tree);
712+ tree = splay_insert((size_t) (*__ctype_b_loc() - 128),
713+ 384 * sizeof (unsigned short), tree);
714+ tree = splay_insert((size_t) __ctype_tolower_loc(),
715+ sizeof (__int32_t *), tree);
716+ tree = splay_insert((size_t) (*__ctype_tolower_loc() - 128),
717+ 384 * sizeof (__int32_t), tree);
718+ tree = splay_insert((size_t) __ctype_toupper_loc(),
719+ sizeof (__int32_t *), tree);
720+ tree = splay_insert((size_t) (*__ctype_toupper_loc() - 128),
721+ 384 * sizeof (__int32_t), tree);
722+#endif
723+#if HAVE_ERRNO
724+ tree = splay_insert((size_t) (&errno), sizeof (int), tree);
725+#endif
458726
459−void __bounds_add_static_var (size_t *p)
460−{
461− dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
462727 /* add all static bound check values */
463− WAIT_SEM ();
728+ p = __bounds_start;
464729 while (p[0] != 0) {
465− dprintf(stderr, "%s, %s() (%p 0x%lx)\n",
466− __FILE__, __FUNCTION__, (void *) p[0], (unsigned long) p[1]);
467730 tree = splay_insert(p[0], p[1], tree);
468731 p += 2;
469732 }
470733 POST_SEM ();
734+#if BOUND_DEBUG
735+ if (print_calls) {
736+ p = __bounds_start;
737+ while (p[0] != 0) {
738+ dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
739+ __FILE__, __FUNCTION__,
740+ (void *) p[0], (unsigned long) p[1]);
741+ p += 2;
742+ }
743+ }
744+#endif
745+
746+ no_checking = 0;
747+
748+ dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
471749 }
472750
473751 void __bound_main_arg(char **p)
@@ -476,33 +754,55 @@ void __bound_main_arg(char **p) · 2 unmodified lines
476754
477755 WAIT_SEM ();
478756 while (*p) {
479− dprintf(stderr, "%s, %s() (%p 0x%lx)\n",
480− __FILE__, __FUNCTION__, *p, (unsigned long)(strlen (*p) + 1));
481757 tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
482− p++;
758+ ++p;
483759 }
484− dprintf(stderr, "%s, %s() argv (%p 0x%lx)\n",
485− __FILE__, __FUNCTION__, start, (unsigned long)((char *) p - start));
486760 tree = splay_insert((size_t) start, (char *) p - start, tree);
761+ POST_SEM ();
762+#if BOUND_DEBUG
763+ if (print_calls) {
764+ p = (char **) start;
765+ while (*p) {
766+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
767+ __FILE__, __FUNCTION__,
768+ *p, (unsigned long)(strlen (*p) + 1));
769+ ++p;
770+ }
771+ dprintf(stderr, "%s, %s(): argv %p 0x%lx\n",
772+ __FILE__, __FUNCTION__,
773+ start, (unsigned long)((char *) p - start));
774+ }
775+#endif
487776
488777 #if HAS_ENVIRON
489778 {
490779 extern char **environ;
491780
781+ WAIT_SEM ();
492782 p = environ;
493783 start = (char *) p;
494784 while (*p) {
495− dprintf(stderr, "%s, %s() (%p 0x%lx)\n",
496− __FILE__, __FUNCTION__, *p, (unsigned long)(strlen (*p) + 1));
497785 tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
498− p++;
786+ ++p;
499787 }
500− dprintf(stderr, "%s, %s() environ(%p 0x%lx)\n",
501− __FILE__, __FUNCTION__, start, (unsigned long)((char *) p - start));
502788 tree = splay_insert((size_t) start, (char *) p - start, tree);
789+ POST_SEM ();
790+#if BOUND_DEBUG
791+ if (print_calls) {
792+ p = environ;
793+ while (*p) {
794+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
795+ __FILE__, __FUNCTION__,
796+ *p, (unsigned long)(strlen (*p) + 1));
797+ ++p;
798+ }
799+ dprintf(stderr, "%s, %s(): environ %p 0x%lx\n",
800+ __FILE__, __FUNCTION__,
801+ start, (unsigned long)((char *) p - start));
802+ }
803+#endif
503804 }
504805 #endif
505− POST_SEM ();
506806 }
507807
508808 void __attribute__((destructor)) __bound_exit(void)
@@ -512,16 +812,30 @@ void __attribute__((destructor)) __bound_exit(void) · 3 unmodified lines
512812 "", "malloc", "calloc", "realloc", "memalign", "strdup"
513813 };
514814
515− dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
815+ dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__);
516816
517817 if (inited) {
518818 #if !defined(_WIN32)
519819 if (print_heap) {
520− extern void __libc_freeres ();
820+ extern void __libc_freeres (void);
521821 __libc_freeres ();
522822 }
523823 #endif
524−
824+
825+ no_checking = 1;
826+
827+ WAIT_SEM ();
828+ while (alloca_list) {
829+ alloca_list_type *next = alloca_list->next;
830+
831+ tree = splay_delete ((size_t) alloca_list->p, tree);
832+#if MALLOC_REDIR
833+ free_redir (alloca_list);
834+#else
835+ free (alloca_list);
836+#endif
837+ alloca_list = next;
838+ }
525839 for (i = 0; i < FREE_REUSE_SIZE; i++) {
526840 if (free_reuse_list[i]) {
527841 tree = splay_delete ((size_t) free_reuse_list[i], tree);
@@ -533,11 +847,10 @@ void __attribute__((destructor)) __bound_exit(void) · 5 unmodified lines
533847 }
534848 }
535849 while (tree) {
536− if (print_heap && tree->type != 0) {
537− fprintf (stderr, "%s, %s() %s found size %lu\n",
850+ if (print_heap && tree->type != 0)
851+ fprintf (stderr, "%s, %s(): %s found size %lu\n",
538852 __FILE__, __FUNCTION__, alloc_type[tree->type],
539853 (unsigned long) tree->size);
540− }
541854 tree = splay_delete (tree->start, tree);
542855 }
543856 #if TREE_REUSE
@@ -551,10 +864,11 @@ void __attribute__((destructor)) __bound_exit(void) · 7 unmodified lines
551864 tree_free_list = next;
552865 }
553866 #endif
867+ POST_SEM ();
554868 EXIT_SEM ();
555869 inited = 0;
556−#ifdef BOUND_STATISTIC
557870 if (print_statistic) {
871+#if BOUND_STATISTIC
558872 fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count);
559873 fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count);
560874 fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count);
@@ -584,14 +898,28 @@ void __attribute__((destructor)) __bound_exit(void) · 23 unmodified lines
584898 fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count);
585899 fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count);
586900 fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count);
587− }
901+ fprintf (stderr, "bound_not_found %llu\n", bound_not_found);
902+#endif
903+#if BOUND_STATISTIC_SPLAY
904+ fprintf (stderr, "bound_splay %llu\n", bound_splay);
905+ fprintf (stderr, "bound_splay_end %llu\n", bound_splay_end);
906+ fprintf (stderr, "bound_splay_insert %llu\n", bound_splay_insert);
907+ fprintf (stderr, "bound_splay_delete %llu\n", bound_splay_delete);
588908 #endif
909+ }
589910 }
590911 }
591912
592−/* XXX: we should use a malloc which ensure that it is unlikely that
593− two malloc'ed data have the same address if 'free' are made in
594− between. */
913+#if HAVE_PTHREAD_CREATE
914+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
915+ void *(*start_routine) (void *), void *arg)
916+{
917+ use_sem = 1;
918+ dprintf (stderr, "%s, %s()n", __FILE__, __FUNCTION__);
919+ return pthread_create_redir(thread, attr, start_routine, arg);
920+}
921+#endif
922+
595923 #if MALLOC_REDIR
596924 void *malloc(size_t size)
597925 #else
@@ -603,34 +931,40 @@ void *__bound_malloc(size_t size, const void *caller) · 5 unmodified lines
603931 #if MALLOC_REDIR
604932 /* This will catch the first dlsym call from __bound_init */
605933 if (malloc_redir == NULL) {
606− ptr = &initial_pool[pool_index];
607− pool_index = (pool_index + size + 7) & ~8;
608− dprintf (stderr, "%s, %s initial (%p, 0x%x)\n",
609− __FILE__, __FUNCTION__, ptr, (unsigned)size);
610− return ptr;
934+ __bound_init ();
935+ if (malloc_redir == NULL) {
936+ ptr = &initial_pool[pool_index];
937+ pool_index = (pool_index + size + 15) & ~15;
938+ if (pool_index >= sizeof (initial_pool))
939+ bound_alloc_error ("initial memory pool too small");
940+ dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
941+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
942+ return ptr;
943+ }
611944 }
612945 #endif
613946 /* we allocate one more byte to ensure the regions will be
614947 separated by at least one byte. With the glibc malloc, it may
615948 be in fact not necessary */
616− WAIT_SEM ();
617− INCR_COUNT(bound_malloc_count);
618949 #if MALLOC_REDIR
619− ptr = malloc_redir (size);
950+ ptr = malloc_redir (size + 1);
620951 #else
621952 ptr = malloc(size + 1);
622953 #endif
954+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
955+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
623956
624− dprintf(stderr, "%s, %s (%p, 0x%x)\n",
625− __FILE__, __FUNCTION__, ptr, (unsigned)size);
957+ if (no_checking == 0) {
958+ WAIT_SEM ();
959+ INCR_COUNT(bound_malloc_count);
626960
627− if (ptr) {
628− tree = splay_insert ((size_t) ptr, size, tree);
629− if (tree && tree->start == (size_t) ptr) {
630− tree->type = TCC_TYPE_MALLOC;
961+ if (ptr) {
962+ tree = splay_insert ((size_t) ptr, size, tree);
963+ if (tree && tree->start == (size_t) ptr)
964+ tree->type = TCC_TYPE_MALLOC;
631965 }
966+ POST_SEM ();
632967 }
633− POST_SEM ();
634968 return ptr;
635969 }
636970
@@ -642,10 +976,16 @@ void *__bound_memalign(size_t size, size_t align, const void *caller) · 5 unmodified lines
642976 {
643977 void *ptr;
644978
645− WAIT_SEM ();
646− INCR_COUNT(bound_memalign_count);
647−
648−#ifndef HAVE_MEMALIGN
979+#if HAVE_MEMALIGN
980+ /* we allocate one more byte to ensure the regions will be
981+ separated by at least one byte. With the glibc malloc, it may
982+ be in fact not necessary */
983+#if MALLOC_REDIR
984+ ptr = memalign_redir(size + 1, align);
985+#else
986+ ptr = memalign(size + 1, align);
987+#endif
988+#else
649989 if (align > 4) {
650990 /* XXX: handle it ? */
651991 ptr = NULL;
@@ -657,25 +997,21 @@ void *__bound_memalign(size_t size, size_t align, const void *caller) · 5 unmodified lines
657997 ptr = malloc(size + 1);
658998 #endif
659999 }
660−#else
661− /* we allocate one more byte to ensure the regions will be
662− separated by at least one byte. With the glibc malloc, it may
663− be in fact not necessary */
664−#if MALLOC_REDIR
665− ptr = memalign_redir(size + 1, align);
666−#else
667− ptr = memalign(size + 1, align);
668−#endif
6691000 #endif
670− if (ptr) {
671− dprintf(stderr, "%s, %s (%p, 0x%x)\n",
672− __FILE__, __FUNCTION__, ptr, (unsigned)size);
673− tree = splay_insert((size_t) ptr, size, tree);
674− if (tree && tree->start == (size_t) ptr) {
675− tree->type = TCC_TYPE_MEMALIGN;
1001+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1002+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1003+
1004+ if (no_checking == 0) {
1005+ WAIT_SEM ();
1006+ INCR_COUNT(bound_memalign_count);
1007+
1008+ if (ptr) {
1009+ tree = splay_insert((size_t) ptr, size, tree);
1010+ if (tree && tree->start == (size_t) ptr)
1011+ tree->type = TCC_TYPE_MEMALIGN;
6761012 }
1013+ POST_SEM ();
6771014 }
678− POST_SEM ();
6791015 return ptr;
6801016 }
6811017
@@ -688,7 +1024,7 @@ void __bound_free(void *ptr, const void *caller) · 6 unmodified lines
6881024 size_t addr = (size_t) ptr;
6891025 void *p;
6901026
691− if (ptr == NULL || tree == NULL
1027+ if (ptr == NULL || tree == NULL || no_checking
6921028 #if MALLOC_REDIR
6931029 || ((unsigned char *) ptr >= &initial_pool[0] &&
6941030 (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)])
@@ -696,15 +1032,15 @@ void __bound_free(void *ptr, const void *caller) · 1 unmodified line
6961032 )
6971033 return;
6981034
699− dprintf(stderr, "%s, %s (%p)\n", __FILE__, __FUNCTION__, ptr);
1035+ dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr);
7001036
7011037 WAIT_SEM ();
7021038 INCR_COUNT(bound_free_count);
7031039 tree = splay (addr, tree);
7041040 if (tree->start == addr) {
7051041 if (tree->is_invalid) {
706− bound_error("freeing invalid region");
7071042 POST_SEM ();
1043+ bound_error("freeing invalid region");
7081044 return;
7091045 }
7101046 tree->is_invalid = 1;
@@ -712,17 +1048,16 @@ void __bound_free(void *ptr, const void *caller) · 1 unmodified line
7121048 p = free_reuse_list[free_reuse_index];
7131049 free_reuse_list[free_reuse_index] = ptr;
7141050 free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE;
715− if (p) {
1051+ if (p)
7161052 tree = splay_delete((size_t)p, tree);
717− }
7181053 ptr = p;
7191054 }
1055+ POST_SEM ();
7201056 #if MALLOC_REDIR
7211057 free_redir (ptr);
7221058 #else
7231059 free(ptr);
7241060 #endif
725− POST_SEM ();
7261061 }
7271062
7281063 #if MALLOC_REDIR
@@ -731,6 +1066,8 @@ void *realloc(void *ptr, size_t size) · 2 unmodified lines
7311066 void *__bound_realloc(void *ptr, size_t size, const void *caller)
7321067 #endif
7331068 {
1069+ void *new_ptr;
1070+
7341071 if (size == 0) {
7351072 #if MALLOC_REDIR
7361073 free(ptr);
@@ -739,40 +1076,29 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller) · 2 unmodified lines
7391076 #endif
7401077 return NULL;
7411078 }
742− else if (ptr == NULL) {
1079+
7431080 #if MALLOC_REDIR
744− ptr = realloc_redir (ptr, size);
1081+ new_ptr = realloc_redir (ptr, size);
7451082 #else
746− ptr = realloc (ptr, size);
1083+ new_ptr = realloc (ptr, size);
7471084 #endif
1085+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1086+ __FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
1087+
1088+ if (no_checking == 0) {
7481089 WAIT_SEM ();
7491090 INCR_COUNT(bound_realloc_count);
750− if (ptr) {
751− tree = splay_insert ((size_t) ptr, size, tree);
752− if (tree && tree->start == (size_t) ptr) {
753− tree->type = TCC_TYPE_REALLOC;
754− }
755− }
756− POST_SEM ();
757− return ptr;
758− }
759− else {
760− WAIT_SEM ();
761− tree = splay_delete ((size_t) ptr, tree);
762−#if MALLOC_REDIR
763− ptr = realloc_redir (ptr, size);
764−#else
765− ptr = realloc (ptr, size);
766−#endif
767− if (ptr) {
768− tree = splay_insert ((size_t) ptr, size, tree);
769− if (tree && tree->start == (size_t) ptr) {
1091+
1092+ if (ptr)
1093+ tree = splay_delete ((size_t) ptr, tree);
1094+ if (new_ptr) {
1095+ tree = splay_insert ((size_t) new_ptr, size, tree);
1096+ if (tree && tree->start == (size_t) new_ptr)
7701097 tree->type = TCC_TYPE_REALLOC;
771− }
7721098 }
7731099 POST_SEM ();
774− return ptr;
7751100 }
1101+ return new_ptr;
7761102 }
7771103
7781104 #if MALLOC_REDIR
@@ -787,12 +1113,17 @@ void *__bound_calloc(size_t nmemb, size_t size) · 8 unmodified lines
7871113 #if MALLOC_REDIR
7881114 /* This will catch the first dlsym call from __bound_init */
7891115 if (malloc_redir == NULL) {
790− ptr = &initial_pool[pool_index];
791− pool_index = (pool_index + size + 7) & ~8;
792− dprintf (stderr, "%s, %s initial (%p, 0x%x)\n",
793− __FILE__, __FUNCTION__, ptr, (unsigned)size);
794− memset (ptr, 0, size);
795− return ptr;
1116+ __bound_init ();
1117+ if (malloc_redir == NULL) {
1118+ ptr = &initial_pool[pool_index];
1119+ pool_index = (pool_index + size + 15) & ~15;
1120+ if (pool_index >= sizeof (initial_pool))
1121+ bound_alloc_error ("initial memory pool too small");
1122+ dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
1123+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1124+ memset (ptr, 0, size);
1125+ return ptr;
1126+ }
7961127 }
7971128 #endif
7981129 #if MALLOC_REDIR
@@ -800,15 +1131,19 @@ void *__bound_calloc(size_t nmemb, size_t size) · 1 unmodified line
8001131 #else
8011132 ptr = malloc(size + 1);
8021133 #endif
1134+ dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
1135+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1136+
8031137 if (ptr) {
8041138 memset (ptr, 0, size);
805− WAIT_SEM ();
806− INCR_COUNT(bound_calloc_count);
807− tree = splay_insert ((size_t) ptr, size, tree);
808− if (tree && tree->start == (size_t) ptr) {
809− tree->type = TCC_TYPE_CALLOC;
1139+ if (no_checking == 0) {
1140+ WAIT_SEM ();
1141+ INCR_COUNT(bound_calloc_count);
1142+ tree = splay_insert ((size_t) ptr, size, tree);
1143+ if (tree && tree->start == (size_t) ptr)
1144+ tree->type = TCC_TYPE_CALLOC;
1145+ POST_SEM ();
8101146 }
811− POST_SEM ();
8121147 }
8131148 return ptr;
8141149 }
@@ -819,10 +1154,10 @@ void *__bound_mmap (void *start, size_t size, int prot, · 4 unmodified lines
8191154 {
8201155 void *result;
8211156
822− dprintf(stderr, "%s, %s (%p, 0x%x)\n",
823− __FILE__, __FUNCTION__, start, (unsigned)size);
1157+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1158+ __FILE__, __FUNCTION__, start, (unsigned long)size);
8241159 result = mmap (start, size, prot, flags, fd, offset);
825− if (result) {
1160+ if (result && no_checking == 0) {
8261161 WAIT_SEM ();
8271162 INCR_COUNT(bound_mmap_count);
8281163 tree = splay_insert((size_t)result, size, tree);
@@ -835,161 +1170,151 @@ int __bound_munmap (void *start, size_t size) · 6 unmodified lines
8351170 {
8361171 int result;
8371172
838− dprintf(stderr, "%s, %s (%p, 0x%x)\n",
839− __FILE__, __FUNCTION__, start, (unsigned)size);
840− WAIT_SEM ();
841− INCR_COUNT(bound_munmap_count);
842− tree = splay_delete ((size_t) start, tree);
843− POST_SEM ();
1173+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1174+ __FILE__, __FUNCTION__, start, (unsigned long)size);
1175+ if (start && no_checking == 0) {
1176+ WAIT_SEM ();
1177+ INCR_COUNT(bound_munmap_count);
1178+ tree = splay_delete ((size_t) start, tree);
1179+ POST_SEM ();
1180+ }
8441181 result = munmap (start, size);
8451182 return result;
8461183 }
8471184 #endif
8481185
849−/* used by alloca */
850−void __bound_new_region(void *p, size_t size)
851−{
852− size_t fp;
853− alloca_list_type *last;
854− alloca_list_type *cur;
855−
856− dprintf(stderr, "%s, %s (%p, 0x%x)\n",
857− __FILE__, __FUNCTION__, p, (unsigned)size);
858− WAIT_SEM ();
859− INCR_COUNT(bound_alloca_count);
860− GET_CALLER_FP (fp);
861− last = NULL;
862− cur = alloca_list;
863− while (cur && cur->fp == fp) {
864− if (cur->p == p) {
865− dprintf(stderr, "%s, %s() remove alloca/vla %p\n",
866− __FILE__, __FUNCTION__, alloca_list->p);
867− if (last) {
868− last->next = cur->next;
869− }
870− else {
871− alloca_list = cur->next;
872− }
873− tree = splay_delete((size_t)p, tree);
874−#if MALLOC_REDIR
875− free_redir (cur);
876−#else
877− free (cur);
878−#endif
879− break;
880− }
881− last = cur;
882− cur = cur->next;
883− }
884− tree = splay_insert((size_t)p, size, tree);
885−#if MALLOC_REDIR
886− cur = malloc_redir (sizeof (alloca_list_type));
887−#else
888− cur = malloc (sizeof (alloca_list_type));
889−#endif
890− if (cur) {
891− cur->fp = fp;
892− cur->p = p;
893− cur->next = alloca_list;
894− alloca_list = cur;
895− }
896− POST_SEM ();
897−}
898−
899−#if defined(__GNUC__) && (__GNUC__ >= 6)
900−#pragma GCC diagnostic pop
901−#endif
902−
903−
9041186 /* some useful checked functions */
9051187
9061188 /* check that (p ... p + size - 1) lies inside 'p' region, if any */
9071189 static void __bound_check(const void *p, size_t size, const char *function)
9081190 {
909− if (no_checking)
910− return;
911− if (size == 0)
912− return;
913− p = __bound_ptr_add((void *)p, size);
914− if (p == INVALID_POINTER)
915− bound_error("invalid pointer");
1191+ if (no_checking == 0 && size != 0 &&
1192+ __bound_ptr_add((void *)p, size) == INVALID_POINTER) {
1193+ static char line[100];
1194+ sprintf(line, "invalid pointer %p, size 0x%lx in %s",
1195+ p, (unsigned long)size, function);
1196+ bound_error(line);
1197+ }
9161198 }
9171199
918−void *__bound_memcpy(void *dst, const void *src, size_t size)
1200+static int check_overlap (const void *p1, size_t n1,
1201+ const void *p2, size_t n2,
1202+ const char *function)
9191203 {
920− void* p;
1204+ const void *p1e = (const void *) ((const char *) p1 + n1);
1205+ const void *p2e = (const void *) ((const char *) p2 + n2);
1206+
1207+ if (no_checking == 0 && n1 != 0 && n2 !=0 &&
1208+ ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
1209+ (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
1210+ static char line[100];
1211+ sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s",
1212+ p1, (unsigned long)n1, p2, (unsigned long)n2, function);
1213+ bound_error(line);
1214+ return never_fatal < 0;
1215+ }
1216+ return 0;
1217+}
9211218
1219+void *__bound_memcpy(void *dest, const void *src, size_t n)
1220+{
1221+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1222+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
9221223 INCR_COUNT(bound_mempcy_count);
923− __bound_check(dst, size, "memcpy");
924− __bound_check(src, size, "memcpy");
925− /* check also region overlap */
926− if (no_checking == 0 && src >= dst && src < dst + size)
927− bound_error("overlapping regions in memcpy()");
928−
929− p = memcpy(dst, src, size);
930−
931− return p;
1224+ __bound_check(dest, n, "memcpy dest");
1225+ __bound_check(src, n, "memcpy src");
1226+ if (check_overlap(dest, n, src, n, "memcpy"))
1227+ return dest;
1228+ return memcpy(dest, src, n);
9321229 }
9331230
934−int __bound_memcmp(const void *s1, const void *s2, size_t size)
1231+int __bound_memcmp(const void *s1, const void *s2, size_t n)
9351232 {
1233+ const unsigned char *u1 = (const unsigned char *) s1;
1234+ const unsigned char *u2 = (const unsigned char *) s2;
1235+ int retval = 0;
1236+
1237+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1238+ __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
9361239 INCR_COUNT(bound_memcmp_count);
937− __bound_check(s1, size, "memcmp");
938− __bound_check(s2, size, "memcmp");
939− return memcmp(s1, s2, size);
1240+ for (;;) {
1241+ if ((ssize_t) --n == -1)
1242+ break;
1243+ else if (*u1 != *u2) {
1244+ retval = *u1++ - *u2++;
1245+ break;
1246+ }
1247+ ++u1;
1248+ ++u2;
1249+ }
1250+ __bound_check(s1, (const void *)u1 - s1, "memcmp s1");
1251+ __bound_check(s2, (const void *)u2 - s2, "memcmp s2");
1252+ return retval;
9401253 }
9411254
942−void *__bound_memmove(void *dst, const void *src, size_t size)
1255+void *__bound_memmove(void *dest, const void *src, size_t n)
9431256 {
1257+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1258+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
9441259 INCR_COUNT(bound_memmove_count);
945− __bound_check(dst, size, "memmove");
946− __bound_check(src, size, "memmove");
947− return memmove(dst, src, size);
1260+ __bound_check(dest, n, "memmove dest");
1261+ __bound_check(src, n, "memmove src");
1262+ return memmove(dest, src, n);
9481263 }
9491264
950−void *__bound_memset(void *dst, int c, size_t size)
1265+void *__bound_memset(void *s, int c, size_t n)
9511266 {
1267+ dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
1268+ __FILE__, __FUNCTION__, s, c, (unsigned long)n);
9521269 INCR_COUNT(bound_memset_count);
953− __bound_check(dst, size, "memset");
954− return memset(dst, c, size);
1270+ __bound_check(s, n, "memset");
1271+ return memset(s, c, n);
9551272 }
9561273
9571274 int __bound_strlen(const char *s)
9581275 {
9591276 const char *p = s;
960− size_t len;
9611277
1278+ dprintf(stderr, "%s, %s(): %p\n",
1279+ __FILE__, __FUNCTION__, s);
9621280 INCR_COUNT(bound_strlen_count);
9631281 while (*p++);
964− len = (p - s) - 1;
965− p = __bound_ptr_indir1((char *)s, len);
966− if (p == INVALID_POINTER)
967− bound_error("bad pointer in strlen()");
968− return len;
1282+ __bound_check(s, p - s, "strlen");
1283+ return (p - s) - 1;
9691284 }
9701285
971−char *__bound_strcpy(char *dst, const char *src)
1286+char *__bound_strcpy(char *dest, const char *src)
9721287 {
9731288 size_t len;
974− void *p;
1289+ const char *p = src;
9751290
1291+ dprintf(stderr, "%s, %s(): %p, %p\n",
1292+ __FILE__, __FUNCTION__, dest, src);
9761293 INCR_COUNT(bound_strcpy_count);
977− len = __bound_strlen(src);
978− p = __bound_memcpy(dst, src, len + 1);
979− return p;
1294+ while (*p++);
1295+ len = p - src;
1296+ __bound_check(dest, len, "strcpy dest");
1297+ __bound_check(src, len, "strcpy src");
1298+ if (check_overlap(dest, len, src, len, "strcpy"))
1299+ return dest;
1300+ return strcpy (dest, src);
9801301 }
9811302
982−char *__bound_strncpy(char *dst, const char *src, size_t n)
1303+char *__bound_strncpy(char *dest, const char *src, size_t n)
9831304 {
9841305 size_t len = n;
9851306 const char *p = src;
9861307
1308+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1309+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1310+ INCR_COUNT(bound_strncpy_count);
9871311 while (len-- && *p++);
9881312 len = p - src;
989− INCR_COUNT(bound_strncpy_count);
990− __bound_check(dst, len, "strncpy");
991− __bound_check(src, len, "strncpy");
992− return strncpy (dst, src, n);
1313+ __bound_check(dest, len, "strncpy dest");
1314+ __bound_check(src, len, "strncpy src");
1315+ if (check_overlap(dest, len, src, len, "strncpy"))
1316+ return dest;
1317+ return strncpy(dest, src, n);
9931318 }
9941319
9951320 int __bound_strcmp(const char *s1, const char *s2)
@@ -997,14 +1322,16 @@ int __bound_strcmp(const char *s1, const char *s2) · 1 unmodified line
9971322 const unsigned char *u1 = (const unsigned char *) s1;
9981323 const unsigned char *u2 = (const unsigned char *) s2;
9991324
1325+ dprintf(stderr, "%s, %s(): %p, %p\n",
1326+ __FILE__, __FUNCTION__, s1, s2);
10001327 INCR_COUNT(bound_strcmp_count);
10011328 while (*u1 && *u1 == *u2) {
1002− u1++;
1003− u2++;
1329+ ++u1;
1330+ ++u2;
10041331 }
1005− __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp");
1006− __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp");
1007− return (*u1 - *u2);
1332+ __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp s1");
1333+ __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp s2");
1334+ return *u1 - *u2;
10081335 }
10091336
10101337 int __bound_strncmp(const char *s1, const char *s2, size_t n)
@@ -1013,18 +1340,20 @@ int __bound_strncmp(const char *s1, const char *s2, size_t n) · 2 unmodified lines
10131340 const unsigned char *u2 = (const unsigned char *) s2;
10141341 int retval = 0;
10151342
1343+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1344+ __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
10161345 INCR_COUNT(bound_strncmp_count);
10171346 do {
10181347 if ((ssize_t) --n == -1)
10191348 break;
10201349 else if (*u1 != *u2) {
1021− retval = *u1 - *u2;
1350+ retval = *u1++ - *u2++;
10221351 break;
10231352 }
1024− u2++;
1353+ ++u2;
10251354 } while (*u1++);
1026− __bound_check(s1, ((const char *)u1 - s1) + 1, "strncmp");
1027− __bound_check(s2, ((const char *)u1 - s1) + 1, "strncmp");
1355+ __bound_check(s1, (const char *)u1 - s1, "strncmp s1");
1356+ __bound_check(s2, (const char *)u2 - s2, "strncmp s2");
10281357 return retval;
10291358 }
10301359
@@ -1033,29 +1362,33 @@ char *__bound_strcat(char *dest, const char *src) · 2 unmodified lines
10331362 char *r = dest;
10341363 const char *s = src;
10351364
1365+ dprintf(stderr, "%s, %s(): %p, %p\n",
1366+ __FILE__, __FUNCTION__, dest, src);
10361367 INCR_COUNT(bound_strcat_count);
10371368 while (*dest++);
1038− dest--;
1039− while ((*dest++ = *src++) != 0);
1040− __bound_check(r, dest - r, "strcat");
1041− __bound_check(s, src - s, "strcat");
1042− return r;
1369+ while (*src++);
1370+ __bound_check(r, (dest - r) + (src - s) - 1, "strcat dest");
1371+ __bound_check(s, src - s, "strcat src");
1372+ if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strcat"))
1373+ return dest;
1374+ return strcat(r, s);
10431375 }
10441376
1045−char *__bound_strchr(const char *string, int ch)
1377+char *__bound_strchr(const char *s, int c)
10461378 {
1047− const unsigned char *s = (const unsigned char *) string;
1048− unsigned char c = ch;
1379+ const unsigned char *str = (const unsigned char *) s;
1380+ unsigned char ch = c;
10491381
1382+ dprintf(stderr, "%s, %s(): %p, %d\n",
1383+ __FILE__, __FUNCTION__, s, ch);
10501384 INCR_COUNT(bound_strchr_count);
1051− while (*s) {
1052− if (*s == c) {
1385+ while (*str) {
1386+ if (*str == ch)
10531387 break;
1054− }
1055− s++;
1388+ ++str;
10561389 }
1057− __bound_check(string, ((const char *)s - string) + 1, "strchr");
1058− return *s == c ? (char *) s : NULL;
1390+ __bound_check(s, ((const char *)str - s) + 1, "strchr");
1391+ return *str == ch ? (char *) str : NULL;
10591392 }
10601393
10611394 char *__bound_strdup(const char *s)
@@ -1067,18 +1400,21 @@ char *__bound_strdup(const char *s) · 5 unmodified lines
10671400 while (*p++);
10681401 __bound_check(s, p - s, "strdup");
10691402 #if MALLOC_REDIR
1070− new = malloc_redir (p - s);
1403+ new = malloc_redir ((p - s) + 1);
10711404 #else
1072− new = malloc (p - s);
1405+ new = malloc ((p - s) + 1);
10731406 #endif
1407+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1408+ __FILE__, __FUNCTION__, new, (unsigned long)(p -s));
10741409 if (new) {
1075− WAIT_SEM ();
1076− tree = splay_insert((size_t)new, p - s, tree);
1077− if (tree && tree->start == (size_t) new) {
1078− tree->type = TCC_TYPE_STRDUP;
1410+ if (no_checking == 0 && no_strdup == 0) {
1411+ WAIT_SEM ();
1412+ tree = splay_insert((size_t)new, p - s, tree);
1413+ if (tree && tree->start == (size_t) new)
1414+ tree->type = TCC_TYPE_STRDUP;
1415+ POST_SEM ();
10791416 }
10801417 memcpy (new, s, p - s);
1081− POST_SEM ();
10821418 }
10831419 return new;
10841420 }
@@ -1136,16 +1472,14 @@ char *__bound_strdup(const char *s) · 51 unmodified lines
11361472 #define compare(start,tstart,tsize) (start < tstart ? -1 : \
11371473 start >= tstart+tsize ? 1 : 0)
11381474
1139−/* This is the comparison. */
1140−/* Returns <0 if i<j, =0 if i=j, and >0 if i>j */
1141−
11421475 static Tree * splay (size_t addr, Tree *t)
11431476 /* Splay using the key start (which may or may not be in the tree.) */
1144−/* The starting root is t, and the tree used is defined by rat */
1477+/* The starting root is t, and the tree used is defined by rat */
11451478 {
11461479 Tree N, *l, *r, *y;
11471480 int comp;
11481481
1482+ INCR_COUNT_SPLAY(bound_splay);
11491483 if (t == NULL) return t;
11501484 N.left = N.right = NULL;
11511485 l = r = &N;
@@ -1198,6 +1532,7 @@ static Tree * splay_end (size_t addr, Tree *t) · 46 unmodified lines
11981532 Tree N, *l, *r, *y;
11991533 int comp;
12001534
1535+ INCR_COUNT_SPLAY(bound_splay_end);
12011536 if (t == NULL) return t;
12021537 N.left = N.right = NULL;
12031538 l = r = &N;
@@ -1242,10 +1577,11 @@ static Tree * splay_end (size_t addr, Tree *t) · 38 unmodified lines
12421577
12431578 static Tree * splay_insert(size_t addr, size_t size, Tree * t)
12441579 /* Insert key start into the tree t, if it is not already there. */
1245−/* Return a pointer to the resulting tree. */
1580+/* Return a pointer to the resulting tree. */
12461581 {
12471582 Tree * new;
12481583
1584+ INCR_COUNT_SPLAY(bound_splay_insert);
12491585 if (t != NULL) {
12501586 t = splay(addr,t);
12511587 if (compare(addr, t->start, t->size)==0) {
@@ -1267,7 +1603,7 @@ static Tree * splay_insert(size_t addr, size_t size, Tree * t) · 15 unmodified lines
12671603 #endif
12681604 }
12691605 if (new == NULL) {
1270− bound_alloc_error();
1606+ bound_alloc_error("not enough memory for bound checking code");
12711607 }
12721608 else {
12731609 if (t == NULL) {
@@ -1294,13 +1630,14 @@ static Tree * splay_insert(size_t addr, size_t size, Tree * t) · 20 unmodified lines
12941630
12951631 static Tree * splay_delete(size_t addr, Tree *t)
12961632 /* Deletes addr from the tree if it's there. */
1297−/* Return a pointer to the resulting tree. */
1633+/* Return a pointer to the resulting tree. */
12981634 {
12991635 Tree * x;
13001636
1637+ INCR_COUNT_SPLAY(bound_splay_delete);
13011638 if (t==NULL) return NULL;
13021639 t = splay(addr,t);
1303− if (compare_destroy(addr, t->start) == 0) { /* found it */
1640+ if (compare_destroy(addr, t->start) == 0) { /* found it */
13041641 if (t->left == NULL) {
13051642 x = t->right;
13061643 } else {
@@ -1319,7 +1656,7 @@ static Tree * splay_delete(size_t addr, Tree *t) · 12 unmodified lines
13191656 #endif
13201657 return x;
13211658 } else {
1322− return t; /* It wasn't there */
1659+ return t; /* It wasn't there */
13231660 }
13241661 }
13251662
@@ -1329,7 +1666,8 @@ void splay_printtree(Tree * t, int d) · 3 unmodified lines
13291666 if (t == NULL) return;
13301667 splay_printtree(t->right, d+1);
13311668 for (i=0; i<d; i++) fprintf(stderr," ");
1332− fprintf(stderr,"%p(0x%lx:%u)\n",
1333− (void *) t->start, (unsigned long) t->size, (unsigned)t->is_invalid);
1669+ fprintf(stderr,"%p(0x%lx:%u:%u)\n",
1670+ (void *) t->start, (unsigned long) t->size,
1671+ (unsigned)t->type, (unsigned)t->is_invalid);
13341672 splay_printtree(t->left, d+1);
13351673 }
tcc-doc.texi+38−5
@@ -356,8 +356,10 @@ memory allocations and array/pointer bounds. @option{-g} is implied. Note · 355 unmodified lines
356356 that the generated code is slower and bigger in this case.
357357 The bound checking code is not included in shared libaries. The main executable should always be compiled with the @option{-b}.
358358
359−There are four environment variables that can be used:
359+There are five environment variables that can be used:
360360 @table @option
361+@item TCC_BOUNDS_WARN_POINTER_ADD
362+Print warning when pointer add creates an illegal pointer.
361363 @item TCC_BOUNDS_PRINT_CALLS
362364 Print bound checking calls. Can be used for debugging.
363365 @item TCC_BOUNDS_PRINT_HEAP
@@ -368,10 +370,7 @@ Print statistic information at exit of program. · 4 unmodified lines
368370 Try to continue in case of a bound checking error.
369371 @end table
370372
371−Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) when using libtcc for the moment.
372−
373−@item -ba
374−Generate address checking tests when using @option{-b}. This will be a lot slower but finds more errors.
373+Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
375374
376375 @item -bt N
377376 Display N callers in stack traces. This is useful with @option{-g} or
@@ -947,6 +946,40 @@ Here are some examples of caught errors: · 569 unmodified lines
947946
948947 @end table
949948
949+Signal handlers are not compatible with bounds checking. The code
950+below can be used to protect signal handlers.
951+The call to __bound_checking(1) will disable bounds checking in the
952+whole application.
953+
954+The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to
955+disable bounds checking for some code. This is not recommended.
956+It is better to fix the code.
957+
958+@example
959+
960+#ifdef __BOUNDS_CHECKING_ON
961+extern void __bound_checking (int no_check);
962+#define BOUNDS_CHECKING_OFF __bound_checking(1)
963+#define BOUNDS_CHECKING_ON __bound_checking(-1)
964+#else
965+#define BOUNDS_CHECKING_OFF
966+#define BOUNDS_CHECKING_ON
967+#endif
968+
969+void real_signal_handler(int sig, siginfo_t *info, void *ucontext)
970+@{
971+ ...
972+@}
973+
974+void signal_handler(int sig, void *info, void *ucontext)
975+@{
976+ BOUNDS_CHECKING_OFF;
977+ real_signal_handler(sig, info, data);
978+ BOUNDS_CHECKING_ON;
979+@}
980+
981+@end example
982+
950983 @node Libtcc
951984 @chapter The @code{libtcc} library
952985
tcc.h+8−0
@@ -292,6 +292,9 @@ extern long double strtold (const char *__nptr, char **__endptr); · 291 unmodified lines
292292 #ifndef TCC_LIBTCC1
293293 # define TCC_LIBTCC1 "libtcc1.a"
294294 #endif
295+#ifndef TCC_LIBBCHECK
296+# define TCC_LIBBCHECK "bcheck.o"
297+#endif
295298
296299 /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
297300 #if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
@@ -1375,6 +1378,9 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi · 1077 unmodified lines
13751378 ST_DATA int func_var; /* true if current function is variadic */
13761379 ST_DATA int func_vc;
13771380 ST_DATA const char *funcname;
1381+#ifdef CONFIG_TCC_BCHECK
1382+ST_DATA addr_t func_bound_offset;
1383+#endif
13781384
13791385 ST_FUNC void tcc_debug_start(TCCState *s1);
13801386 ST_FUNC void tcc_debug_end(TCCState *s1);
@@ -1440,6 +1446,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty); · 59 unmodified lines
14401446 #endif
14411447 #ifdef CONFIG_TCC_BCHECK
14421448 ST_FUNC void gbound_args(int nb_args);
1449+ST_FUNC void save_temp_local(int nb_args);
1450+ST_FUNC void restore_temp_local(void);
14431451 #endif
14441452
14451453 /* ------------ tccelf.c ------------ */
tccelf.c+29−4
@@ -85,6 +85,23 @@ ST_FUNC void tccelf_bounds_new(TCCState *s) · 84 unmodified lines
8585 lbounds_section = new_section(s, ".lbounds",
8686 SHT_PROGBITS, SHF_ALLOC);
8787 }
88+
89+ST_FUNC void tcc_add_bcheck(TCCState *s1)
90+{
91+ addr_t *ptr;
92+
93+ if (0 == s1->do_bounds_check)
94+ return;
95+ ptr = section_ptr_add(bounds_section, sizeof(*ptr));
96+ *ptr = 0;
97+ set_elf_sym(symtab_section, 0, 0,
98+ ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
99+ bounds_section->sh_num, "__bounds_start");
100+ /* pull bcheck.o from libtcc1.a */
101+ set_elf_sym(symtab_section, 0, 0,
102+ ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
103+ SHN_UNDEF, "__bound_init");
104+}
88105 #endif
89106
90107 ST_FUNC void tccelf_stab_new(TCCState *s)
@@ -1288,7 +1305,7 @@ static int tcc_add_support(TCCState *s1, const char *filename) · 1197 unmodified lines
12881305 }
12891306 #endif
12901307
1291−static void add_array (const char *section, TCCState *s1, Sym *sym)
1308+static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
12921309 {
12931310 Section *s;
12941311 unsigned char *ptr;
@@ -1296,6 +1313,9 @@ static void add_array (const char *section, TCCState *s1, Sym *sym) · 1 unmodified line
12961313 s = find_section(s1, section);
12971314 if (s) {
12981315 s->sh_flags |= SHF_WRITE;
1316+#ifndef TCC_TARGET_PE
1317+ s->sh_type = sh_type;
1318+#endif
12991319 ptr = section_ptr_add(s, PTR_SIZE);
13001320 memset (ptr, 0, PTR_SIZE);
13011321 put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
@@ -1304,12 +1324,12 @@ static void add_array (const char *section, TCCState *s1, Sym *sym) · 2 unmodified lines
13041324
13051325 ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
13061326 {
1307− add_array (".init_array", s1, sym);
1327+ add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
13081328 }
13091329
13101330 ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
13111331 {
1312− add_array (".fini_array", s1, sym);
1332+ add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
13131333 }
13141334
13151335 /* add tcc runtime libraries */
@@ -1336,7 +1356,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 20 unmodified lines
13361356 if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
13371357 tcc_add_library_err(s1, "pthread");
13381358 tcc_add_library_err(s1, "dl");
1339− tcc_add_support(s1, "bcheck.o");
1359+ tcc_add_support(s1, TCC_LIBBCHECK);
13401360 }
13411361 #endif
13421362 tcc_add_support(s1, TCC_LIBTCC1);
@@ -2040,6 +2060,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, · 697 unmodified lines
20402060 Section *s;
20412061 ElfW(Ehdr) ehdr;
20422062 ElfW(Shdr) shdr, *sh;
2063+ ElfW(Sym) *sym;
20432064
20442065 file_type = s1->output_type;
20452066 shnum = s1->nb_sections;
@@ -2110,6 +2131,10 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, · 64 unmodified lines
21102131 offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
21112132
21122133 sort_syms(s1, symtab_section);
2134+ if (s1->dynsym)
2135+ for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
2136+ if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
2137+ s1->dynsym->sh_info++;
21132138 for(i = 1; i < s1->nb_sections; i++) {
21142139 s = s1->sections[sec_order[i]];
21152140 if (s->sh_type != SHT_NOBITS) {
tccgen.c+122−18
@@ -110,6 +110,16 @@ ST_DATA struct temp_local_variable { · 109 unmodified lines
110110 short align;
111111 } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
112112 short nb_temp_local_vars;
113+#ifdef CONFIG_TCC_BCHECK
114+static short call_nesting;
115+static char used_location[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
116+static int nb_bound_local_param;
117+struct {
118+ unsigned long data_offset;
119+ int v;
120+} *bound_local_param;
121+ST_DATA addr_t func_bound_offset;
122+#endif
113123
114124 static struct scope {
115125 struct scope *prev;
@@ -1383,11 +1393,6 @@ ST_FUNC void save_reg_upstack(int r, int n) · 1267 unmodified lines
13831393 bt = VT_PTR;
13841394 sv.type.t = bt;
13851395 size = type_size(&sv.type, &align);
1386−#ifdef CONFIG_TCC_BCHECK
1387− if (tcc_state->do_bounds_check)
1388− l = loc = (loc - size) & -align;
1389− else
1390−#endif
13911396 l = get_temp_local_var(size,align);
13921397 sv.r = VT_LOCAL | VT_LVAL;
13931398 sv.c.i = l;
@@ -1496,7 +1501,11 @@ static int get_temp_local_var(int size,int align){ · 102 unmodified lines
14961501 found=0;
14971502 for(i=0;i<nb_temp_local_vars;i++){
14981503 temp_var=&arr_temp_local_vars[i];
1499− if(temp_var->size<size||align!=temp_var->align){
1504+ if(temp_var->size<size||align!=temp_var->align
1505+#ifdef CONFIG_TCC_BCHECK
1506+ || (tcc_state->do_bounds_check && used_location[i])
1507+#endif
1508+ ){
15001509 continue;
15011510 }
15021511 /*check if temp_var is free*/
@@ -1596,6 +1605,50 @@ ST_FUNC void gbound_args(int nb_args) · 93 unmodified lines
15961605 vrott(i);
15971606 }
15981607 }
1608+
1609+ST_FUNC void save_temp_local(int nb_args)
1610+{
1611+ int i, j;
1612+
1613+ if (call_nesting++ == 0)
1614+ for (i = 1; i <= nb_args; ++i)
1615+ for (j = 0; j < nb_temp_local_vars; j++)
1616+ if (vtop[1 - i].c.i == arr_temp_local_vars[j].location) {
1617+ used_location[j] = 1;
1618+ break;
1619+ }
1620+}
1621+
1622+ST_FUNC void restore_temp_local()
1623+{
1624+ if (--call_nesting == 0)
1625+ memset (used_location, 0, sizeof (used_location));
1626+}
1627+
1628+static void add_bound_param(CType *type, int size, int v, int c)
1629+{
1630+ addr_t *bounds_ptr;
1631+ /* Add arrays/structs/unions because we always take address */
1632+ int taken = (type->t & VT_ARRAY)
1633+ || (type->t & VT_BTYPE) == VT_STRUCT;
1634+
1635+ if (taken == 0) {
1636+ /* Add parameter to check */
1637+ nb_bound_local_param++;
1638+ bound_local_param =
1639+ tcc_realloc (bound_local_param,
1640+ nb_bound_local_param *
1641+ sizeof (*bound_local_param));
1642+ bound_local_param[nb_bound_local_param-1].data_offset =
1643+ lbounds_section->data_offset;
1644+ bound_local_param[nb_bound_local_param-1].v = v;
1645+ }
1646+ /* add local bound info */
1647+ bounds_ptr = section_ptr_add(lbounds_section,
1648+ 2 * sizeof(addr_t));
1649+ bounds_ptr[0] = c;
1650+ bounds_ptr[1] = taken ? size : ~size;
1651+}
15991652 #endif
16001653
16011654 static void incr_bf_adr(int o)
@@ -3418,6 +3471,7 @@ ST_FUNC void vstore(void) · 1816 unmodified lines
34183471
34193472 vswap();
34203473 /* source */
3474+ vtop->r &= ~VT_MUSTBOUND;
34213475 vpushv(vtop - 2);
34223476 vtop->type.t = VT_PTR;
34233477 gaddrof();
@@ -5083,6 +5137,23 @@ ST_FUNC void unary(void) · 1659 unmodified lines
50835137 if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
50845138 !(vtop->type.t & VT_ARRAY))
50855139 test_lvalue();
5140+#ifdef CONFIG_TCC_BCHECK
5141+ if (tcc_state->do_bounds_check && vtop->sym) {
5142+ int i;
5143+
5144+ /* Mark parameter as being used for address off */
5145+ for (i = 0; i < nb_bound_local_param; i++) {
5146+ if (bound_local_param[i].v == vtop->sym->v) {
5147+ addr_t *bounds_ptr =
5148+ (addr_t *) (lbounds_section->data +
5149+ bound_local_param[i].data_offset);
5150+ bounds_ptr[1] = ~bounds_ptr[1];
5151+ bound_local_param[i].v = 0;
5152+ break;
5153+ }
5154+ }
5155+ }
5156+#endif
50865157 mk_pointer(&vtop->type);
50875158 gaddrof();
50885159 break;
@@ -7435,8 +7506,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 2346 unmodified lines
74357506 if ((r & VT_VALMASK) == VT_LOCAL) {
74367507 sec = NULL;
74377508 #ifdef CONFIG_TCC_BCHECK
7438− if (bcheck && ((type->t & VT_ARRAY) ||
7439− (type->t & VT_BTYPE) == VT_STRUCT)) {
7509+ if (bcheck && v) {
7510+ /* add padding between stack variables */
74407511 loc--;
74417512 }
74427513 #endif
@@ -7444,17 +7515,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1 unmodified line
74447515 addr = loc;
74457516 #ifdef CONFIG_TCC_BCHECK
74467517 /* handles bounds */
7447− /* XXX: currently, since we do only one pass, we cannot track
7448− '&' operators, so we add only arrays/structs/unions */
7449− if (bcheck && ((type->t & VT_ARRAY) ||
7450− (type->t & VT_BTYPE) == VT_STRUCT)) {
7451− addr_t *bounds_ptr;
7452− /* add padding between regions */
7518+ if (bcheck && v) {
7519+ add_bound_param (type, size, v, addr);
7520+ /* add padding between stack variables */
74537521 loc--;
7454− /* then add local bound info */
7455− bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
7456− bounds_ptr[0] = addr;
7457− bounds_ptr[1] = size;
74587522 }
74597523 #endif
74607524 if (v) {
@@ -7633,12 +7697,52 @@ static void gen_function(Sym *sym, AttributeDef *ad) · 172 unmodified lines
76337697 sym_push2(&local_stack, SYM_FIELD, 0, 0);
76347698 local_scope = 1; /* for function parameters */
76357699 gfunc_prolog(sym);
7700+#ifdef CONFIG_TCC_BCHECK
7701+ if (tcc_state->do_bounds_check
7702+ && sym->type.ref->f.func_type != FUNC_ELLIPSIS) {
7703+ Sym *fpar;
7704+
7705+ /* Add function arguments in case & is used */
7706+ for (fpar = sym->type.ref->next; fpar; fpar = fpar->next) {
7707+ Sym *fsym = sym_find (fpar->v & ~SYM_FIELD);
7708+
7709+ if (fsym && (fsym->r & VT_VALMASK) == VT_LOCAL) {
7710+ int align;
7711+ int size = type_size(&fsym->type, &align);
7712+
7713+ if (size > 0)
7714+ add_bound_param (&fsym->type, size, fsym->v, fsym->c);
7715+ }
7716+ }
7717+ }
7718+#endif
76367719 local_scope = 0;
76377720 rsym = 0;
76387721 clear_temp_local_var_list();
76397722 block(0);
76407723 gsym(rsym);
76417724 nocode_wanted = 0;
7725+#ifdef CONFIG_TCC_BCHECK
7726+ if (tcc_state->do_bounds_check) {
7727+ addr_t o = func_bound_offset;
7728+
7729+ /* Remove parameters where address off is not used */
7730+ while (o != lbounds_section->data_offset) {
7731+ addr_t *bounds_ptr = (addr_t *) (lbounds_section->data + o);
7732+ if ((ssize_t) bounds_ptr[1] < 0) {
7733+ lbounds_section->data_offset -= 2 * sizeof (addr_t);
7734+ memmove(bounds_ptr, bounds_ptr + 2,
7735+ lbounds_section->data_offset - o);
7736+ }
7737+ else {
7738+ o += 2 * sizeof (addr_t);
7739+ }
7740+ }
7741+ tcc_free (bound_local_param);
7742+ nb_bound_local_param = 0;
7743+ bound_local_param = NULL;
7744+ }
7745+#endif
76427746 gfunc_epilog();
76437747 cur_text_section->data_offset = ind;
76447748 /* reset local stack */
tccpe.c+1−1
@@ -1897,7 +1897,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 1896 unmodified lines
18971897 const char **pp, *p;
18981898 #ifdef TCC_IS_NATIVE
18991899 if (s1->do_bounds_check)
1900− tcc_add_support(s1, "bcheck.o");
1900+ tcc_add_support(s1, TCC_LIBBCHECK);
19011901 #endif
19021902 tcc_add_support(s1, TCC_LIBTCC1);
19031903 for (pp = libs; 0 != (p = *pp); ++pp) {
tccrun.c+48−18
@@ -86,6 +86,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) · 85 unmodified lines
8686 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
8787 dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
8888 ptr_diff = (char*)prx - (char*)ptr;
89+ close(fd);
8990 }
9091 #else
9192 ptr = tcc_malloc(size);
@@ -119,6 +120,17 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 27 unmodified lines
119120 /* launch the compiled program with the given arguments */
120121 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
121122 {
123+/* PE target overwrites runtime_main */
124+#ifndef TCC_TARGET_PE
125+ typedef void (*init_array_func)(int, char **, char **);
126+ typedef void (*fini_array_func)(void);
127+ init_array_func *__init_array_start;
128+ init_array_func *__init_array_end;
129+ fini_array_func *__fini_array_start;
130+ fini_array_func *__fini_array_end;
131+#endif
132+ int i;
133+ int ret;
122134 int (*prog_main)(int, char **);
123135
124136 s1->runtime_main = s1->nostdlib ? "_start" : "main";
@@ -140,31 +152,34 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 15 unmodified lines
140152 errno = 0; /* clean errno value */
141153
142154 #ifdef CONFIG_TCC_BCHECK
143− if (s1->do_bounds_check) {
144− void (*bound_init)(void);
145− void (*bound_exit)(void);
146− void (*bounds_add_static_var)(size_t *p);
147− size_t *bounds_start;
148− int ret;
149−
155+ if (s1->do_bounds_check)
150156 /* set error function */
151157 s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
152− /* XXX: use .init section so that it also work in binary ? */
153− bound_init = tcc_get_symbol_err(s1, "__bound_init");
154− bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
155− bounds_add_static_var = tcc_get_symbol_err(s1, "__bounds_add_static_var");
156− bounds_start = tcc_get_symbol_err(s1, "__bounds_start");
158+#endif
157159
158− bound_init();
159− bounds_add_static_var (bounds_start);
160+#ifndef TCC_TARGET_PE
161+ __init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
162+ __init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
163+ __fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
164+ __fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
165+
166+ if (__init_array_start && __init_array_end) {
167+ i = 0;
168+ while (&__init_array_start[i] != __init_array_end)
169+ (*__init_array_start[i++])(argc, argv, environ);
170+ }
171+#endif
160172
161− ret = (*prog_main)(argc, argv);
173+ ret = (*prog_main)(argc, argv);
162174
163− bound_exit();
164− return ret;
175+#ifndef TCC_TARGET_PE
176+ if (__fini_array_start && __fini_array_end) {
177+ i = 0;
178+ while (&__fini_array_end[i] != __fini_array_start)
179+ (*__fini_array_end[--i])();
165180 }
166181 #endif
167− return (*prog_main)(argc, argv);
182+ return ret;
168183 }
169184
170185 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
@@ -649,6 +664,9 @@ static void set_exception_handler(void) · 478 unmodified lines
649664 /* install TCC signal handlers to print debug info on fatal
650665 runtime errors */
651666 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
667+#ifdef SIGSTKSZ
668+ sigact.sa_flags |= SA_ONSTACK;
669+#endif
652670 sigact.sa_sigaction = sig_error;
653671 sigemptyset(&sigact.sa_mask);
654672 sigaction(SIGFPE, &sigact, NULL);
@@ -656,6 +674,18 @@ static void set_exception_handler(void) · 1 unmodified line
656674 sigaction(SIGSEGV, &sigact, NULL);
657675 sigaction(SIGBUS, &sigact, NULL);
658676 sigaction(SIGABRT, &sigact, NULL);
677+#ifdef SIGSTKSZ
678+ /* This allows stack overflow to be reported instead of a SEGV */
679+ {
680+ stack_t ss;
681+ static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
682+
683+ ss.ss_sp = stack;
684+ ss.ss_size = SIGSTKSZ;
685+ ss.ss_flags = 0;
686+ sigaltstack(&ss, NULL);
687+ }
688+#endif
659689 }
660690
661691 #else /* WIN32 */
tests/Makefile+1−1
@@ -168,7 +168,7 @@ memtest: · 167 unmodified lines
168168
169169
170170 # memory and bound check auto test
171−BOUNDS_OK = 1 4 8 10 14 16
171+BOUNDS_OK = 1 4 8 10 14 16 18
172172 BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
173173
174174 btest: boundtest.c
tests/boundtest.c+197−0
@@ -230,6 +230,202 @@ int test17() · 229 unmodified lines
230230 return 0;
231231 }
232232
233+#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
234+
235+extern void __bound_never_fatal (int neverfatal);
236+extern const char *__bound_error_msg;
237+
238+static void init18(char *a, char *b)
239+{
240+ memset (a, 'a', 10);
241+ a[3] = 0;
242+ a[9] = 0;
243+ memset (b, 'b', 10);
244+ __bound_error_msg = "";
245+}
246+
247+/* ok (catch all errors) */
248+int test18()
249+{
250+ char pad1[10];
251+ char a[10];
252+ char pad2[10];
253+ char b[10];
254+ char pad3[10];
255+
256+ memset (pad1, 0, sizeof(pad1));
257+ memset (pad2, 0, sizeof(pad2));
258+ memset (pad3, 0, sizeof(pad3));
259+
260+ /* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
261+ __bound_never_fatal (-2);
262+
263+ /* memcpy */
264+ init18(a,b);
265+ memcpy(&a[1],&b[0],10);
266+ CHECK("memcpy dest");
267+ init18(a,b);
268+ memcpy(&a[0],&b[1],10);
269+ CHECK("memcpy src");
270+ init18(a,b);
271+ memcpy(&a[0],&a[3],4);
272+ CHECK("overlapping regions");
273+ init18(a,b);
274+ memcpy(&a[3],&a[0],4);
275+ CHECK("overlapping regions");
276+
277+ /* memcmp */
278+ init18(a,b);
279+ memcmp(&b[1],&b[0],10);
280+ CHECK("memcmp s1");
281+ init18(a,b);
282+ memcmp(&b[0],&b[1],10);
283+ CHECK("memcmp s2");
284+
285+ /* memmove */
286+ init18(a,b);
287+ memmove(&b[1],&b[0],10);
288+ CHECK("memmove dest");
289+ init18(a,b);
290+ memmove(&b[0],&b[1],10);
291+ CHECK("memmove src");
292+
293+ /* memset */
294+ init18(a,b);
295+ memset(&b[1],'b',10);
296+ CHECK("memset");
297+
298+ /* strlen */
299+ init18(a,b);
300+ strlen(&b[0]);
301+ CHECK("strlen");
302+
303+ /* strcpy */
304+ init18(a,b);
305+ strcpy(&a[7], &a[0]);
306+ CHECK("strcpy dest");
307+ init18(a,b);
308+ strcpy(&a[0], &b[7]);
309+ CHECK("strcpy src");
310+ init18(a,b);
311+ strcpy(&a[0], &a[1]);
312+ CHECK("overlapping regions");
313+ init18(a,b);
314+ strcpy(&a[2], &a[0]);
315+ CHECK("overlapping regions");
316+
317+ /* strncpy */
318+ init18(a,b);
319+ strncpy(&a[7], &a[0], 10);
320+ CHECK("strncpy dest");
321+ init18(a,b);
322+ strncpy(&a[0], &b[7], 10);
323+ CHECK("strncpy src");
324+ init18(a,b);
325+ strncpy(&a[0], &a[1], 10);
326+ CHECK("overlapping regions");
327+ strncpy(&a[2], &a[0], 10);
328+ CHECK("overlapping regions");
329+
330+ /* strcmp */
331+ init18(a,b);
332+ strcmp(&b[2], &b[0]);
333+ CHECK("strcmp s1");
334+ init18(a,b);
335+ strcmp(&b[0], &b[2]);
336+ CHECK("strcmp s2");
337+
338+ /* strncmp */
339+ init18(a,b);
340+ strncmp(&b[5], &b[0], 10);
341+ CHECK("strncmp s1");
342+ init18(a,b);
343+ strncmp(&b[0], &b[5], 10);
344+ CHECK("strncmp s2");
345+
346+ /* strcat */
347+ init18(a,b);
348+ strcat(&a[7], &a[0]);
349+ CHECK("strcat dest");
350+ init18(a,b);
351+ strcat(&a[0], &b[5]);
352+ CHECK("strcat src");
353+ init18(a,b);
354+ strcat(&a[0], &a[4]);
355+ CHECK("overlapping regions");
356+ init18(a,b);
357+ strcat(&a[3], &a[0]);
358+ CHECK("overlapping regions");
359+
360+ /* strchr */
361+ init18(a,b);
362+ strchr(&b[0], 'a');
363+ CHECK("strchr");
364+
365+ /* strdup */
366+ init18(a,b);
367+ free(strdup(&b[0]));
368+ CHECK("strdup");
369+
370+ __bound_never_fatal (2);
371+
372+ /* memcpy */
373+ init18(a,b);
374+ memcpy(&a[0],&b[0],10);
375+ init18(a,b);
376+ memcpy(&a[0],&a[3],3);
377+ init18(a,b);
378+ memcpy(&a[3],&a[0],3);
379+
380+ /* memcmp */
381+ init18(a,b);
382+ memcmp(&b[0],&b[0],10);
383+
384+ /* memmove */
385+ init18(a,b);
386+ memmove(&b[0],&b[5],5);
387+ init18(a,b);
388+ memmove(&b[5],&b[0],5);
389+
390+ /* memset */
391+ init18(a,b);
392+ memset(&b[0],'b',10);
393+
394+ /* strlen */
395+ init18(a,b);
396+ strlen (&a[0]);
397+
398+ /* strcpy */
399+ init18(a,b);
400+ strcpy (&a[0], &a[7]);
401+
402+ /* strncpy */
403+ init18(a,b);
404+ strncpy (&a[0], &a[7], 4);
405+
406+ /* strcmp */
407+ init18(a,b);
408+ strcmp (&a[0], &a[4]);
409+
410+ /* strncmp */
411+ init18(a,b);
412+ strncmp (&a[0], &a[4], 10);
413+
414+ /* strcat */
415+ init18(a,b);
416+ strcat (&a[0], &a[7]);
417+
418+ /* strchr */
419+ init18(a,b);
420+ strchr (&a[0], 0);
421+
422+ /* strdup */
423+ init18(a,b);
424+ free (strdup (&a[0]));
425+
426+ return 0;
427+}
428+
233429 int (*table_test[])(void) = {
234430 test1,
235431 test2,
@@ -248,6 +444,7 @@ int (*table_test[])(void) = { · 12 unmodified lines
248444 test15,
249445 test16,
250446 test17,
447+ test18,
251448 };
252449
253450 int main(int argc, char **argv)
x86_64-gen.c+14−3
@@ -637,7 +637,6 @@ static void gcall_or_jmp(int is_jmp) · 636 unmodified lines
637637 }
638638
639639 #if defined(CONFIG_TCC_BCHECK)
640−static addr_t func_bound_offset;
641640 static unsigned long func_bound_ind;
642641
643642 static void gen_bounds_call(int v)
@@ -784,8 +783,10 @@ void gfunc_call(int nb_args) · 140 unmodified lines
784783 int arg;
785784
786785 #ifdef CONFIG_TCC_BCHECK
787− if (tcc_state->do_bounds_check)
786+ if (tcc_state->do_bounds_check) {
787+ save_temp_local (nb_args);
788788 gbound_args(nb_args);
789+ }
789790 #endif
790791
791792 args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
@@ -906,6 +907,10 @@ void gfunc_call(int nb_args) · 114 unmodified lines
906907
907908 }
908909 vtop--;
910+#ifdef CONFIG_TCC_BCHECK
911+ if (tcc_state->do_bounds_check)
912+ restore_temp_local ();
913+#endif
909914 }
910915
911916
@@ -1271,8 +1276,10 @@ void gfunc_call(int nb_args) · 359 unmodified lines
12711276 char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
12721277
12731278 #ifdef CONFIG_TCC_BCHECK
1274− if (tcc_state->do_bounds_check)
1279+ if (tcc_state->do_bounds_check) {
1280+ save_temp_local (nb_args);
12751281 gbound_args(nb_args);
1282+ }
12761283 #endif
12771284
12781285 /* calculate the number of integer/float register arguments, remember
@@ -1453,6 +1460,10 @@ void gfunc_call(int nb_args) · 174 unmodified lines
14531460 if (args_size)
14541461 gadd_sp(args_size);
14551462 vtop--;
1463+#ifdef CONFIG_TCC_BCHECK
1464+ if (tcc_state->do_bounds_check)
1465+ restore_temp_local ();
1466+#endif
14561467 }
14571468
14581469 #define FUNC_PROLOG_SIZE 11
x86_64-link.c+0−85
@@ -287,89 +287,4 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t · 286 unmodified lines
287287 }
288288 }
289289
290−#ifdef CONFIG_TCC_BCHECK
291−ST_FUNC void tcc_add_bcheck(TCCState *s1)
292−{
293− addr_t *ptr;
294− int loc_glob;
295− int sym_index;
296− int bsym_index;
297−
298− if (0 == s1->do_bounds_check)
299− return;
300− /* XXX: add an object file to do that */
301− ptr = section_ptr_add(bounds_section, sizeof(*ptr));
302− *ptr = 0;
303− loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
304− bsym_index = set_elf_sym(symtab_section, 0, 0,
305− ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
306− bounds_section->sh_num, "__bounds_start");
307− /* pull bcheck.o from libtcc1.a */
308− sym_index = set_elf_sym(symtab_section, 0, 0,
309− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
310− SHN_UNDEF, "__bound_init");
311− if (s1->output_type != TCC_OUTPUT_MEMORY) {
312− /* add 'call __bound_init()' in .init section */
313− Section *init_section = find_section(s1, ".init");
314− unsigned char *pinit;
315−#ifdef TCC_TARGET_PE
316− pinit = section_ptr_add(init_section, 8);
317− pinit[0] = 0x55; /* push %rbp */
318− pinit[1] = 0x48; /* mov %rsp,%rpb */
319− pinit[2] = 0x89;
320− pinit[3] = 0xe5;
321− pinit[4] = 0x48; /* sub $0x10,%rsp */
322− pinit[5] = 0x83;
323− pinit[6] = 0xec;
324− pinit[7] = 0x10;
325−#endif
326− pinit = section_ptr_add(init_section, 5);
327− pinit[0] = 0xe8;
328− write32le(pinit + 1, -4);
329− put_elf_reloc(symtab_section, init_section,
330− init_section->data_offset - 4, R_386_PC32, sym_index);
331− /* R_386_PC32 = R_X86_64_PC32 = 2 */
332− pinit = section_ptr_add(init_section, 13);
333− pinit[0] = 0x48; /* mov xx,%rax */
334− pinit[1] = 0xb8;
335− write64le(pinit + 2, 0);
336−#ifdef TCC_TARGET_PE
337− pinit[10] = 0x48; /* mov %rax,%rcx */
338− pinit[11] = 0x89;
339− pinit[12] = 0xc1;
340−#else
341− pinit[10] = 0x48; /* mov %rax,%rdi */
342− pinit[11] = 0x89;
343− pinit[12] = 0xc7;
344−#endif
345− put_elf_reloc(symtab_section, init_section,
346− init_section->data_offset - 11, R_X86_64_64, bsym_index);
347− sym_index = set_elf_sym(symtab_section, 0, 0,
348− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
349− SHN_UNDEF, "__bounds_add_static_var");
350− pinit = section_ptr_add(init_section, 5);
351− pinit[0] = 0xe8;
352− write32le(pinit + 1, -4);
353− put_elf_reloc(symtab_section, init_section,
354− init_section->data_offset - 4, R_386_PC32, sym_index);
355− /* R_386_PC32 = R_X86_64_PC32 = 2 */
356−#ifdef TCC_TARGET_PE
357− {
358− int init_index = set_elf_sym(symtab_section,
359− 0, 0,
360− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
361− init_section->sh_num, "__init_start");
362− Sym sym;
363− init_section->sh_flags |= SHF_EXECINSTR;
364− pinit = section_ptr_add(init_section, 2);
365− pinit[0] = 0xc9; /* leave */
366− pinit[1] = 0xc3; /* ret */
367− sym.c = init_index;
368− add_init_array (s1, &sym);
369− }
370−#endif
371− }
372−}
373−#endif
374−
375290 #endif /* !TARGET_DEFS_ONLY */

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