riscv: asm: Add branch to label
[tinycc.git] / lib / bcheck.c
blobf609a22829e394f272783297cfe851dab67eb8b7
1 /*
2 * Tiny C Memory and bounds checker
3 *
4 * Copyright (c) 2002 Fabrice Bellard
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.
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.
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
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <setjmp.h>
26 #if !defined(__FreeBSD__) \
27 && !defined(__FreeBSD_kernel__) \
28 && !defined(__DragonFly__) \
29 && !defined(__OpenBSD__) \
30 && !defined(__APPLE__) \
31 && !defined(__NetBSD__)
32 #include <malloc.h>
33 #endif
35 #if !defined(_WIN32)
36 #include <unistd.h>
37 #include <sys/syscall.h>
38 #endif
40 #define BOUND_DEBUG (1)
41 #define BOUND_STATISTIC (1)
43 #if BOUND_DEBUG
44 #define dprintf(a...) if (print_calls) { bounds_loc(a); }
45 #else
46 #define dprintf(a...)
47 #endif
49 #ifdef __attribute__
50 /* an __attribute__ macro is defined in the system headers */
51 #undef __attribute__
52 #endif
53 #define FASTCALL __attribute__((regparm(3)))
55 #ifdef _WIN32
56 # define DLL_EXPORT __declspec(dllexport)
57 #else
58 # define DLL_EXPORT
59 #endif
61 #if defined(__FreeBSD__) \
62 || defined(__FreeBSD_kernel__) \
63 || defined(__DragonFly__) \
64 || defined(__OpenBSD__) \
65 || defined(__NetBSD__) \
66 || defined(__dietlibc__)
68 #include <sys/mman.h>
69 #define INIT_SEM()
70 #define EXIT_SEM()
71 #define WAIT_SEM()
72 #define POST_SEM()
73 #define TRY_SEM()
74 #define HAVE_MEMALIGN (0)
75 #define MALLOC_REDIR (0)
76 #define HAVE_PTHREAD_CREATE (0)
77 #define HAVE_CTYPE (0)
78 #define HAVE_ERRNO (0)
79 #define HAVE_SIGNAL (0)
80 #define HAVE_SIGACTION (0)
81 #define HAVE_FORK (0)
82 #define HAVE_TLS_FUNC (0)
83 #define HAVE_TLS_VAR (0)
85 #elif defined(_WIN32)
87 #include <windows.h>
88 #include <signal.h>
89 static CRITICAL_SECTION bounds_sem;
90 #define INIT_SEM() InitializeCriticalSection(&bounds_sem)
91 #define EXIT_SEM() DeleteCriticalSection(&bounds_sem)
92 #define WAIT_SEM() EnterCriticalSection(&bounds_sem)
93 #define POST_SEM() LeaveCriticalSection(&bounds_sem)
94 #define TRY_SEM() TryEnterCriticalSection(&bounds_sem)
95 #define HAVE_MEMALIGN (0)
96 #define MALLOC_REDIR (0)
97 #define HAVE_PTHREAD_CREATE (0)
98 #define HAVE_CTYPE (0)
99 #define HAVE_ERRNO (0)
100 #define HAVE_SIGNAL (1)
101 #define HAVE_SIGACTION (0)
102 #define HAVE_FORK (0)
103 #define HAVE_TLS_FUNC (1)
104 #define HAVE_TLS_VAR (0)
106 #else
108 #define __USE_GNU /* get RTLD_NEXT */
109 #include <sys/mman.h>
110 #include <ctype.h>
111 #include <pthread.h>
112 #include <dlfcn.h>
113 #include <errno.h>
114 #include <signal.h>
115 #ifdef __APPLE__
116 #include <dispatch/dispatch.h>
117 static dispatch_semaphore_t bounds_sem;
118 #define INIT_SEM() bounds_sem = dispatch_semaphore_create(1)
119 #define EXIT_SEM() dispatch_release(*(dispatch_object_t*)&bounds_sem)
120 #define WAIT_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_FOREVER)
121 #define POST_SEM() if (use_sem) dispatch_semaphore_signal(bounds_sem)
122 #define TRY_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_NOW)
123 #elif 0
124 #include <semaphore.h>
125 static sem_t bounds_sem;
126 #define INIT_SEM() sem_init (&bounds_sem, 0, 1)
127 #define EXIT_SEM() sem_destroy (&bounds_sem)
128 #define WAIT_SEM() if (use_sem) while (sem_wait (&bounds_sem) < 0 \
129 && errno == EINTR)
130 #define POST_SEM() if (use_sem) sem_post (&bounds_sem)
131 #define TRY_SEM() if (use_sem) while (sem_trywait (&bounds_sem) < 0 \
132 && errno == EINTR)
133 #elif 0
134 static pthread_mutex_t bounds_mtx;
135 #define INIT_SEM() pthread_mutex_init (&bounds_mtx, NULL)
136 #define EXIT_SEM() pthread_mutex_destroy (&bounds_mtx)
137 #define WAIT_SEM() if (use_sem) pthread_mutex_lock (&bounds_mtx)
138 #define POST_SEM() if (use_sem) pthread_mutex_unlock (&bounds_mtx)
139 #define TRY_SEM() if (use_sem) pthread_mutex_trylock (&bounds_mtx)
140 #else
141 static pthread_spinlock_t bounds_spin;
142 /* about 25% faster then semaphore. */
143 #define INIT_SEM() pthread_spin_init (&bounds_spin, 0)
144 #define EXIT_SEM() pthread_spin_destroy (&bounds_spin)
145 #define WAIT_SEM() if (use_sem) pthread_spin_lock (&bounds_spin)
146 #define POST_SEM() if (use_sem) pthread_spin_unlock (&bounds_spin)
147 #define TRY_SEM() if (use_sem) pthread_spin_trylock (&bounds_spin)
148 #endif
149 #define HAVE_MEMALIGN (1)
150 #define MALLOC_REDIR (1)
151 #define HAVE_PTHREAD_CREATE (1)
152 #define HAVE_CTYPE (1)
153 #define HAVE_ERRNO (1)
154 #define HAVE_SIGNAL (1)
155 #define HAVE_SIGACTION (1)
156 #define HAVE_FORK (1)
157 #if !defined(__APPLE__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
158 #define HAVE_TLS_FUNC (0)
159 #define HAVE_TLS_VAR (1)
160 #else
161 #define HAVE_TLS_FUNC (1)
162 #define HAVE_TLS_VAR (0)
163 #endif
164 #if defined TCC_MUSL || defined __ANDROID__
165 # undef HAVE_CTYPE
166 #endif
167 #endif
169 #if MALLOC_REDIR
170 static void *(*malloc_redir) (size_t);
171 static void *(*calloc_redir) (size_t, size_t);
172 static void (*free_redir) (void *);
173 static void *(*realloc_redir) (void *, size_t);
174 static unsigned int pool_index;
175 static unsigned char __attribute__((aligned(16))) initial_pool[256];
176 #endif
177 #if HAVE_MEMALIGN
178 static void *(*memalign_redir) (size_t, size_t);
179 #endif
180 #if HAVE_PTHREAD_CREATE
181 static int (*pthread_create_redir) (pthread_t *thread,
182 const pthread_attr_t *attr,
183 void *(*start_routine)(void *), void *arg);
184 #endif
185 #if HAVE_SIGNAL
186 typedef void (*bound_sig)(int);
187 static bound_sig (*signal_redir) (int signum, bound_sig handler);
188 #endif
189 #if HAVE_SIGACTION
190 static int (*sigaction_redir) (int signum, const struct sigaction *act,
191 struct sigaction *oldact);
192 #endif
193 #if HAVE_FORK
194 static int (*fork_redir) (void);
195 #endif
197 #define TCC_TYPE_NONE (0)
198 #define TCC_TYPE_MALLOC (1)
199 #define TCC_TYPE_CALLOC (2)
200 #define TCC_TYPE_REALLOC (3)
201 #define TCC_TYPE_MEMALIGN (4)
202 #define TCC_TYPE_STRDUP (5)
204 /* this pointer is generated when bound check is incorrect */
205 #define INVALID_POINTER ((void *)(-2))
207 typedef struct tree_node Tree;
208 struct tree_node {
209 Tree * left, * right;
210 size_t start;
211 size_t size;
212 unsigned char type;
213 unsigned char is_invalid; /* true if pointers outside region are invalid */
216 typedef struct alloca_list_struct {
217 size_t fp;
218 void *p;
219 size_t size;
220 struct alloca_list_struct *next;
221 } alloca_list_type;
223 #if defined(_WIN32)
224 #define BOUND_TID_TYPE DWORD
225 #define BOUND_GET_TID(id) id = GetCurrentThreadId()
226 #elif defined(__OpenBSD__)
227 #define BOUND_TID_TYPE pid_t
228 #define BOUND_GET_TID(id) id = getthrid()
229 #elif defined(__FreeBSD__)
230 #define BOUND_TID_TYPE pid_t
231 #define BOUND_GET_TID(id) syscall (SYS_thr_self, &id)
232 #elif defined(__NetBSD__)
233 #define BOUND_TID_TYPE pid_t
234 #define BOUND_GET_TID(id) id = syscall (SYS__lwp_self)
235 #elif defined(__linux__)
236 #define BOUND_TID_TYPE pid_t
237 #define BOUND_GET_TID(id) id = syscall (SYS_gettid)
238 #else
239 #define BOUND_TID_TYPE int
240 #define BOUND_GET_TID(id) id = 0
241 #endif
243 typedef struct jmp_list_struct {
244 void *penv;
245 size_t fp;
246 size_t end_fp;
247 BOUND_TID_TYPE tid;
248 struct jmp_list_struct *next;
249 } jmp_list_type;
251 #define BOUND_STATISTIC_SPLAY (0)
252 static Tree * splay (size_t addr, Tree *t);
253 static Tree * splay_end (size_t addr, Tree *t);
254 static Tree * splay_insert(size_t addr, size_t size, Tree * t);
255 static Tree * splay_delete(size_t addr, Tree *t);
256 void splay_printtree(Tree * t, int d);
258 /* external interface */
259 void __bounds_checking (int no_check);
260 void __bound_checking_lock (void);
261 void __bound_checking_unlock (void);
262 void __bound_never_fatal (int no_check);
263 DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
264 DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
265 DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
266 DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
267 DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
268 DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
269 DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
270 DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
271 DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
272 void __bound_init(size_t *, int);
273 void __bound_main_arg(int argc, char **argv, char **envp);
274 void __bound_exit(void);
275 void __bound_exit_dll(size_t *);
276 #if !defined(_WIN32)
277 void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
278 off_t offset);
279 int __bound_munmap (void *start, size_t size);
280 DLL_EXPORT void __bound_siglongjmp(jmp_buf env, int val);
281 #endif
282 DLL_EXPORT void __bound_new_region(void *p, size_t size);
283 DLL_EXPORT void __bound_setjmp(jmp_buf env);
284 DLL_EXPORT void __bound_longjmp(jmp_buf env, int val);
285 DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
286 DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
287 DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
288 DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
289 DLL_EXPORT int __bound_strlen(const char *s);
290 DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
291 DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
292 DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
293 DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
294 DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
295 DLL_EXPORT char *__bound_strncat(char *dest, const char *src, size_t n);
296 DLL_EXPORT char *__bound_strchr(const char *string, int ch);
297 DLL_EXPORT char *__bound_strrchr(const char *string, int ch);
298 DLL_EXPORT char *__bound_strdup(const char *s);
300 #if defined(__arm__) && defined(__ARM_EABI__)
301 DLL_EXPORT void *__bound___aeabi_memcpy(void *dst, const void *src, size_t size);
302 DLL_EXPORT void *__bound___aeabi_memmove(void *dst, const void *src, size_t size);
303 DLL_EXPORT void *__bound___aeabi_memmove4(void *dst, const void *src, size_t size);
304 DLL_EXPORT void *__bound___aeabi_memmove8(void *dst, const void *src, size_t size);
305 DLL_EXPORT void *__bound___aeabi_memset(void *dst, int c, size_t size);
306 DLL_EXPORT void *__aeabi_memcpy(void *dst, const void *src, size_t size);
307 DLL_EXPORT void *__aeabi_memmove(void *dst, const void *src, size_t size);
308 DLL_EXPORT void *__aeabi_memmove4(void *dst, const void *src, size_t size);
309 DLL_EXPORT void *__aeabi_memmove8(void *dst, const void *src, size_t size);
310 DLL_EXPORT void *__aeabi_memset(void *dst, int c, size_t size);
311 #endif
313 #if MALLOC_REDIR
314 #define BOUND_MALLOC(a) malloc_redir(a)
315 #define BOUND_MEMALIGN(a,b) memalign_redir(a,b)
316 #define BOUND_FREE(a) free_redir(a)
317 #define BOUND_REALLOC(a,b) realloc_redir(a,b)
318 #define BOUND_CALLOC(a,b) calloc_redir(a,b)
319 #else
320 #define BOUND_MALLOC(a) malloc(a)
321 #define BOUND_MEMALIGN(a,b) memalign(a,b)
322 #define BOUND_FREE(a) free(a)
323 #define BOUND_REALLOC(a,b) realloc(a,b)
324 #define BOUND_CALLOC(a,b) calloc(a,b)
325 DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
326 DLL_EXPORT void *__bound_memalign(size_t align, size_t size, const void *caller);
327 DLL_EXPORT void __bound_free(void *ptr, const void *caller);
328 DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
329 DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
330 #endif
332 #define FREE_REUSE_SIZE (100)
333 static unsigned int free_reuse_index;
334 static void *free_reuse_list[FREE_REUSE_SIZE];
336 static Tree *tree = NULL;
337 #define TREE_REUSE (1)
338 #if TREE_REUSE
339 static Tree *tree_free_list;
340 #endif
341 static alloca_list_type *alloca_list;
342 static jmp_list_type *jmp_list;
344 static unsigned char inited;
345 static unsigned char print_warn_ptr_add;
346 static unsigned char print_calls;
347 static unsigned char print_heap;
348 static unsigned char print_statistic;
349 static unsigned char no_strdup;
350 static unsigned char use_sem;
351 static int never_fatal;
352 #if HAVE_TLS_FUNC
353 #if defined(_WIN32)
354 static int no_checking = 0;
355 static DWORD no_checking_key;
356 #define NO_CHECKING_CHECK() if (!p) { \
357 p = (int *) LocalAlloc(LPTR, sizeof(int)); \
358 if (!p) bound_alloc_error("tls malloc"); \
359 *p = 0; \
360 TlsSetValue(no_checking_key, p); \
362 #define NO_CHECKING_GET() ({ int *p = TlsGetValue(no_checking_key); \
363 NO_CHECKING_CHECK(); \
364 *p; \
366 #define NO_CHECKING_SET(v) { int *p = TlsGetValue(no_checking_key); \
367 NO_CHECKING_CHECK(); \
368 *p = v; \
370 #else
371 static int no_checking = 0;
372 static pthread_key_t no_checking_key;
373 #define NO_CHECKING_CHECK() if (!p) { \
374 p = (int *) BOUND_MALLOC(sizeof(int)); \
375 if (!p) bound_alloc_error("tls malloc"); \
376 *p = 0; \
377 pthread_setspecific(no_checking_key, p); \
379 #define NO_CHECKING_GET() ({ int *p = pthread_getspecific(no_checking_key); \
380 NO_CHECKING_CHECK(); \
381 *p; \
383 #define NO_CHECKING_SET(v) { int *p = pthread_getspecific(no_checking_key); \
384 NO_CHECKING_CHECK(); \
385 *p = v; \
387 #endif
388 #elif HAVE_TLS_VAR
389 static __thread int no_checking = 0;
390 #define NO_CHECKING_GET() no_checking
391 #define NO_CHECKING_SET(v) no_checking = v
392 #else
393 static int no_checking = 0;
394 #define NO_CHECKING_GET() no_checking
395 #define NO_CHECKING_SET(v) no_checking = v
396 #endif
397 static char exec[100];
399 #if BOUND_STATISTIC
400 static unsigned long long bound_ptr_add_count;
401 static unsigned long long bound_ptr_indir1_count;
402 static unsigned long long bound_ptr_indir2_count;
403 static unsigned long long bound_ptr_indir4_count;
404 static unsigned long long bound_ptr_indir8_count;
405 static unsigned long long bound_ptr_indir12_count;
406 static unsigned long long bound_ptr_indir16_count;
407 static unsigned long long bound_local_new_count;
408 static unsigned long long bound_local_delete_count;
409 static unsigned long long bound_malloc_count;
410 static unsigned long long bound_calloc_count;
411 static unsigned long long bound_realloc_count;
412 static unsigned long long bound_free_count;
413 static unsigned long long bound_memalign_count;
414 static unsigned long long bound_mmap_count;
415 static unsigned long long bound_munmap_count;
416 static unsigned long long bound_alloca_count;
417 static unsigned long long bound_setjmp_count;
418 static unsigned long long bound_longjmp_count;
419 static unsigned long long bound_mempcy_count;
420 static unsigned long long bound_memcmp_count;
421 static unsigned long long bound_memmove_count;
422 static unsigned long long bound_memset_count;
423 static unsigned long long bound_strlen_count;
424 static unsigned long long bound_strcpy_count;
425 static unsigned long long bound_strncpy_count;
426 static unsigned long long bound_strcmp_count;
427 static unsigned long long bound_strncmp_count;
428 static unsigned long long bound_strcat_count;
429 static unsigned long long bound_strncat_count;
430 static unsigned long long bound_strchr_count;
431 static unsigned long long bound_strrchr_count;
432 static unsigned long long bound_strdup_count;
433 static unsigned long long bound_not_found;
434 #define INCR_COUNT(x) ++x
435 #else
436 #define INCR_COUNT(x)
437 #endif
438 #if BOUND_STATISTIC_SPLAY
439 static unsigned long long bound_splay;
440 static unsigned long long bound_splay_end;
441 static unsigned long long bound_splay_insert;
442 static unsigned long long bound_splay_delete;
443 #define INCR_COUNT_SPLAY(x) ++x
444 #else
445 #define INCR_COUNT_SPLAY(x)
446 #endif
448 int tcc_backtrace(const char *fmt, ...);
450 /* print a bound error message */
451 #define bound_warning(...) \
452 do { \
453 WAIT_SEM (); \
454 tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__); \
455 POST_SEM (); \
456 } while (0)
458 #define bound_error(...) \
459 do { \
460 bound_warning(__VA_ARGS__); \
461 if (never_fatal == 0) \
462 exit(255); \
463 } while (0)
465 #define bounds_loc(fp, ...) \
466 do { \
467 WAIT_SEM (); \
468 tcc_backtrace("^bcheck.c^\001" __VA_ARGS__); \
469 POST_SEM (); \
470 } while (0)
472 static void bound_alloc_error(const char *s)
474 fprintf(stderr,"FATAL: %s\n",s);
475 exit (1);
478 static void bound_not_found_warning(const char *file, const char *function,
479 void *ptr)
481 dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
484 static void fetch_and_add(int* variable, int value)
486 #if defined __i386__ || defined __x86_64__
487 __asm__ volatile("lock; addl %0, %1"
488 : "+r" (value), "+m" (*variable) // input+output
489 : // No input-only
490 : "memory"
492 #elif defined __arm__
493 extern void fetch_and_add_arm(int* variable, int value);
494 fetch_and_add_arm(variable, value);
495 #elif defined __aarch64__
496 extern void fetch_and_add_arm64(int* variable, int value);
497 fetch_and_add_arm64(variable, value);
498 #elif defined __riscv
499 extern void fetch_and_add_riscv64(int* variable, int value);
500 fetch_and_add_riscv64(variable, value);
501 #else
502 *variable += value;
503 #endif
506 /* enable/disable checking. This can be used in signal handlers. */
507 void __bounds_checking (int no_check)
509 #if HAVE_TLS_FUNC || HAVE_TLS_VAR
510 NO_CHECKING_SET(NO_CHECKING_GET() + no_check);
511 #else
512 fetch_and_add (&no_checking, no_check);
513 #endif
516 void __bound_checking_lock(void)
518 WAIT_SEM ();
521 void __bound_checking_unlock(void)
523 POST_SEM ();
526 /* enable/disable checking. This can be used in signal handlers. */
527 void __bound_never_fatal (int neverfatal)
529 fetch_and_add (&never_fatal, neverfatal);
532 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
533 the end of a region in this case */
534 void * __bound_ptr_add(void *p, size_t offset)
536 size_t addr = (size_t)p;
538 if (NO_CHECKING_GET())
539 return p + offset;
541 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
542 __FILE__, __FUNCTION__, p, (unsigned long)offset);
544 WAIT_SEM ();
545 INCR_COUNT(bound_ptr_add_count);
546 if (tree) {
547 addr -= tree->start;
548 if (addr >= tree->size) {
549 addr = (size_t)p;
550 tree = splay (addr, tree);
551 addr -= tree->start;
553 if (addr >= tree->size) {
554 addr = (size_t)p;
555 tree = splay_end (addr, tree);
556 addr -= tree->start;
558 if (addr <= tree->size) {
559 if (tree->is_invalid || addr + offset > tree->size) {
560 POST_SEM ();
561 if (print_warn_ptr_add)
562 bound_warning("%p is outside of the region", p + offset);
563 if (never_fatal <= 0)
564 return INVALID_POINTER; /* return an invalid pointer */
565 return p + offset;
568 else if (p) { /* Allow NULL + offset. offsetoff is using it. */
569 INCR_COUNT(bound_not_found);
570 POST_SEM ();
571 bound_not_found_warning (__FILE__, __FUNCTION__, p);
572 return p + offset;
575 POST_SEM ();
576 return p + offset;
579 /* return '(p + offset)' for pointer indirection (the resulting must
580 be strictly inside the region */
581 #define BOUND_PTR_INDIR(dsize) \
582 void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
584 size_t addr = (size_t)p; \
586 if (NO_CHECKING_GET()) \
587 return p + offset; \
589 dprintf(stderr, "%s, %s(): %p 0x%lx\n", \
590 __FILE__, __FUNCTION__, p, (unsigned long)offset); \
591 WAIT_SEM (); \
592 INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
593 if (tree) { \
594 addr -= tree->start; \
595 if (addr >= tree->size) { \
596 addr = (size_t)p; \
597 tree = splay (addr, tree); \
598 addr -= tree->start; \
600 if (addr >= tree->size) { \
601 addr = (size_t)p; \
602 tree = splay_end (addr, tree); \
603 addr -= tree->start; \
605 if (addr <= tree->size) { \
606 if (tree->is_invalid || addr + offset + dsize > tree->size) { \
607 POST_SEM (); \
608 bound_warning("%p is outside of the region", p + offset); \
609 if (never_fatal <= 0) \
610 return INVALID_POINTER; /* return an invalid pointer */ \
611 return p + offset; \
614 else { \
615 INCR_COUNT(bound_not_found); \
616 POST_SEM (); \
617 bound_not_found_warning (__FILE__, __FUNCTION__, p); \
618 return p + offset; \
621 POST_SEM (); \
622 return p + offset; \
625 BOUND_PTR_INDIR(1)
626 BOUND_PTR_INDIR(2)
627 BOUND_PTR_INDIR(4)
628 BOUND_PTR_INDIR(8)
629 BOUND_PTR_INDIR(12)
630 BOUND_PTR_INDIR(16)
632 /* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */
633 #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
635 * At least gcc 6.2 complains when __builtin_frame_address is used with
636 * nonzero argument.
638 #pragma GCC diagnostic push
639 #pragma GCC diagnostic ignored "-Wframe-address"
640 #endif
642 /* return the frame pointer of the caller */
643 #define GET_CALLER_FP(fp)\
645 fp = (size_t)__builtin_frame_address(1);\
648 /* called when entering a function to add all the local regions */
649 void FASTCALL __bound_local_new(void *p1)
651 size_t addr, fp, *p = p1;
653 if (NO_CHECKING_GET())
654 return;
655 GET_CALLER_FP(fp);
656 dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
657 __FILE__, __FUNCTION__, p, (void *)fp);
658 WAIT_SEM ();
659 while ((addr = p[0])) {
660 INCR_COUNT(bound_local_new_count);
661 tree = splay_insert(addr + fp, p[1], tree);
662 p += 2;
664 POST_SEM ();
665 #if BOUND_DEBUG
666 if (print_calls) {
667 p = p1;
668 while ((addr = p[0])) {
669 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
670 __FILE__, __FUNCTION__,
671 (void *) (addr + fp), (unsigned long) p[1]);
672 p += 2;
675 #endif
678 /* called when leaving a function to delete all the local regions */
679 void FASTCALL __bound_local_delete(void *p1)
681 size_t addr, fp, *p = p1;
683 if (NO_CHECKING_GET())
684 return;
685 GET_CALLER_FP(fp);
686 dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
687 __FILE__, __FUNCTION__, p, (void *)fp);
688 WAIT_SEM ();
689 while ((addr = p[0])) {
690 INCR_COUNT(bound_local_delete_count);
691 tree = splay_delete(addr + fp, tree);
692 p += 2;
694 if (alloca_list) {
695 alloca_list_type *last = NULL;
696 alloca_list_type *cur = alloca_list;
698 do {
699 if (cur->fp == fp) {
700 if (last)
701 last->next = cur->next;
702 else
703 alloca_list = cur->next;
704 tree = splay_delete ((size_t) cur->p, tree);
705 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
706 __FILE__, __FUNCTION__, cur->p);
707 BOUND_FREE (cur);
708 cur = last ? last->next : alloca_list;
710 else {
711 last = cur;
712 cur = cur->next;
714 } while (cur);
716 if (jmp_list) {
717 jmp_list_type *last = NULL;
718 jmp_list_type *cur = jmp_list;
720 do {
721 if (cur->fp == fp) {
722 if (last)
723 last->next = cur->next;
724 else
725 jmp_list = cur->next;
726 dprintf(stderr, "%s, %s(): remove setjmp %p\n",
727 __FILE__, __FUNCTION__, cur->penv);
728 BOUND_FREE (cur);
729 cur = last ? last->next : jmp_list;
731 else {
732 last = cur;
733 cur = cur->next;
735 } while (cur);
738 POST_SEM ();
739 #if BOUND_DEBUG
740 if (print_calls) {
741 p = p1;
742 while ((addr = p[0])) {
743 if (addr != 1) {
744 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
745 __FILE__, __FUNCTION__,
746 (void *) (addr + fp), (unsigned long) p[1]);
748 p+= 2;
751 #endif
754 /* used by alloca */
755 void __bound_new_region(void *p, size_t size)
757 size_t fp;
758 alloca_list_type *last;
759 alloca_list_type *cur;
760 alloca_list_type *new;
762 if (NO_CHECKING_GET())
763 return;
765 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
766 __FILE__, __FUNCTION__, p, (unsigned long)size);
767 GET_CALLER_FP (fp);
768 new = BOUND_MALLOC (sizeof (alloca_list_type));
769 WAIT_SEM ();
770 INCR_COUNT(bound_alloca_count);
771 last = NULL;
772 cur = alloca_list;
773 while (cur) {
774 #if defined(__i386__) || (defined(__arm__) && !defined(__ARM_EABI__))
775 int align = 4;
776 #elif defined(__arm__)
777 int align = 8;
778 #else
779 int align = 16;
780 #endif
781 void *cure = (void *)((char *)cur->p + ((cur->size + align) & -align));
782 void *pe = (void *)((char *)p + ((size + align) & -align));
783 if (cur->fp == fp && ((cur->p <= p && cure > p) ||
784 (p <= cur->p && pe > cur->p))) {
785 if (last)
786 last->next = cur->next;
787 else
788 alloca_list = cur->next;
789 tree = splay_delete((size_t)cur->p, tree);
790 break;
792 last = cur;
793 cur = cur->next;
795 tree = splay_insert((size_t)p, size, tree);
796 if (new) {
797 new->fp = fp;
798 new->p = p;
799 new->size = size;
800 new->next = alloca_list;
801 alloca_list = new;
803 POST_SEM ();
804 if (cur) {
805 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
806 __FILE__, __FUNCTION__, cur->p);
807 BOUND_FREE (cur);
811 void __bound_setjmp(jmp_buf env)
813 jmp_list_type *jl;
814 void *e = (void *) env;
816 if (NO_CHECKING_GET() == 0) {
817 dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
818 WAIT_SEM ();
819 INCR_COUNT(bound_setjmp_count);
820 jl = jmp_list;
821 while (jl) {
822 if (jl->penv == e)
823 break;
824 jl = jl->next;
826 if (jl == NULL) {
827 jl = BOUND_MALLOC (sizeof (jmp_list_type));
828 if (jl) {
829 jl->penv = e;
830 jl->next = jmp_list;
831 jmp_list = jl;
834 if (jl) {
835 size_t fp;
837 GET_CALLER_FP (fp);
838 jl->fp = fp;
839 jl->end_fp = (size_t)__builtin_frame_address(0);
840 BOUND_GET_TID(jl->tid);
842 POST_SEM ();
846 static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
848 jmp_list_type *jl;
849 void *e;
850 BOUND_TID_TYPE tid;
852 if (NO_CHECKING_GET() == 0) {
853 e = (void *)env;
854 BOUND_GET_TID(tid);
855 dprintf(stderr, "%s, %s(): %p\n", __FILE__, func, e);
856 WAIT_SEM();
857 INCR_COUNT(bound_longjmp_count);
858 jl = jmp_list;
859 while (jl) {
860 if (jl->penv == e && jl->tid == tid) {
861 size_t start_fp = (size_t)__builtin_frame_address(0);
862 size_t end_fp = jl->end_fp;
863 jmp_list_type *cur = jmp_list;
864 jmp_list_type *last = NULL;
866 while (cur->penv != e || cur->tid != tid) {
867 if (cur->tid == tid) {
868 dprintf(stderr, "%s, %s(): remove setjmp %p\n",
869 __FILE__, func, cur->penv);
870 if (last)
871 last->next = cur->next;
872 else
873 jmp_list = cur->next;
874 BOUND_FREE (cur);
875 cur = last ? last->next : jmp_list;
877 else {
878 last = cur;
879 cur = cur->next;
882 for (;;) {
883 Tree *t = tree;
884 alloca_list_type *last;
885 alloca_list_type *cur;
887 while (t && (t->start < start_fp || t->start > end_fp))
888 if (t->start < start_fp)
889 t = t->right;
890 else
891 t = t->left;
892 if (t == NULL)
893 break;
894 last = NULL;
895 cur = alloca_list;
896 while (cur) {
897 if ((size_t) cur->p == t->start) {
898 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
899 __FILE__, func, cur->p);
900 if (last)
901 last->next = cur->next;
902 else
903 alloca_list = cur->next;
904 BOUND_FREE (cur);
905 break;
907 last = cur;
908 cur = cur->next;
910 dprintf(stderr, "%s, %s(): delete %p\n",
911 __FILE__, func, (void *) t->start);
912 tree = splay_delete(t->start, tree);
914 break;
916 jl = jl->next;
918 POST_SEM();
920 #if !defined(_WIN32)
921 sig ? siglongjmp(env, val) :
922 #endif
923 longjmp (env, val);
926 void __bound_longjmp(jmp_buf env, int val)
928 __bound_long_jump(env,val, 0, __FUNCTION__);
931 #if !defined(_WIN32)
932 void __bound_siglongjmp(jmp_buf env, int val)
934 __bound_long_jump(env,val, 1, __FUNCTION__);
936 #endif
938 #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
939 #pragma GCC diagnostic pop
940 #endif
942 void __bound_init(size_t *p, int mode)
944 dprintf(stderr, "%s, %s(): start %s\n", __FILE__, __FUNCTION__,
945 mode < 0 ? "lazy" : mode == 0 ? "normal use" : "for -run");
947 if (inited) {
948 WAIT_SEM();
949 goto add_bounds;
951 inited = 1;
953 #if HAVE_TLS_FUNC
954 #if defined(_WIN32)
955 no_checking_key = TlsAlloc();
956 TlsSetValue(no_checking_key, &no_checking);
957 #else
958 pthread_key_create(&no_checking_key, NULL);
959 pthread_setspecific(no_checking_key, &no_checking);
960 #endif
961 #endif
962 NO_CHECKING_SET(1);
964 print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
965 print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL;
966 print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL;
967 print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
968 never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
970 INIT_SEM ();
972 #if MALLOC_REDIR
974 void *addr = mode > 0 ? RTLD_DEFAULT : RTLD_NEXT;
976 /* tcc -run required RTLD_DEFAULT. Normal usage requires RTLD_NEXT,
977 but using RTLD_NEXT with -run segfaults on MacOS in dyld as the
978 generated code segment isn't registered with dyld and hence the
979 caller image of dlsym isn't known to it */
980 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
981 if (malloc_redir == NULL) {
982 dprintf(stderr, "%s, %s(): use RTLD_DEFAULT\n",
983 __FILE__, __FUNCTION__);
984 addr = RTLD_DEFAULT;
985 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
987 *(void **) (&calloc_redir) = dlsym (addr, "calloc");
988 *(void **) (&free_redir) = dlsym (addr, "free");
989 *(void **) (&realloc_redir) = dlsym (addr, "realloc");
990 *(void **) (&memalign_redir) = dlsym (addr, "memalign");
991 dprintf(stderr, "%s, %s(): malloc_redir %p\n",
992 __FILE__, __FUNCTION__, malloc_redir);
993 dprintf(stderr, "%s, %s(): free_redir %p\n",
994 __FILE__, __FUNCTION__, free_redir);
995 dprintf(stderr, "%s, %s(): realloc_redir %p\n",
996 __FILE__, __FUNCTION__, realloc_redir);
997 dprintf(stderr, "%s, %s(): memalign_redir %p\n",
998 __FILE__, __FUNCTION__, memalign_redir);
999 if (malloc_redir == NULL || free_redir == NULL)
1000 bound_alloc_error ("Cannot redirect malloc/free");
1001 #if HAVE_PTHREAD_CREATE
1002 *(void **) (&pthread_create_redir) = dlsym (addr, "pthread_create");
1003 dprintf(stderr, "%s, %s(): pthread_create_redir %p\n",
1004 __FILE__, __FUNCTION__, pthread_create_redir);
1005 if (pthread_create_redir == NULL)
1006 bound_alloc_error ("Cannot redirect pthread_create");
1007 #endif
1008 #if HAVE_SIGNAL
1009 *(void **) (&signal_redir) = dlsym (addr, "signal");
1010 dprintf(stderr, "%s, %s(): signal_redir %p\n",
1011 __FILE__, __FUNCTION__, signal_redir);
1012 if (signal_redir == NULL)
1013 bound_alloc_error ("Cannot redirect signal");
1014 #endif
1015 #if HAVE_SIGACTION
1016 *(void **) (&sigaction_redir) = dlsym (addr, "sigaction");
1017 dprintf(stderr, "%s, %s(): sigaction_redir %p\n",
1018 __FILE__, __FUNCTION__, sigaction_redir);
1019 if (sigaction_redir == NULL)
1020 bound_alloc_error ("Cannot redirect sigaction");
1021 #endif
1022 #if HAVE_FORK
1023 *(void **) (&fork_redir) = dlsym (addr, "fork");
1024 dprintf(stderr, "%s, %s(): fork_redir %p\n",
1025 __FILE__, __FUNCTION__, fork_redir);
1026 if (fork_redir == NULL)
1027 bound_alloc_error ("Cannot redirect fork");
1028 #endif
1030 #endif
1032 #ifdef __linux__
1034 FILE *fp;
1035 unsigned char found;
1036 unsigned long start;
1037 unsigned long end;
1038 unsigned long ad =
1039 (unsigned long) __builtin_return_address(0);
1040 char line[1000];
1042 /* Display exec name. Usefull when a lot of code is compiled with tcc */
1043 fp = fopen ("/proc/self/comm", "r");
1044 if (fp) {
1045 memset (exec, 0, sizeof(exec));
1046 fread (exec, 1, sizeof(exec) - 2, fp);
1047 if (strchr(exec,'\n'))
1048 *strchr(exec,'\n') = '\0';
1049 strcat (exec, ":");
1050 fclose (fp);
1052 /* check if dlopen is used (is threre a better way?) */
1053 found = 0;
1054 fp = fopen ("/proc/self/maps", "r");
1055 if (fp) {
1056 while (fgets (line, sizeof(line), fp)) {
1057 if (sscanf (line, "%lx-%lx", &start, &end) == 2 &&
1058 ad >= start && ad < end) {
1059 found = 1;
1060 break;
1062 if (strstr (line,"[heap]"))
1063 break;
1065 fclose (fp);
1067 if (found == 0) {
1068 use_sem = 1;
1069 no_strdup = 1;
1072 #endif
1074 WAIT_SEM ();
1076 #if HAVE_CTYPE
1077 #ifdef __APPLE__
1078 tree = splay_insert((size_t) &_DefaultRuneLocale,
1079 sizeof (_DefaultRuneLocale), tree);
1080 #else
1081 /* XXX: Does not work if locale is changed */
1082 tree = splay_insert((size_t) __ctype_b_loc(),
1083 sizeof (unsigned short *), tree);
1084 tree = splay_insert((size_t) (*__ctype_b_loc() - 128),
1085 384 * sizeof (unsigned short), tree);
1086 tree = splay_insert((size_t) __ctype_tolower_loc(),
1087 sizeof (__int32_t *), tree);
1088 tree = splay_insert((size_t) (*__ctype_tolower_loc() - 128),
1089 384 * sizeof (__int32_t), tree);
1090 tree = splay_insert((size_t) __ctype_toupper_loc(),
1091 sizeof (__int32_t *), tree);
1092 tree = splay_insert((size_t) (*__ctype_toupper_loc() - 128),
1093 384 * sizeof (__int32_t), tree);
1094 #endif
1095 #endif
1096 #if HAVE_ERRNO
1097 tree = splay_insert((size_t) (&errno), sizeof (int), tree);
1098 #endif
1100 add_bounds:
1101 if (!p)
1102 goto no_bounds;
1104 /* add all static bound check values */
1105 while (p[0] != 0) {
1106 tree = splay_insert(p[0], p[1], tree);
1107 #if BOUND_DEBUG
1108 if (print_calls) {
1109 dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
1110 __FILE__, __FUNCTION__,
1111 (void *) p[0], (unsigned long) p[1]);
1113 #endif
1114 p += 2;
1116 no_bounds:
1118 POST_SEM ();
1119 NO_CHECKING_SET(0);
1120 dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
1123 void
1124 #if (defined(__GLIBC__) && (__GLIBC_MINOR__ >= 4)) || defined(_WIN32)
1125 __attribute__((constructor))
1126 #endif
1127 __bound_main_arg(int argc, char **argv, char **envp)
1129 __bound_init (0, -1);
1130 if (argc && argv) {
1131 int i;
1133 WAIT_SEM ();
1134 for (i = 0; i < argc; i++)
1135 tree = splay_insert((size_t) argv[i], strlen (argv[i]) + 1, tree);
1136 tree = splay_insert((size_t) argv, (argc + 1) * sizeof(char *), tree);
1137 POST_SEM ();
1138 #if BOUND_DEBUG
1139 if (print_calls) {
1140 for (i = 0; i < argc; i++)
1141 dprintf(stderr, "%s, %s(): arg %p 0x%lx\n",
1142 __FILE__, __FUNCTION__,
1143 argv[i], (unsigned long)(strlen (argv[i]) + 1));
1144 dprintf(stderr, "%s, %s(): argv %p %d\n",
1145 __FILE__, __FUNCTION__, argv,
1146 (int)((argc + 1) * sizeof(char *)));
1148 #endif
1151 if (envp && *envp) {
1152 char **p = envp;
1154 WAIT_SEM ();
1155 while (*p) {
1156 tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
1157 ++p;
1159 tree = splay_insert((size_t) envp, (++p - envp) * sizeof(char *), tree);
1160 POST_SEM ();
1161 #if BOUND_DEBUG
1162 if (print_calls) {
1163 p = envp;
1164 while (*p) {
1165 dprintf(stderr, "%s, %s(): env %p 0x%lx\n",
1166 __FILE__, __FUNCTION__,
1167 *p, (unsigned long)(strlen (*p) + 1));
1168 ++p;
1170 dprintf(stderr, "%s, %s(): environ %p %d\n",
1171 __FILE__, __FUNCTION__, envp,
1172 (int)((++p - envp) * sizeof(char *)));
1174 #endif
1178 void __attribute__((destructor)) __bound_exit(void)
1180 int i;
1181 static const char * const alloc_type[] = {
1182 "", "malloc", "calloc", "realloc", "memalign", "strdup"
1185 dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__);
1187 if (inited) {
1188 #if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \
1189 !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
1190 !defined(__ANDROID__)
1191 if (print_heap) {
1192 extern void __libc_freeres (void);
1193 __libc_freeres ();
1195 #endif
1197 NO_CHECKING_SET(1);
1199 TRY_SEM ();
1200 while (alloca_list) {
1201 alloca_list_type *next = alloca_list->next;
1203 tree = splay_delete ((size_t) alloca_list->p, tree);
1204 BOUND_FREE (alloca_list);
1205 alloca_list = next;
1207 while (jmp_list) {
1208 jmp_list_type *next = jmp_list->next;
1210 BOUND_FREE (jmp_list);
1211 jmp_list = next;
1213 for (i = 0; i < FREE_REUSE_SIZE; i++) {
1214 if (free_reuse_list[i]) {
1215 tree = splay_delete ((size_t) free_reuse_list[i], tree);
1216 BOUND_FREE (free_reuse_list[i]);
1219 while (tree) {
1220 if (print_heap && tree->type != 0)
1221 fprintf (stderr, "%s, %s(): %s found size %lu\n",
1222 __FILE__, __FUNCTION__, alloc_type[tree->type],
1223 (unsigned long) tree->size);
1224 tree = splay_delete (tree->start, tree);
1226 #if TREE_REUSE
1227 while (tree_free_list) {
1228 Tree *next = tree_free_list->left;
1229 BOUND_FREE (tree_free_list);
1230 tree_free_list = next;
1232 #endif
1233 POST_SEM ();
1234 EXIT_SEM ();
1235 #if HAVE_TLS_FUNC
1236 #if defined(_WIN32)
1237 TlsFree(no_checking_key);
1238 #else
1239 pthread_key_delete(no_checking_key);
1240 #endif
1241 #endif
1242 inited = 0;
1243 if (print_statistic) {
1244 #if BOUND_STATISTIC
1245 fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count);
1246 fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count);
1247 fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count);
1248 fprintf (stderr, "bound_ptr_indir4_count %llu\n", bound_ptr_indir4_count);
1249 fprintf (stderr, "bound_ptr_indir8_count %llu\n", bound_ptr_indir8_count);
1250 fprintf (stderr, "bound_ptr_indir12_count %llu\n", bound_ptr_indir12_count);
1251 fprintf (stderr, "bound_ptr_indir16_count %llu\n", bound_ptr_indir16_count);
1252 fprintf (stderr, "bound_local_new_count %llu\n", bound_local_new_count);
1253 fprintf (stderr, "bound_local_delete_count %llu\n", bound_local_delete_count);
1254 fprintf (stderr, "bound_malloc_count %llu\n", bound_malloc_count);
1255 fprintf (stderr, "bound_calloc_count %llu\n", bound_calloc_count);
1256 fprintf (stderr, "bound_realloc_count %llu\n", bound_realloc_count);
1257 fprintf (stderr, "bound_free_count %llu\n", bound_free_count);
1258 fprintf (stderr, "bound_memalign_count %llu\n", bound_memalign_count);
1259 fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count);
1260 fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count);
1261 fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count);
1262 fprintf (stderr, "bound_setjmp_count %llu\n", bound_setjmp_count);
1263 fprintf (stderr, "bound_longjmp_count %llu\n", bound_longjmp_count);
1264 fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count);
1265 fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count);
1266 fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count);
1267 fprintf (stderr, "bound_memset_count %llu\n", bound_memset_count);
1268 fprintf (stderr, "bound_strlen_count %llu\n", bound_strlen_count);
1269 fprintf (stderr, "bound_strcpy_count %llu\n", bound_strcpy_count);
1270 fprintf (stderr, "bound_strncpy_count %llu\n", bound_strncpy_count);
1271 fprintf (stderr, "bound_strcmp_count %llu\n", bound_strcmp_count);
1272 fprintf (stderr, "bound_strncmp_count %llu\n", bound_strncmp_count);
1273 fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count);
1274 fprintf (stderr, "bound_strncat_count %llu\n", bound_strncat_count);
1275 fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count);
1276 fprintf (stderr, "bound_strrchr_count %llu\n", bound_strrchr_count);
1277 fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count);
1278 fprintf (stderr, "bound_not_found %llu\n", bound_not_found);
1279 #endif
1280 #if BOUND_STATISTIC_SPLAY
1281 fprintf (stderr, "bound_splay %llu\n", bound_splay);
1282 fprintf (stderr, "bound_splay_end %llu\n", bound_splay_end);
1283 fprintf (stderr, "bound_splay_insert %llu\n", bound_splay_insert);
1284 fprintf (stderr, "bound_splay_delete %llu\n", bound_splay_delete);
1285 #endif
1290 void __bound_exit_dll(size_t *p)
1292 dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
1294 if (p) {
1295 WAIT_SEM ();
1296 while (p[0] != 0) {
1297 tree = splay_delete(p[0], tree);
1298 #if BOUND_DEBUG
1299 if (print_calls) {
1300 dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n",
1301 __FILE__, __FUNCTION__,
1302 (void *) p[0], (unsigned long) p[1]);
1304 #endif
1305 p += 2;
1307 POST_SEM ();
1311 #if HAVE_PTHREAD_CREATE
1312 typedef struct {
1313 void *(*start_routine) (void *);
1314 void *arg;
1315 sigset_t old_mask;
1316 } bound_thread_create_type;
1318 static void *bound_thread_create(void *bdata)
1320 bound_thread_create_type *data = (bound_thread_create_type *) bdata;
1321 void *retval;
1322 #if HAVE_TLS_FUNC
1323 int *p = (int *) BOUND_MALLOC(sizeof(int));
1325 if (!p) bound_alloc_error("bound_thread_create malloc");
1326 *p = 0;
1327 pthread_setspecific(no_checking_key, p);
1328 #endif
1329 pthread_sigmask(SIG_SETMASK, &data->old_mask, NULL);
1330 retval = data->start_routine(data->arg);
1331 #if HAVE_TLS_FUNC
1332 pthread_setspecific(no_checking_key, NULL);
1333 BOUND_FREE (p);
1334 #endif
1335 BOUND_FREE (data);
1336 return retval;
1339 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
1340 void *(*start_routine) (void *), void *arg)
1342 int retval;
1343 bound_thread_create_type *data;
1344 sigset_t mask;
1345 sigset_t old_mask;
1347 use_sem = 1;
1348 dprintf (stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
1349 sigfillset(&mask);
1350 pthread_sigmask(SIG_SETMASK, &mask, &old_mask);
1351 data = (bound_thread_create_type *) BOUND_MALLOC(sizeof(bound_thread_create_type));
1352 if (!data) bound_alloc_error("bound_thread_create malloc");
1353 data->start_routine = start_routine;
1354 data->arg = arg;
1355 data->old_mask = old_mask;
1356 retval = pthread_create_redir(thread, attr, bound_thread_create, data);
1357 pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
1358 return retval;
1360 #endif
1362 #if HAVE_SIGNAL || HAVE_SIGACTION
1363 typedef union {
1364 #if HAVE_SIGNAL
1365 bound_sig signal_handler;
1366 #endif
1367 #if HAVE_SIGACTION
1368 void (*sig_handler)(int);
1369 void (*sig_sigaction)(int, siginfo_t *, void *);
1370 #endif
1371 } bound_sig_type;
1373 static unsigned char bound_sig_used[NSIG];
1374 static bound_sig_type bound_sig_data[NSIG];
1375 #endif
1377 #if HAVE_SIGNAL
1378 static void signal_handler(int sig)
1380 __bounds_checking(1);
1381 bound_sig_data[sig].signal_handler(sig);
1382 __bounds_checking(-1);
1385 bound_sig signal(int signum, bound_sig handler)
1387 bound_sig retval;
1389 dprintf (stderr, "%s, %s() %d %p\n", __FILE__, __FUNCTION__,
1390 signum, handler);
1391 retval = signal_redir(signum, handler ? signal_handler : handler);
1392 if (retval != SIG_ERR) {
1393 if (bound_sig_used[signum])
1394 retval = bound_sig_data[signum].signal_handler;
1395 if (handler) {
1396 bound_sig_used[signum] = 1;
1397 bound_sig_data[signum].signal_handler = handler;
1400 return retval;
1402 #endif
1404 #if HAVE_SIGACTION
1405 static void sig_handler(int sig)
1407 __bounds_checking(1);
1408 bound_sig_data[sig].sig_handler(sig);
1409 __bounds_checking(-1);
1412 static void sig_sigaction(int sig, siginfo_t *info, void *ucontext)
1414 __bounds_checking(1);
1415 bound_sig_data[sig].sig_sigaction(sig, info, ucontext);
1416 __bounds_checking(-1);
1419 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
1421 int retval;
1422 struct sigaction nact, oact;
1424 dprintf (stderr, "%s, %s() %d %p %p\n", __FILE__, __FUNCTION__,
1425 signum, act, oldact);
1427 if (sigaction_redir == NULL)
1428 __bound_init(0,-1);
1430 if (act) {
1431 nact = *act;
1432 if (nact.sa_flags & SA_SIGINFO)
1433 nact.sa_sigaction = sig_sigaction;
1434 else
1435 nact.sa_handler = sig_handler;
1436 retval = sigaction_redir(signum, &nact, &oact);
1438 else
1439 retval = sigaction_redir(signum, act, &oact);
1440 if (retval >= 0) {
1441 if (bound_sig_used[signum]) {
1442 if (oact.sa_flags & SA_SIGINFO)
1443 oact.sa_sigaction = bound_sig_data[signum].sig_sigaction;
1444 else
1445 oact.sa_handler = bound_sig_data[signum].sig_handler;
1447 if (oldact) {
1448 *oldact = oact;
1450 if (act) {
1451 bound_sig_used[signum] = 1;
1452 if (act->sa_flags & SA_SIGINFO)
1453 bound_sig_data[signum].sig_sigaction = act->sa_sigaction;
1454 else
1455 bound_sig_data[signum].sig_handler = act->sa_handler;
1458 return retval;
1460 #endif
1462 #if HAVE_FORK
1463 pid_t fork(void)
1465 pid_t retval;
1467 WAIT_SEM();
1468 retval = (*fork_redir)();
1469 if (retval == 0)
1470 INIT_SEM();
1471 else
1472 POST_SEM();
1473 return retval;
1475 #endif
1477 #if MALLOC_REDIR
1478 void *malloc(size_t size)
1479 #else
1480 void *__bound_malloc(size_t size, const void *caller)
1481 #endif
1483 void *ptr;
1485 #if MALLOC_REDIR
1486 /* This will catch the first dlsym call from __bound_init */
1487 if (malloc_redir == NULL) {
1488 __bound_init (0, -1);
1489 if (malloc_redir == NULL) {
1490 ptr = &initial_pool[pool_index];
1491 pool_index = (pool_index + size + 15) & ~15;
1492 if (pool_index >= sizeof (initial_pool))
1493 bound_alloc_error ("initial memory pool too small");
1494 dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
1495 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1496 return ptr;
1499 #endif
1500 /* we allocate one more byte to ensure the regions will be
1501 separated by at least one byte. With the glibc malloc, it may
1502 be in fact not necessary */
1503 ptr = BOUND_MALLOC (size + 1);
1504 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1505 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1507 if (inited && NO_CHECKING_GET() == 0) {
1508 WAIT_SEM ();
1509 INCR_COUNT(bound_malloc_count);
1511 if (ptr) {
1512 tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
1513 if (tree && tree->start == (size_t) ptr)
1514 tree->type = TCC_TYPE_MALLOC;
1516 POST_SEM ();
1518 return ptr;
1521 #if MALLOC_REDIR
1522 void *memalign(size_t align, size_t size)
1523 #else
1524 void *__bound_memalign(size_t align, size_t size, const void *caller)
1525 #endif
1527 void *ptr;
1529 #if HAVE_MEMALIGN
1530 /* we allocate one more byte to ensure the regions will be
1531 separated by at least one byte. With the glibc malloc, it may
1532 be in fact not necessary */
1533 ptr = BOUND_MEMALIGN(align, size + 1);
1534 #else
1535 if (align > 4) {
1536 /* XXX: handle it ? */
1537 ptr = NULL;
1538 } else {
1539 /* we suppose that malloc aligns to at least four bytes */
1540 ptr = BOUND_MALLOC(size + 1);
1542 #endif
1543 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1544 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1546 if (NO_CHECKING_GET() == 0) {
1547 WAIT_SEM ();
1548 INCR_COUNT(bound_memalign_count);
1550 if (ptr) {
1551 tree = splay_insert((size_t) ptr, size ? size : size + 1, tree);
1552 if (tree && tree->start == (size_t) ptr)
1553 tree->type = TCC_TYPE_MEMALIGN;
1555 POST_SEM ();
1557 return ptr;
1560 #if MALLOC_REDIR
1561 void free(void *ptr)
1562 #else
1563 void __bound_free(void *ptr, const void *caller)
1564 #endif
1566 size_t addr = (size_t) ptr;
1567 void *p;
1569 if (ptr == NULL || tree == NULL
1570 #if MALLOC_REDIR
1571 || ((unsigned char *) ptr >= &initial_pool[0] &&
1572 (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)])
1573 #endif
1575 return;
1577 dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr);
1579 if (inited && NO_CHECKING_GET() == 0) {
1580 WAIT_SEM ();
1581 INCR_COUNT(bound_free_count);
1582 tree = splay (addr, tree);
1583 if (tree->start == addr) {
1584 if (tree->is_invalid) {
1585 POST_SEM ();
1586 bound_error("freeing invalid region");
1587 return;
1589 tree->is_invalid = 1;
1590 memset (ptr, 0x5a, tree->size);
1591 p = free_reuse_list[free_reuse_index];
1592 free_reuse_list[free_reuse_index] = ptr;
1593 free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE;
1594 if (p)
1595 tree = splay_delete((size_t)p, tree);
1596 ptr = p;
1598 POST_SEM ();
1600 BOUND_FREE (ptr);
1603 #if MALLOC_REDIR
1604 void *realloc(void *ptr, size_t size)
1605 #else
1606 void *__bound_realloc(void *ptr, size_t size, const void *caller)
1607 #endif
1609 void *new_ptr;
1611 if (size == 0) {
1612 #if MALLOC_REDIR
1613 free(ptr);
1614 #else
1615 __bound_free(ptr, caller);
1616 #endif
1617 return NULL;
1620 new_ptr = BOUND_REALLOC (ptr, size + 1);
1621 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1622 __FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
1624 if (NO_CHECKING_GET() == 0) {
1625 WAIT_SEM ();
1626 INCR_COUNT(bound_realloc_count);
1628 if (ptr)
1629 tree = splay_delete ((size_t) ptr, tree);
1630 if (new_ptr) {
1631 tree = splay_insert ((size_t) new_ptr, size ? size : size + 1, tree);
1632 if (tree && tree->start == (size_t) new_ptr)
1633 tree->type = TCC_TYPE_REALLOC;
1635 POST_SEM ();
1637 return new_ptr;
1640 #if MALLOC_REDIR
1641 void *calloc(size_t nmemb, size_t size)
1642 #else
1643 void *__bound_calloc(size_t nmemb, size_t size)
1644 #endif
1646 void *ptr;
1648 size *= nmemb;
1649 #if MALLOC_REDIR
1650 /* This will catch the first dlsym call from __bound_init */
1651 if (malloc_redir == NULL) {
1652 __bound_init (0, -1);
1653 if (malloc_redir == NULL) {
1654 ptr = &initial_pool[pool_index];
1655 pool_index = (pool_index + size + 15) & ~15;
1656 if (pool_index >= sizeof (initial_pool))
1657 bound_alloc_error ("initial memory pool too small");
1658 dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
1659 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1660 memset (ptr, 0, size);
1661 return ptr;
1664 #endif
1665 ptr = BOUND_MALLOC(size + 1);
1666 dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
1667 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1669 if (ptr) {
1670 memset (ptr, 0, size);
1671 if (NO_CHECKING_GET() == 0) {
1672 WAIT_SEM ();
1673 INCR_COUNT(bound_calloc_count);
1674 tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
1675 if (tree && tree->start == (size_t) ptr)
1676 tree->type = TCC_TYPE_CALLOC;
1677 POST_SEM ();
1680 return ptr;
1683 #if !defined(_WIN32)
1684 void *__bound_mmap (void *start, size_t size, int prot,
1685 int flags, int fd, off_t offset)
1687 void *result;
1689 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1690 __FILE__, __FUNCTION__, start, (unsigned long)size);
1691 result = mmap (start, size, prot, flags, fd, offset);
1692 if (result && NO_CHECKING_GET() == 0) {
1693 WAIT_SEM ();
1694 INCR_COUNT(bound_mmap_count);
1695 tree = splay_insert((size_t)result, size, tree);
1696 POST_SEM ();
1698 return result;
1701 int __bound_munmap (void *start, size_t size)
1703 int result;
1705 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1706 __FILE__, __FUNCTION__, start, (unsigned long)size);
1707 if (start && NO_CHECKING_GET() == 0) {
1708 WAIT_SEM ();
1709 INCR_COUNT(bound_munmap_count);
1710 tree = splay_delete ((size_t) start, tree);
1711 POST_SEM ();
1713 result = munmap (start, size);
1714 return result;
1716 #endif
1718 /* some useful checked functions */
1720 /* check that (p ... p + size - 1) lies inside 'p' region, if any */
1721 static void __bound_check(const void *p, size_t size, const char *function)
1723 if (size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) {
1724 bound_error("invalid pointer %p, size 0x%lx in %s",
1725 p, (unsigned long)size, function);
1729 static int check_overlap (const void *p1, size_t n1,
1730 const void *p2, size_t n2,
1731 const char *function)
1733 const void *p1e = (const void *) ((const char *) p1 + n1);
1734 const void *p2e = (const void *) ((const char *) p2 + n2);
1736 if (NO_CHECKING_GET() == 0 && n1 != 0 && n2 !=0 &&
1737 ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
1738 (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
1739 bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
1740 p1, (unsigned long)n1, p2, (unsigned long)n2, function);
1741 return never_fatal < 0;
1743 return 0;
1746 void *__bound_memcpy(void *dest, const void *src, size_t n)
1748 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1749 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1750 INCR_COUNT(bound_mempcy_count);
1751 __bound_check(dest, n, "memcpy dest");
1752 __bound_check(src, n, "memcpy src");
1753 if (check_overlap(dest, n, src, n, "memcpy"))
1754 return dest;
1755 return memcpy(dest, src, n);
1758 int __bound_memcmp(const void *s1, const void *s2, size_t n)
1760 const unsigned char *u1 = (const unsigned char *) s1;
1761 const unsigned char *u2 = (const unsigned char *) s2;
1762 int retval = 0;
1764 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1765 __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
1766 INCR_COUNT(bound_memcmp_count);
1767 for (;;) {
1768 if ((ssize_t) --n == -1)
1769 break;
1770 else if (*u1 != *u2) {
1771 retval = *u1++ - *u2++;
1772 break;
1774 ++u1;
1775 ++u2;
1777 __bound_check(s1, (const void *)u1 - s1, "memcmp s1");
1778 __bound_check(s2, (const void *)u2 - s2, "memcmp s2");
1779 return retval;
1782 void *__bound_memmove(void *dest, const void *src, size_t n)
1784 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1785 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1786 INCR_COUNT(bound_memmove_count);
1787 __bound_check(dest, n, "memmove dest");
1788 __bound_check(src, n, "memmove src");
1789 return memmove(dest, src, n);
1792 void *__bound_memset(void *s, int c, size_t n)
1794 dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
1795 __FILE__, __FUNCTION__, s, c, (unsigned long)n);
1796 INCR_COUNT(bound_memset_count);
1797 __bound_check(s, n, "memset");
1798 return memset(s, c, n);
1801 #if defined(__arm__) && defined(__ARM_EABI__)
1802 void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n)
1804 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1805 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1806 INCR_COUNT(bound_mempcy_count);
1807 __bound_check(dest, n, "memcpy dest");
1808 __bound_check(src, n, "memcpy src");
1809 if (check_overlap(dest, n, src, n, "memcpy"))
1810 return dest;
1811 return __aeabi_memcpy(dest, src, n);
1814 void *__bound___aeabi_memmove(void *dest, const void *src, size_t n)
1816 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1817 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1818 INCR_COUNT(bound_memmove_count);
1819 __bound_check(dest, n, "memmove dest");
1820 __bound_check(src, n, "memmove src");
1821 return __aeabi_memmove(dest, src, n);
1824 void *__bound___aeabi_memmove4(void *dest, const void *src, size_t n)
1826 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1827 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1828 INCR_COUNT(bound_memmove_count);
1829 __bound_check(dest, n, "memmove dest");
1830 __bound_check(src, n, "memmove src");
1831 return __aeabi_memmove4(dest, src, n);
1834 void *__bound___aeabi_memmove8(void *dest, const void *src, size_t n)
1836 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1837 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1838 INCR_COUNT(bound_memmove_count);
1839 __bound_check(dest, n, "memmove dest");
1840 __bound_check(src, n, "memmove src");
1841 return __aeabi_memmove8(dest, src, n);
1844 void *__bound___aeabi_memset(void *s, int c, size_t n)
1846 dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
1847 __FILE__, __FUNCTION__, s, c, (unsigned long)n);
1848 INCR_COUNT(bound_memset_count);
1849 __bound_check(s, n, "memset");
1850 return __aeabi_memset(s, c, n);
1852 #endif
1854 int __bound_strlen(const char *s)
1856 const char *p = s;
1858 dprintf(stderr, "%s, %s(): %p\n",
1859 __FILE__, __FUNCTION__, s);
1860 INCR_COUNT(bound_strlen_count);
1861 while (*p++);
1862 __bound_check(s, p - s, "strlen");
1863 return (p - s) - 1;
1866 char *__bound_strcpy(char *dest, const char *src)
1868 size_t len;
1869 const char *p = src;
1871 dprintf(stderr, "%s, %s(): %p, %p\n",
1872 __FILE__, __FUNCTION__, dest, src);
1873 INCR_COUNT(bound_strcpy_count);
1874 while (*p++);
1875 len = p - src;
1876 __bound_check(dest, len, "strcpy dest");
1877 __bound_check(src, len, "strcpy src");
1878 if (check_overlap(dest, len, src, len, "strcpy"))
1879 return dest;
1880 return strcpy (dest, src);
1883 char *__bound_strncpy(char *dest, const char *src, size_t n)
1885 size_t len = n;
1886 const char *p = src;
1888 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1889 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1890 INCR_COUNT(bound_strncpy_count);
1891 while (len-- && *p++);
1892 len = p - src;
1893 __bound_check(dest, len, "strncpy dest");
1894 __bound_check(src, len, "strncpy src");
1895 if (check_overlap(dest, len, src, len, "strncpy"))
1896 return dest;
1897 return strncpy(dest, src, n);
1900 int __bound_strcmp(const char *s1, const char *s2)
1902 const unsigned char *u1 = (const unsigned char *) s1;
1903 const unsigned char *u2 = (const unsigned char *) s2;
1905 dprintf(stderr, "%s, %s(): %p, %p\n",
1906 __FILE__, __FUNCTION__, s1, s2);
1907 INCR_COUNT(bound_strcmp_count);
1908 while (*u1 && *u1 == *u2) {
1909 ++u1;
1910 ++u2;
1912 __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp s1");
1913 __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp s2");
1914 return *u1 - *u2;
1917 int __bound_strncmp(const char *s1, const char *s2, size_t n)
1919 const unsigned char *u1 = (const unsigned char *) s1;
1920 const unsigned char *u2 = (const unsigned char *) s2;
1921 int retval = 0;
1923 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1924 __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
1925 INCR_COUNT(bound_strncmp_count);
1926 do {
1927 if ((ssize_t) --n == -1)
1928 break;
1929 else if (*u1 != *u2) {
1930 retval = *u1++ - *u2++;
1931 break;
1933 ++u2;
1934 } while (*u1++);
1935 __bound_check(s1, (const char *)u1 - s1, "strncmp s1");
1936 __bound_check(s2, (const char *)u2 - s2, "strncmp s2");
1937 return retval;
1940 char *__bound_strcat(char *dest, const char *src)
1942 char *r = dest;
1943 const char *s = src;
1945 dprintf(stderr, "%s, %s(): %p, %p\n",
1946 __FILE__, __FUNCTION__, dest, src);
1947 INCR_COUNT(bound_strcat_count);
1948 while (*dest++);
1949 while (*src++);
1950 __bound_check(r, (dest - r) + (src - s) - 1, "strcat dest");
1951 __bound_check(s, src - s, "strcat src");
1952 if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strcat"))
1953 return dest;
1954 return strcat(r, s);
1957 char *__bound_strncat(char *dest, const char *src, size_t n)
1959 char *r = dest;
1960 const char *s = src;
1961 size_t len = n;
1963 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1964 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1965 INCR_COUNT(bound_strncat_count);
1966 while (*dest++);
1967 while (len-- && *src++);
1968 __bound_check(r, (dest - r) + (src - s) - 1, "strncat dest");
1969 __bound_check(s, src - s, "strncat src");
1970 if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strncat"))
1971 return dest;
1972 return strncat(r, s, n);
1975 char *__bound_strchr(const char *s, int c)
1977 const unsigned char *str = (const unsigned char *) s;
1978 unsigned char ch = c;
1980 dprintf(stderr, "%s, %s(): %p, %d\n",
1981 __FILE__, __FUNCTION__, s, ch);
1982 INCR_COUNT(bound_strchr_count);
1983 while (*str) {
1984 if (*str == ch)
1985 break;
1986 ++str;
1988 __bound_check(s, ((const char *)str - s) + 1, "strchr");
1989 return *str == ch ? (char *) str : NULL;
1992 char *__bound_strrchr(const char *s, int c)
1994 const unsigned char *str = (const unsigned char *) s;
1995 unsigned char ch = c;
1997 dprintf(stderr, "%s, %s(): %p, %d\n",
1998 __FILE__, __FUNCTION__, s, ch);
1999 INCR_COUNT(bound_strrchr_count);
2000 while (*str++);
2001 __bound_check(s, (const char *)str - s, "strrchr");
2002 while (str != (const unsigned char *)s) {
2003 if (*--str == ch)
2004 break;
2006 __bound_check(s, (const char *)str - s, "strrchr");
2007 return *str == ch ? (char *) str : NULL;
2010 char *__bound_strdup(const char *s)
2012 const char *p = s;
2013 char *new;
2015 INCR_COUNT(bound_strdup_count);
2016 while (*p++);
2017 __bound_check(s, p - s, "strdup");
2018 new = BOUND_MALLOC ((p - s) + 1);
2019 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
2020 __FILE__, __FUNCTION__, new, (unsigned long)(p -s));
2021 if (new) {
2022 if (NO_CHECKING_GET() == 0 && no_strdup == 0) {
2023 WAIT_SEM ();
2024 tree = splay_insert((size_t)new, p - s, tree);
2025 if (tree && tree->start == (size_t) new)
2026 tree->type = TCC_TYPE_STRDUP;
2027 POST_SEM ();
2029 memcpy (new, s, p - s);
2031 return new;
2035 An implementation of top-down splaying with sizes
2036 D. Sleator <sleator@cs.cmu.edu>, January 1994.
2038 This extends top-down-splay.c to maintain a size field in each node.
2039 This is the number of nodes in the subtree rooted there. This makes
2040 it possible to efficiently compute the rank of a key. (The rank is
2041 the number of nodes to the left of the given key.) It it also
2042 possible to quickly find the node of a given rank. Both of these
2043 operations are illustrated in the code below. The remainder of this
2044 introduction is taken from top-down-splay.c.
2046 "Splay trees", or "self-adjusting search trees" are a simple and
2047 efficient data structure for storing an ordered set. The data
2048 structure consists of a binary tree, with no additional fields. It
2049 allows searching, insertion, deletion, deletemin, deletemax,
2050 splitting, joining, and many other operations, all with amortized
2051 logarithmic performance. Since the trees adapt to the sequence of
2052 requests, their performance on real access patterns is typically even
2053 better. Splay trees are described in a number of texts and papers
2054 [1,2,3,4].
2056 The code here is adapted from simple top-down splay, at the bottom of
2057 page 669 of [2]. It can be obtained via anonymous ftp from
2058 spade.pc.cs.cmu.edu in directory /usr/sleator/public.
2060 The chief modification here is that the splay operation works even if the
2061 item being splayed is not in the tree, and even if the tree root of the
2062 tree is NULL. So the line:
2064 t = splay(i, t);
2066 causes it to search for item with key i in the tree rooted at t. If it's
2067 there, it is splayed to the root. If it isn't there, then the node put
2068 at the root is the last one before NULL that would have been reached in a
2069 normal binary search for i. (It's a neighbor of i in the tree.) This
2070 allows many other operations to be easily implemented, as shown below.
2072 [1] "Data Structures and Their Algorithms", Lewis and Denenberg,
2073 Harper Collins, 1991, pp 243-251.
2074 [2] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
2075 JACM Volume 32, No 3, July 1985, pp 652-686.
2076 [3] "Data Structure and Algorithm Analysis", Mark Weiss,
2077 Benjamin Cummins, 1992, pp 119-130.
2078 [4] "Data Structures, Algorithms, and Performance", Derick Wood,
2079 Addison-Wesley, 1993, pp 367-375
2082 /* Code adapted for tcc */
2084 #define compare(start,tstart,tsize) (start < tstart ? -1 : \
2085 start >= tstart+tsize ? 1 : 0)
2087 static Tree * splay (size_t addr, Tree *t)
2088 /* Splay using the key start (which may or may not be in the tree.) */
2089 /* The starting root is t, and the tree used is defined by rat */
2091 Tree N, *l, *r, *y;
2092 int comp;
2094 INCR_COUNT_SPLAY(bound_splay);
2095 if (t == NULL) return t;
2096 N.left = N.right = NULL;
2097 l = r = &N;
2099 for (;;) {
2100 comp = compare(addr, t->start, t->size);
2101 if (comp < 0) {
2102 y = t->left;
2103 if (y == NULL) break;
2104 if (compare(addr, y->start, y->size) < 0) {
2105 t->left = y->right; /* rotate right */
2106 y->right = t;
2107 t = y;
2108 if (t->left == NULL) break;
2110 r->left = t; /* link right */
2111 r = t;
2112 t = t->left;
2113 } else if (comp > 0) {
2114 y = t->right;
2115 if (y == NULL) break;
2116 if (compare(addr, y->start, y->size) > 0) {
2117 t->right = y->left; /* rotate left */
2118 y->left = t;
2119 t = y;
2120 if (t->right == NULL) break;
2122 l->right = t; /* link left */
2123 l = t;
2124 t = t->right;
2125 } else {
2126 break;
2129 l->right = t->left; /* assemble */
2130 r->left = t->right;
2131 t->left = N.right;
2132 t->right = N.left;
2134 return t;
2137 #define compare_end(start,tend) (start < tend ? -1 : \
2138 start > tend ? 1 : 0)
2140 static Tree * splay_end (size_t addr, Tree *t)
2141 /* Splay using the key start (which may or may not be in the tree.) */
2142 /* The starting root is t, and the tree used is defined by rat */
2144 Tree N, *l, *r, *y;
2145 int comp;
2147 INCR_COUNT_SPLAY(bound_splay_end);
2148 if (t == NULL) return t;
2149 N.left = N.right = NULL;
2150 l = r = &N;
2152 for (;;) {
2153 comp = compare_end(addr, t->start + t->size);
2154 if (comp < 0) {
2155 y = t->left;
2156 if (y == NULL) break;
2157 if (compare_end(addr, y->start + y->size) < 0) {
2158 t->left = y->right; /* rotate right */
2159 y->right = t;
2160 t = y;
2161 if (t->left == NULL) break;
2163 r->left = t; /* link right */
2164 r = t;
2165 t = t->left;
2166 } else if (comp > 0) {
2167 y = t->right;
2168 if (y == NULL) break;
2169 if (compare_end(addr, y->start + y->size) > 0) {
2170 t->right = y->left; /* rotate left */
2171 y->left = t;
2172 t = y;
2173 if (t->right == NULL) break;
2175 l->right = t; /* link left */
2176 l = t;
2177 t = t->right;
2178 } else {
2179 break;
2182 l->right = t->left; /* assemble */
2183 r->left = t->right;
2184 t->left = N.right;
2185 t->right = N.left;
2187 return t;
2190 static Tree * splay_insert(size_t addr, size_t size, Tree * t)
2191 /* Insert key start into the tree t, if it is not already there. */
2192 /* Return a pointer to the resulting tree. */
2194 Tree * new;
2196 INCR_COUNT_SPLAY(bound_splay_insert);
2197 if (t != NULL) {
2198 t = splay(addr,t);
2199 if (compare(addr, t->start, t->size)==0) {
2200 return t; /* it's already there */
2203 #if TREE_REUSE
2204 if (tree_free_list) {
2205 new = tree_free_list;
2206 tree_free_list = new->left;
2208 else
2209 #endif
2211 new = (Tree *) BOUND_MALLOC (sizeof (Tree));
2213 if (new == NULL) {
2214 bound_alloc_error("not enough memory for bound checking code");
2216 else {
2217 if (t == NULL) {
2218 new->left = new->right = NULL;
2219 } else if (compare(addr, t->start, t->size) < 0) {
2220 new->left = t->left;
2221 new->right = t;
2222 t->left = NULL;
2223 } else {
2224 new->right = t->right;
2225 new->left = t;
2226 t->right = NULL;
2228 new->start = addr;
2229 new->size = size;
2230 new->type = TCC_TYPE_NONE;
2231 new->is_invalid = 0;
2233 return new;
2236 #define compare_destroy(start,tstart) (start < tstart ? -1 : \
2237 start > tstart ? 1 : 0)
2239 static Tree * splay_delete(size_t addr, Tree *t)
2240 /* Deletes addr from the tree if it's there. */
2241 /* Return a pointer to the resulting tree. */
2243 Tree * x;
2245 INCR_COUNT_SPLAY(bound_splay_delete);
2246 if (t==NULL) return NULL;
2247 t = splay(addr,t);
2248 if (compare_destroy(addr, t->start) == 0) { /* found it */
2249 if (t->left == NULL) {
2250 x = t->right;
2251 } else {
2252 x = splay(addr, t->left);
2253 x->right = t->right;
2255 #if TREE_REUSE
2256 t->left = tree_free_list;
2257 tree_free_list = t;
2258 #else
2259 BOUND_FREE(t);
2260 #endif
2261 return x;
2262 } else {
2263 return t; /* It wasn't there */
2267 void splay_printtree(Tree * t, int d)
2269 int i;
2270 if (t == NULL) return;
2271 splay_printtree(t->right, d+1);
2272 for (i=0; i<d; i++) fprintf(stderr," ");
2273 fprintf(stderr,"%p(0x%lx:%u:%u)\n",
2274 (void *) t->start, (unsigned long) t->size,
2275 (unsigned)t->type, (unsigned)t->is_invalid);
2276 splay_printtree(t->left, d+1);