riscv64-tok.h: update with more instructions from the spec
[tinycc.git] / lib / bcheck.c
blobb8dd1c5356901790a12a30f42a4c487a69ab139a
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) fprintf(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 size, size_t align, 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 static void bound_alloc_error(const char *s)
467 fprintf(stderr,"FATAL: %s\n",s);
468 exit (1);
471 static void bound_not_found_warning(const char *file, const char *function,
472 void *ptr)
474 dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
477 static void fetch_and_add(int* variable, int value)
479 #if defined __i386__ || defined __x86_64__
480 __asm__ volatile("lock; addl %0, %1"
481 : "+r" (value), "+m" (*variable) // input+output
482 : // No input-only
483 : "memory"
485 #elif defined __arm__
486 extern void fetch_and_add_arm(int* variable, int value);
487 fetch_and_add_arm(variable, value);
488 #elif defined __aarch64__
489 extern void fetch_and_add_arm64(int* variable, int value);
490 fetch_and_add_arm64(variable, value);
491 #elif defined __riscv
492 extern void fetch_and_add_riscv64(int* variable, int value);
493 fetch_and_add_riscv64(variable, value);
494 #else
495 *variable += value;
496 #endif
499 /* enable/disable checking. This can be used in signal handlers. */
500 void __bounds_checking (int no_check)
502 #if HAVE_TLS_FUNC || HAVE_TLS_VAR
503 NO_CHECKING_SET(NO_CHECKING_GET() + no_check);
504 #else
505 fetch_and_add (&no_checking, no_check);
506 #endif
509 void __bound_checking_lock(void)
511 WAIT_SEM ();
514 void __bound_checking_unlock(void)
516 POST_SEM ();
519 /* enable/disable checking. This can be used in signal handlers. */
520 void __bound_never_fatal (int neverfatal)
522 fetch_and_add (&never_fatal, neverfatal);
525 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
526 the end of a region in this case */
527 void * __bound_ptr_add(void *p, size_t offset)
529 size_t addr = (size_t)p;
531 if (NO_CHECKING_GET())
532 return p + offset;
534 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
535 __FILE__, __FUNCTION__, p, (unsigned long)offset);
537 WAIT_SEM ();
538 INCR_COUNT(bound_ptr_add_count);
539 if (tree) {
540 addr -= tree->start;
541 if (addr >= tree->size) {
542 addr = (size_t)p;
543 tree = splay (addr, tree);
544 addr -= tree->start;
546 if (addr >= tree->size) {
547 addr = (size_t)p;
548 tree = splay_end (addr, tree);
549 addr -= tree->start;
551 if (addr <= tree->size) {
552 if (tree->is_invalid || addr + offset > tree->size) {
553 POST_SEM ();
554 if (print_warn_ptr_add)
555 bound_warning("%p is outside of the region", p + offset);
556 if (never_fatal <= 0)
557 return INVALID_POINTER; /* return an invalid pointer */
558 return p + offset;
561 else if (p) { /* Allow NULL + offset. offsetoff is using it. */
562 INCR_COUNT(bound_not_found);
563 POST_SEM ();
564 bound_not_found_warning (__FILE__, __FUNCTION__, p);
565 return p + offset;
568 POST_SEM ();
569 return p + offset;
572 /* return '(p + offset)' for pointer indirection (the resulting must
573 be strictly inside the region */
574 #define BOUND_PTR_INDIR(dsize) \
575 void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
577 size_t addr = (size_t)p; \
579 if (NO_CHECKING_GET()) \
580 return p + offset; \
582 dprintf(stderr, "%s, %s(): %p 0x%lx\n", \
583 __FILE__, __FUNCTION__, p, (unsigned long)offset); \
584 WAIT_SEM (); \
585 INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
586 if (tree) { \
587 addr -= tree->start; \
588 if (addr >= tree->size) { \
589 addr = (size_t)p; \
590 tree = splay (addr, tree); \
591 addr -= tree->start; \
593 if (addr >= tree->size) { \
594 addr = (size_t)p; \
595 tree = splay_end (addr, tree); \
596 addr -= tree->start; \
598 if (addr <= tree->size) { \
599 if (tree->is_invalid || addr + offset + dsize > tree->size) { \
600 POST_SEM (); \
601 bound_warning("%p is outside of the region", p + offset); \
602 if (never_fatal <= 0) \
603 return INVALID_POINTER; /* return an invalid pointer */ \
604 return p + offset; \
607 else { \
608 INCR_COUNT(bound_not_found); \
609 POST_SEM (); \
610 bound_not_found_warning (__FILE__, __FUNCTION__, p); \
611 return p + offset; \
614 POST_SEM (); \
615 return p + offset; \
618 BOUND_PTR_INDIR(1)
619 BOUND_PTR_INDIR(2)
620 BOUND_PTR_INDIR(4)
621 BOUND_PTR_INDIR(8)
622 BOUND_PTR_INDIR(12)
623 BOUND_PTR_INDIR(16)
625 /* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */
626 #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
628 * At least gcc 6.2 complains when __builtin_frame_address is used with
629 * nonzero argument.
631 #pragma GCC diagnostic push
632 #pragma GCC diagnostic ignored "-Wframe-address"
633 #endif
635 /* return the frame pointer of the caller */
636 #define GET_CALLER_FP(fp)\
638 fp = (size_t)__builtin_frame_address(1);\
641 /* called when entering a function to add all the local regions */
642 void FASTCALL __bound_local_new(void *p1)
644 size_t addr, fp, *p = p1;
646 if (NO_CHECKING_GET())
647 return;
648 GET_CALLER_FP(fp);
649 dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
650 __FILE__, __FUNCTION__, p, (void *)fp);
651 WAIT_SEM ();
652 while ((addr = p[0])) {
653 INCR_COUNT(bound_local_new_count);
654 tree = splay_insert(addr + fp, p[1], tree);
655 p += 2;
657 POST_SEM ();
658 #if BOUND_DEBUG
659 if (print_calls) {
660 p = p1;
661 while ((addr = p[0])) {
662 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
663 __FILE__, __FUNCTION__,
664 (void *) (addr + fp), (unsigned long) p[1]);
665 p += 2;
668 #endif
671 /* called when leaving a function to delete all the local regions */
672 void FASTCALL __bound_local_delete(void *p1)
674 size_t addr, fp, *p = p1;
676 if (NO_CHECKING_GET())
677 return;
678 GET_CALLER_FP(fp);
679 dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
680 __FILE__, __FUNCTION__, p, (void *)fp);
681 WAIT_SEM ();
682 while ((addr = p[0])) {
683 INCR_COUNT(bound_local_delete_count);
684 tree = splay_delete(addr + fp, tree);
685 p += 2;
687 if (alloca_list) {
688 alloca_list_type *last = NULL;
689 alloca_list_type *cur = alloca_list;
691 do {
692 if (cur->fp == fp) {
693 if (last)
694 last->next = cur->next;
695 else
696 alloca_list = cur->next;
697 tree = splay_delete ((size_t) cur->p, tree);
698 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
699 __FILE__, __FUNCTION__, cur->p);
700 BOUND_FREE (cur);
701 cur = last ? last->next : alloca_list;
703 else {
704 last = cur;
705 cur = cur->next;
707 } while (cur);
709 if (jmp_list) {
710 jmp_list_type *last = NULL;
711 jmp_list_type *cur = jmp_list;
713 do {
714 if (cur->fp == fp) {
715 if (last)
716 last->next = cur->next;
717 else
718 jmp_list = cur->next;
719 dprintf(stderr, "%s, %s(): remove setjmp %p\n",
720 __FILE__, __FUNCTION__, cur->penv);
721 BOUND_FREE (cur);
722 cur = last ? last->next : jmp_list;
724 else {
725 last = cur;
726 cur = cur->next;
728 } while (cur);
731 POST_SEM ();
732 #if BOUND_DEBUG
733 if (print_calls) {
734 p = p1;
735 while ((addr = p[0])) {
736 if (addr != 1) {
737 dprintf(stderr, "%s, %s(): %p 0x%lx\n",
738 __FILE__, __FUNCTION__,
739 (void *) (addr + fp), (unsigned long) p[1]);
741 p+= 2;
744 #endif
747 /* used by alloca */
748 void __bound_new_region(void *p, size_t size)
750 size_t fp;
751 alloca_list_type *last;
752 alloca_list_type *cur;
753 alloca_list_type *new;
755 if (NO_CHECKING_GET())
756 return;
758 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
759 __FILE__, __FUNCTION__, p, (unsigned long)size);
760 GET_CALLER_FP (fp);
761 new = BOUND_MALLOC (sizeof (alloca_list_type));
762 WAIT_SEM ();
763 INCR_COUNT(bound_alloca_count);
764 last = NULL;
765 cur = alloca_list;
766 while (cur) {
767 #if defined(__i386__) || (defined(__arm__) && !defined(__ARM_EABI__))
768 int align = 4;
769 #elif defined(__arm__)
770 int align = 8;
771 #else
772 int align = 16;
773 #endif
774 void *cure = (void *)((char *)cur->p + ((cur->size + align) & -align));
775 void *pe = (void *)((char *)p + ((size + align) & -align));
776 if (cur->fp == fp && ((cur->p <= p && cure > p) ||
777 (p <= cur->p && pe > cur->p))) {
778 if (last)
779 last->next = cur->next;
780 else
781 alloca_list = cur->next;
782 tree = splay_delete((size_t)cur->p, tree);
783 break;
785 last = cur;
786 cur = cur->next;
788 tree = splay_insert((size_t)p, size, tree);
789 if (new) {
790 new->fp = fp;
791 new->p = p;
792 new->size = size;
793 new->next = alloca_list;
794 alloca_list = new;
796 POST_SEM ();
797 if (cur) {
798 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
799 __FILE__, __FUNCTION__, cur->p);
800 BOUND_FREE (cur);
804 void __bound_setjmp(jmp_buf env)
806 jmp_list_type *jl;
807 void *e = (void *) env;
809 if (NO_CHECKING_GET() == 0) {
810 dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
811 WAIT_SEM ();
812 INCR_COUNT(bound_setjmp_count);
813 jl = jmp_list;
814 while (jl) {
815 if (jl->penv == e)
816 break;
817 jl = jl->next;
819 if (jl == NULL) {
820 jl = BOUND_MALLOC (sizeof (jmp_list_type));
821 if (jl) {
822 jl->penv = e;
823 jl->next = jmp_list;
824 jmp_list = jl;
827 if (jl) {
828 size_t fp;
830 GET_CALLER_FP (fp);
831 jl->fp = fp;
832 jl->end_fp = (size_t)__builtin_frame_address(0);
833 BOUND_GET_TID(jl->tid);
835 POST_SEM ();
839 static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
841 jmp_list_type *jl;
842 void *e;
843 BOUND_TID_TYPE tid;
845 if (NO_CHECKING_GET() == 0) {
846 e = (void *)env;
847 BOUND_GET_TID(tid);
848 dprintf(stderr, "%s, %s(): %p\n", __FILE__, func, e);
849 WAIT_SEM();
850 INCR_COUNT(bound_longjmp_count);
851 jl = jmp_list;
852 while (jl) {
853 if (jl->penv == e && jl->tid == tid) {
854 size_t start_fp = (size_t)__builtin_frame_address(0);
855 size_t end_fp = jl->end_fp;
856 jmp_list_type *cur = jmp_list;
857 jmp_list_type *last = NULL;
859 while (cur->penv != e || cur->tid != tid) {
860 if (cur->tid == tid) {
861 dprintf(stderr, "%s, %s(): remove setjmp %p\n",
862 __FILE__, func, cur->penv);
863 if (last)
864 last->next = cur->next;
865 else
866 jmp_list = cur->next;
867 BOUND_FREE (cur);
868 cur = last ? last->next : jmp_list;
870 else {
871 last = cur;
872 cur = cur->next;
875 for (;;) {
876 Tree *t = tree;
877 alloca_list_type *last;
878 alloca_list_type *cur;
880 while (t && (t->start < start_fp || t->start > end_fp))
881 if (t->start < start_fp)
882 t = t->right;
883 else
884 t = t->left;
885 if (t == NULL)
886 break;
887 last = NULL;
888 cur = alloca_list;
889 while (cur) {
890 if ((size_t) cur->p == t->start) {
891 dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
892 __FILE__, func, cur->p);
893 if (last)
894 last->next = cur->next;
895 else
896 alloca_list = cur->next;
897 BOUND_FREE (cur);
898 break;
900 last = cur;
901 cur = cur->next;
903 dprintf(stderr, "%s, %s(): delete %p\n",
904 __FILE__, func, (void *) t->start);
905 tree = splay_delete(t->start, tree);
907 break;
909 jl = jl->next;
911 POST_SEM();
913 #if !defined(_WIN32)
914 sig ? siglongjmp(env, val) :
915 #endif
916 longjmp (env, val);
919 void __bound_longjmp(jmp_buf env, int val)
921 __bound_long_jump(env,val, 0, __FUNCTION__);
924 #if !defined(_WIN32)
925 void __bound_siglongjmp(jmp_buf env, int val)
927 __bound_long_jump(env,val, 1, __FUNCTION__);
929 #endif
931 #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
932 #pragma GCC diagnostic pop
933 #endif
935 void __bound_init(size_t *p, int mode)
937 dprintf(stderr, "%s, %s(): start %s\n", __FILE__, __FUNCTION__,
938 mode < 0 ? "lazy" : mode == 0 ? "normal use" : "for -run");
940 if (inited) {
941 WAIT_SEM();
942 goto add_bounds;
944 inited = 1;
946 #if HAVE_TLS_FUNC
947 #if defined(_WIN32)
948 no_checking_key = TlsAlloc();
949 TlsSetValue(no_checking_key, &no_checking);
950 #else
951 pthread_key_create(&no_checking_key, NULL);
952 pthread_setspecific(no_checking_key, &no_checking);
953 #endif
954 #endif
955 NO_CHECKING_SET(1);
957 print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
958 print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL;
959 print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL;
960 print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
961 never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
963 INIT_SEM ();
965 #if MALLOC_REDIR
967 void *addr = mode > 0 ? RTLD_DEFAULT : RTLD_NEXT;
969 /* tcc -run required RTLD_DEFAULT. Normal usage requires RTLD_NEXT,
970 but using RTLD_NEXT with -run segfaults on MacOS in dyld as the
971 generated code segment isn't registered with dyld and hence the
972 caller image of dlsym isn't known to it */
973 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
974 if (malloc_redir == NULL) {
975 dprintf(stderr, "%s, %s(): use RTLD_DEFAULT\n",
976 __FILE__, __FUNCTION__);
977 addr = RTLD_DEFAULT;
978 *(void **) (&malloc_redir) = dlsym (addr, "malloc");
980 *(void **) (&calloc_redir) = dlsym (addr, "calloc");
981 *(void **) (&free_redir) = dlsym (addr, "free");
982 *(void **) (&realloc_redir) = dlsym (addr, "realloc");
983 *(void **) (&memalign_redir) = dlsym (addr, "memalign");
984 dprintf(stderr, "%s, %s(): malloc_redir %p\n",
985 __FILE__, __FUNCTION__, malloc_redir);
986 dprintf(stderr, "%s, %s(): free_redir %p\n",
987 __FILE__, __FUNCTION__, free_redir);
988 dprintf(stderr, "%s, %s(): realloc_redir %p\n",
989 __FILE__, __FUNCTION__, realloc_redir);
990 dprintf(stderr, "%s, %s(): memalign_redir %p\n",
991 __FILE__, __FUNCTION__, memalign_redir);
992 if (malloc_redir == NULL || free_redir == NULL)
993 bound_alloc_error ("Cannot redirect malloc/free");
994 #if HAVE_PTHREAD_CREATE
995 *(void **) (&pthread_create_redir) = dlsym (addr, "pthread_create");
996 dprintf(stderr, "%s, %s(): pthread_create_redir %p\n",
997 __FILE__, __FUNCTION__, pthread_create_redir);
998 if (pthread_create_redir == NULL)
999 bound_alloc_error ("Cannot redirect pthread_create");
1000 #endif
1001 #if HAVE_SIGNAL
1002 *(void **) (&signal_redir) = dlsym (addr, "signal");
1003 dprintf(stderr, "%s, %s(): signal_redir %p\n",
1004 __FILE__, __FUNCTION__, signal_redir);
1005 if (signal_redir == NULL)
1006 bound_alloc_error ("Cannot redirect signal");
1007 #endif
1008 #if HAVE_SIGACTION
1009 *(void **) (&sigaction_redir) = dlsym (addr, "sigaction");
1010 dprintf(stderr, "%s, %s(): sigaction_redir %p\n",
1011 __FILE__, __FUNCTION__, sigaction_redir);
1012 if (sigaction_redir == NULL)
1013 bound_alloc_error ("Cannot redirect sigaction");
1014 #endif
1015 #if HAVE_FORK
1016 *(void **) (&fork_redir) = dlsym (addr, "fork");
1017 dprintf(stderr, "%s, %s(): fork_redir %p\n",
1018 __FILE__, __FUNCTION__, fork_redir);
1019 if (fork_redir == NULL)
1020 bound_alloc_error ("Cannot redirect fork");
1021 #endif
1023 #endif
1025 #ifdef __linux__
1027 FILE *fp;
1028 unsigned char found;
1029 unsigned long start;
1030 unsigned long end;
1031 unsigned long ad =
1032 (unsigned long) __builtin_return_address(0);
1033 char line[1000];
1035 /* Display exec name. Usefull when a lot of code is compiled with tcc */
1036 fp = fopen ("/proc/self/comm", "r");
1037 if (fp) {
1038 memset (exec, 0, sizeof(exec));
1039 fread (exec, 1, sizeof(exec) - 2, fp);
1040 if (strchr(exec,'\n'))
1041 *strchr(exec,'\n') = '\0';
1042 strcat (exec, ":");
1043 fclose (fp);
1045 /* check if dlopen is used (is threre a better way?) */
1046 found = 0;
1047 fp = fopen ("/proc/self/maps", "r");
1048 if (fp) {
1049 while (fgets (line, sizeof(line), fp)) {
1050 if (sscanf (line, "%lx-%lx", &start, &end) == 2 &&
1051 ad >= start && ad < end) {
1052 found = 1;
1053 break;
1055 if (strstr (line,"[heap]"))
1056 break;
1058 fclose (fp);
1060 if (found == 0) {
1061 use_sem = 1;
1062 no_strdup = 1;
1065 #endif
1067 WAIT_SEM ();
1069 #if HAVE_CTYPE
1070 #ifdef __APPLE__
1071 tree = splay_insert((size_t) &_DefaultRuneLocale,
1072 sizeof (_DefaultRuneLocale), tree);
1073 #else
1074 /* XXX: Does not work if locale is changed */
1075 tree = splay_insert((size_t) __ctype_b_loc(),
1076 sizeof (unsigned short *), tree);
1077 tree = splay_insert((size_t) (*__ctype_b_loc() - 128),
1078 384 * sizeof (unsigned short), tree);
1079 tree = splay_insert((size_t) __ctype_tolower_loc(),
1080 sizeof (__int32_t *), tree);
1081 tree = splay_insert((size_t) (*__ctype_tolower_loc() - 128),
1082 384 * sizeof (__int32_t), tree);
1083 tree = splay_insert((size_t) __ctype_toupper_loc(),
1084 sizeof (__int32_t *), tree);
1085 tree = splay_insert((size_t) (*__ctype_toupper_loc() - 128),
1086 384 * sizeof (__int32_t), tree);
1087 #endif
1088 #endif
1089 #if HAVE_ERRNO
1090 tree = splay_insert((size_t) (&errno), sizeof (int), tree);
1091 #endif
1093 add_bounds:
1094 if (!p)
1095 goto no_bounds;
1097 /* add all static bound check values */
1098 while (p[0] != 0) {
1099 tree = splay_insert(p[0], p[1], tree);
1100 #if BOUND_DEBUG
1101 if (print_calls) {
1102 dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
1103 __FILE__, __FUNCTION__,
1104 (void *) p[0], (unsigned long) p[1]);
1106 #endif
1107 p += 2;
1109 no_bounds:
1111 POST_SEM ();
1112 NO_CHECKING_SET(0);
1113 dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
1116 void
1117 #if (defined(__GLIBC__) && (__GLIBC_MINOR__ >= 4)) || defined(_WIN32)
1118 __attribute__((constructor))
1119 #endif
1120 __bound_main_arg(int argc, char **argv, char **envp)
1122 __bound_init (0, -1);
1123 if (argc && argv) {
1124 int i;
1126 WAIT_SEM ();
1127 for (i = 0; i < argc; i++)
1128 tree = splay_insert((size_t) argv[i], strlen (argv[i]) + 1, tree);
1129 tree = splay_insert((size_t) argv, (argc + 1) * sizeof(char *), tree);
1130 POST_SEM ();
1131 #if BOUND_DEBUG
1132 if (print_calls) {
1133 for (i = 0; i < argc; i++)
1134 dprintf(stderr, "%s, %s(): arg %p 0x%lx\n",
1135 __FILE__, __FUNCTION__,
1136 argv[i], (unsigned long)(strlen (argv[i]) + 1));
1137 dprintf(stderr, "%s, %s(): argv %p %d\n",
1138 __FILE__, __FUNCTION__, argv,
1139 (int)((argc + 1) * sizeof(char *)));
1141 #endif
1144 if (envp && *envp) {
1145 char **p = envp;
1147 WAIT_SEM ();
1148 while (*p) {
1149 tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
1150 ++p;
1152 tree = splay_insert((size_t) envp, (++p - envp) * sizeof(char *), tree);
1153 POST_SEM ();
1154 #if BOUND_DEBUG
1155 if (print_calls) {
1156 p = envp;
1157 while (*p) {
1158 dprintf(stderr, "%s, %s(): env %p 0x%lx\n",
1159 __FILE__, __FUNCTION__,
1160 *p, (unsigned long)(strlen (*p) + 1));
1161 ++p;
1163 dprintf(stderr, "%s, %s(): environ %p %d\n",
1164 __FILE__, __FUNCTION__, envp,
1165 (int)((++p - envp) * sizeof(char *)));
1167 #endif
1171 void __attribute__((destructor)) __bound_exit(void)
1173 int i;
1174 static const char * const alloc_type[] = {
1175 "", "malloc", "calloc", "realloc", "memalign", "strdup"
1178 dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__);
1180 if (inited) {
1181 #if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \
1182 !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
1183 !defined(__ANDROID__)
1184 if (print_heap) {
1185 extern void __libc_freeres (void);
1186 __libc_freeres ();
1188 #endif
1190 NO_CHECKING_SET(1);
1192 TRY_SEM ();
1193 while (alloca_list) {
1194 alloca_list_type *next = alloca_list->next;
1196 tree = splay_delete ((size_t) alloca_list->p, tree);
1197 BOUND_FREE (alloca_list);
1198 alloca_list = next;
1200 while (jmp_list) {
1201 jmp_list_type *next = jmp_list->next;
1203 BOUND_FREE (jmp_list);
1204 jmp_list = next;
1206 for (i = 0; i < FREE_REUSE_SIZE; i++) {
1207 if (free_reuse_list[i]) {
1208 tree = splay_delete ((size_t) free_reuse_list[i], tree);
1209 BOUND_FREE (free_reuse_list[i]);
1212 while (tree) {
1213 if (print_heap && tree->type != 0)
1214 fprintf (stderr, "%s, %s(): %s found size %lu\n",
1215 __FILE__, __FUNCTION__, alloc_type[tree->type],
1216 (unsigned long) tree->size);
1217 tree = splay_delete (tree->start, tree);
1219 #if TREE_REUSE
1220 while (tree_free_list) {
1221 Tree *next = tree_free_list->left;
1222 BOUND_FREE (tree_free_list);
1223 tree_free_list = next;
1225 #endif
1226 POST_SEM ();
1227 EXIT_SEM ();
1228 #if HAVE_TLS_FUNC
1229 #if defined(_WIN32)
1230 TlsFree(no_checking_key);
1231 #else
1232 pthread_key_delete(no_checking_key);
1233 #endif
1234 #endif
1235 inited = 0;
1236 if (print_statistic) {
1237 #if BOUND_STATISTIC
1238 fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count);
1239 fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count);
1240 fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count);
1241 fprintf (stderr, "bound_ptr_indir4_count %llu\n", bound_ptr_indir4_count);
1242 fprintf (stderr, "bound_ptr_indir8_count %llu\n", bound_ptr_indir8_count);
1243 fprintf (stderr, "bound_ptr_indir12_count %llu\n", bound_ptr_indir12_count);
1244 fprintf (stderr, "bound_ptr_indir16_count %llu\n", bound_ptr_indir16_count);
1245 fprintf (stderr, "bound_local_new_count %llu\n", bound_local_new_count);
1246 fprintf (stderr, "bound_local_delete_count %llu\n", bound_local_delete_count);
1247 fprintf (stderr, "bound_malloc_count %llu\n", bound_malloc_count);
1248 fprintf (stderr, "bound_calloc_count %llu\n", bound_calloc_count);
1249 fprintf (stderr, "bound_realloc_count %llu\n", bound_realloc_count);
1250 fprintf (stderr, "bound_free_count %llu\n", bound_free_count);
1251 fprintf (stderr, "bound_memalign_count %llu\n", bound_memalign_count);
1252 fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count);
1253 fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count);
1254 fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count);
1255 fprintf (stderr, "bound_setjmp_count %llu\n", bound_setjmp_count);
1256 fprintf (stderr, "bound_longjmp_count %llu\n", bound_longjmp_count);
1257 fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count);
1258 fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count);
1259 fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count);
1260 fprintf (stderr, "bound_memset_count %llu\n", bound_memset_count);
1261 fprintf (stderr, "bound_strlen_count %llu\n", bound_strlen_count);
1262 fprintf (stderr, "bound_strcpy_count %llu\n", bound_strcpy_count);
1263 fprintf (stderr, "bound_strncpy_count %llu\n", bound_strncpy_count);
1264 fprintf (stderr, "bound_strcmp_count %llu\n", bound_strcmp_count);
1265 fprintf (stderr, "bound_strncmp_count %llu\n", bound_strncmp_count);
1266 fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count);
1267 fprintf (stderr, "bound_strncat_count %llu\n", bound_strncat_count);
1268 fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count);
1269 fprintf (stderr, "bound_strrchr_count %llu\n", bound_strrchr_count);
1270 fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count);
1271 fprintf (stderr, "bound_not_found %llu\n", bound_not_found);
1272 #endif
1273 #if BOUND_STATISTIC_SPLAY
1274 fprintf (stderr, "bound_splay %llu\n", bound_splay);
1275 fprintf (stderr, "bound_splay_end %llu\n", bound_splay_end);
1276 fprintf (stderr, "bound_splay_insert %llu\n", bound_splay_insert);
1277 fprintf (stderr, "bound_splay_delete %llu\n", bound_splay_delete);
1278 #endif
1283 void __bound_exit_dll(size_t *p)
1285 dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
1287 if (p) {
1288 WAIT_SEM ();
1289 while (p[0] != 0) {
1290 tree = splay_delete(p[0], tree);
1291 #if BOUND_DEBUG
1292 if (print_calls) {
1293 dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n",
1294 __FILE__, __FUNCTION__,
1295 (void *) p[0], (unsigned long) p[1]);
1297 #endif
1298 p += 2;
1300 POST_SEM ();
1304 #if HAVE_PTHREAD_CREATE
1305 typedef struct {
1306 void *(*start_routine) (void *);
1307 void *arg;
1308 sigset_t old_mask;
1309 } bound_thread_create_type;
1311 static void *bound_thread_create(void *bdata)
1313 bound_thread_create_type *data = (bound_thread_create_type *) bdata;
1314 void *retval;
1315 #if HAVE_TLS_FUNC
1316 int *p = (int *) BOUND_MALLOC(sizeof(int));
1318 if (!p) bound_alloc_error("bound_thread_create malloc");
1319 *p = 0;
1320 pthread_setspecific(no_checking_key, p);
1321 #endif
1322 pthread_sigmask(SIG_SETMASK, &data->old_mask, NULL);
1323 retval = data->start_routine(data->arg);
1324 #if HAVE_TLS_FUNC
1325 pthread_setspecific(no_checking_key, NULL);
1326 BOUND_FREE (p);
1327 #endif
1328 BOUND_FREE (data);
1329 return retval;
1332 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
1333 void *(*start_routine) (void *), void *arg)
1335 int retval;
1336 bound_thread_create_type *data;
1337 sigset_t mask;
1338 sigset_t old_mask;
1340 use_sem = 1;
1341 dprintf (stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
1342 sigfillset(&mask);
1343 pthread_sigmask(SIG_SETMASK, &mask, &old_mask);
1344 data = (bound_thread_create_type *) BOUND_MALLOC(sizeof(bound_thread_create_type));
1345 if (!data) bound_alloc_error("bound_thread_create malloc");
1346 data->start_routine = start_routine;
1347 data->arg = arg;
1348 data->old_mask = old_mask;
1349 retval = pthread_create_redir(thread, attr, bound_thread_create, data);
1350 pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
1351 return retval;
1353 #endif
1355 #if HAVE_SIGNAL || HAVE_SIGACTION
1356 typedef union {
1357 #if HAVE_SIGNAL
1358 bound_sig signal_handler;
1359 #endif
1360 #if HAVE_SIGACTION
1361 void (*sig_handler)(int);
1362 void (*sig_sigaction)(int, siginfo_t *, void *);
1363 #endif
1364 } bound_sig_type;
1366 static unsigned char bound_sig_used[NSIG];
1367 static bound_sig_type bound_sig_data[NSIG];
1368 #endif
1370 #if HAVE_SIGNAL
1371 static void signal_handler(int sig)
1373 __bounds_checking(1);
1374 bound_sig_data[sig].signal_handler(sig);
1375 __bounds_checking(-1);
1378 bound_sig signal(int signum, bound_sig handler)
1380 bound_sig retval;
1382 dprintf (stderr, "%s, %s() %d %p\n", __FILE__, __FUNCTION__,
1383 signum, handler);
1384 retval = signal_redir(signum, handler ? signal_handler : handler);
1385 if (retval != SIG_ERR) {
1386 if (bound_sig_used[signum])
1387 retval = bound_sig_data[signum].signal_handler;
1388 if (handler) {
1389 bound_sig_used[signum] = 1;
1390 bound_sig_data[signum].signal_handler = handler;
1393 return retval;
1395 #endif
1397 #if HAVE_SIGACTION
1398 static void sig_handler(int sig)
1400 __bounds_checking(1);
1401 bound_sig_data[sig].sig_handler(sig);
1402 __bounds_checking(-1);
1405 static void sig_sigaction(int sig, siginfo_t *info, void *ucontext)
1407 __bounds_checking(1);
1408 bound_sig_data[sig].sig_sigaction(sig, info, ucontext);
1409 __bounds_checking(-1);
1412 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
1414 int retval;
1415 struct sigaction nact, oact;
1417 dprintf (stderr, "%s, %s() %d %p %p\n", __FILE__, __FUNCTION__,
1418 signum, act, oldact);
1420 if (sigaction_redir == NULL)
1421 __bound_init(0,-1);
1423 if (act) {
1424 nact = *act;
1425 if (nact.sa_flags & SA_SIGINFO)
1426 nact.sa_sigaction = sig_sigaction;
1427 else
1428 nact.sa_handler = sig_handler;
1429 retval = sigaction_redir(signum, &nact, &oact);
1431 else
1432 retval = sigaction_redir(signum, act, &oact);
1433 if (retval >= 0) {
1434 if (bound_sig_used[signum]) {
1435 if (oact.sa_flags & SA_SIGINFO)
1436 oact.sa_sigaction = bound_sig_data[signum].sig_sigaction;
1437 else
1438 oact.sa_handler = bound_sig_data[signum].sig_handler;
1440 if (oldact) {
1441 *oldact = oact;
1443 if (act) {
1444 bound_sig_used[signum] = 1;
1445 if (act->sa_flags & SA_SIGINFO)
1446 bound_sig_data[signum].sig_sigaction = act->sa_sigaction;
1447 else
1448 bound_sig_data[signum].sig_handler = act->sa_handler;
1451 return retval;
1453 #endif
1455 #if HAVE_FORK
1456 pid_t fork(void)
1458 pid_t retval;
1460 WAIT_SEM();
1461 retval = (*fork_redir)();
1462 if (retval == 0)
1463 INIT_SEM();
1464 else
1465 POST_SEM();
1466 return retval;
1468 #endif
1470 #if MALLOC_REDIR
1471 void *malloc(size_t size)
1472 #else
1473 void *__bound_malloc(size_t size, const void *caller)
1474 #endif
1476 void *ptr;
1478 #if MALLOC_REDIR
1479 /* This will catch the first dlsym call from __bound_init */
1480 if (malloc_redir == NULL) {
1481 __bound_init (0, -1);
1482 if (malloc_redir == NULL) {
1483 ptr = &initial_pool[pool_index];
1484 pool_index = (pool_index + size + 15) & ~15;
1485 if (pool_index >= sizeof (initial_pool))
1486 bound_alloc_error ("initial memory pool too small");
1487 dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
1488 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1489 return ptr;
1492 #endif
1493 /* we allocate one more byte to ensure the regions will be
1494 separated by at least one byte. With the glibc malloc, it may
1495 be in fact not necessary */
1496 ptr = BOUND_MALLOC (size + 1);
1497 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1498 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1500 if (inited && NO_CHECKING_GET() == 0) {
1501 WAIT_SEM ();
1502 INCR_COUNT(bound_malloc_count);
1504 if (ptr) {
1505 tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
1506 if (tree && tree->start == (size_t) ptr)
1507 tree->type = TCC_TYPE_MALLOC;
1509 POST_SEM ();
1511 return ptr;
1514 #if MALLOC_REDIR
1515 void *memalign(size_t size, size_t align)
1516 #else
1517 void *__bound_memalign(size_t size, size_t align, const void *caller)
1518 #endif
1520 void *ptr;
1522 #if HAVE_MEMALIGN
1523 /* we allocate one more byte to ensure the regions will be
1524 separated by at least one byte. With the glibc malloc, it may
1525 be in fact not necessary */
1526 ptr = BOUND_MEMALIGN(size + 1, align);
1527 #else
1528 if (align > 4) {
1529 /* XXX: handle it ? */
1530 ptr = NULL;
1531 } else {
1532 /* we suppose that malloc aligns to at least four bytes */
1533 ptr = BOUND_MALLOC(size + 1);
1535 #endif
1536 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1537 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1539 if (NO_CHECKING_GET() == 0) {
1540 WAIT_SEM ();
1541 INCR_COUNT(bound_memalign_count);
1543 if (ptr) {
1544 tree = splay_insert((size_t) ptr, size ? size : size + 1, tree);
1545 if (tree && tree->start == (size_t) ptr)
1546 tree->type = TCC_TYPE_MEMALIGN;
1548 POST_SEM ();
1550 return ptr;
1553 #if MALLOC_REDIR
1554 void free(void *ptr)
1555 #else
1556 void __bound_free(void *ptr, const void *caller)
1557 #endif
1559 size_t addr = (size_t) ptr;
1560 void *p;
1562 if (ptr == NULL || tree == NULL
1563 #if MALLOC_REDIR
1564 || ((unsigned char *) ptr >= &initial_pool[0] &&
1565 (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)])
1566 #endif
1568 return;
1570 dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr);
1572 if (inited && NO_CHECKING_GET() == 0) {
1573 WAIT_SEM ();
1574 INCR_COUNT(bound_free_count);
1575 tree = splay (addr, tree);
1576 if (tree->start == addr) {
1577 if (tree->is_invalid) {
1578 POST_SEM ();
1579 bound_error("freeing invalid region");
1580 return;
1582 tree->is_invalid = 1;
1583 memset (ptr, 0x5a, tree->size);
1584 p = free_reuse_list[free_reuse_index];
1585 free_reuse_list[free_reuse_index] = ptr;
1586 free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE;
1587 if (p)
1588 tree = splay_delete((size_t)p, tree);
1589 ptr = p;
1591 POST_SEM ();
1593 BOUND_FREE (ptr);
1596 #if MALLOC_REDIR
1597 void *realloc(void *ptr, size_t size)
1598 #else
1599 void *__bound_realloc(void *ptr, size_t size, const void *caller)
1600 #endif
1602 void *new_ptr;
1604 if (size == 0) {
1605 #if MALLOC_REDIR
1606 free(ptr);
1607 #else
1608 __bound_free(ptr, caller);
1609 #endif
1610 return NULL;
1613 new_ptr = BOUND_REALLOC (ptr, size + 1);
1614 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1615 __FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
1617 if (NO_CHECKING_GET() == 0) {
1618 WAIT_SEM ();
1619 INCR_COUNT(bound_realloc_count);
1621 if (ptr)
1622 tree = splay_delete ((size_t) ptr, tree);
1623 if (new_ptr) {
1624 tree = splay_insert ((size_t) new_ptr, size ? size : size + 1, tree);
1625 if (tree && tree->start == (size_t) new_ptr)
1626 tree->type = TCC_TYPE_REALLOC;
1628 POST_SEM ();
1630 return new_ptr;
1633 #if MALLOC_REDIR
1634 void *calloc(size_t nmemb, size_t size)
1635 #else
1636 void *__bound_calloc(size_t nmemb, size_t size)
1637 #endif
1639 void *ptr;
1641 size *= nmemb;
1642 #if MALLOC_REDIR
1643 /* This will catch the first dlsym call from __bound_init */
1644 if (malloc_redir == NULL) {
1645 __bound_init (0, -1);
1646 if (malloc_redir == NULL) {
1647 ptr = &initial_pool[pool_index];
1648 pool_index = (pool_index + size + 15) & ~15;
1649 if (pool_index >= sizeof (initial_pool))
1650 bound_alloc_error ("initial memory pool too small");
1651 dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
1652 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1653 memset (ptr, 0, size);
1654 return ptr;
1657 #endif
1658 ptr = BOUND_MALLOC(size + 1);
1659 dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
1660 __FILE__, __FUNCTION__, ptr, (unsigned long)size);
1662 if (ptr) {
1663 memset (ptr, 0, size);
1664 if (NO_CHECKING_GET() == 0) {
1665 WAIT_SEM ();
1666 INCR_COUNT(bound_calloc_count);
1667 tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
1668 if (tree && tree->start == (size_t) ptr)
1669 tree->type = TCC_TYPE_CALLOC;
1670 POST_SEM ();
1673 return ptr;
1676 #if !defined(_WIN32)
1677 void *__bound_mmap (void *start, size_t size, int prot,
1678 int flags, int fd, off_t offset)
1680 void *result;
1682 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1683 __FILE__, __FUNCTION__, start, (unsigned long)size);
1684 result = mmap (start, size, prot, flags, fd, offset);
1685 if (result && NO_CHECKING_GET() == 0) {
1686 WAIT_SEM ();
1687 INCR_COUNT(bound_mmap_count);
1688 tree = splay_insert((size_t)result, size, tree);
1689 POST_SEM ();
1691 return result;
1694 int __bound_munmap (void *start, size_t size)
1696 int result;
1698 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
1699 __FILE__, __FUNCTION__, start, (unsigned long)size);
1700 if (start && NO_CHECKING_GET() == 0) {
1701 WAIT_SEM ();
1702 INCR_COUNT(bound_munmap_count);
1703 tree = splay_delete ((size_t) start, tree);
1704 POST_SEM ();
1706 result = munmap (start, size);
1707 return result;
1709 #endif
1711 /* some useful checked functions */
1713 /* check that (p ... p + size - 1) lies inside 'p' region, if any */
1714 static void __bound_check(const void *p, size_t size, const char *function)
1716 if (size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) {
1717 bound_error("invalid pointer %p, size 0x%lx in %s",
1718 p, (unsigned long)size, function);
1722 static int check_overlap (const void *p1, size_t n1,
1723 const void *p2, size_t n2,
1724 const char *function)
1726 const void *p1e = (const void *) ((const char *) p1 + n1);
1727 const void *p2e = (const void *) ((const char *) p2 + n2);
1729 if (NO_CHECKING_GET() == 0 && n1 != 0 && n2 !=0 &&
1730 ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
1731 (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
1732 bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
1733 p1, (unsigned long)n1, p2, (unsigned long)n2, function);
1734 return never_fatal < 0;
1736 return 0;
1739 void *__bound_memcpy(void *dest, const void *src, size_t n)
1741 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1742 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1743 INCR_COUNT(bound_mempcy_count);
1744 __bound_check(dest, n, "memcpy dest");
1745 __bound_check(src, n, "memcpy src");
1746 if (check_overlap(dest, n, src, n, "memcpy"))
1747 return dest;
1748 return memcpy(dest, src, n);
1751 int __bound_memcmp(const void *s1, const void *s2, size_t n)
1753 const unsigned char *u1 = (const unsigned char *) s1;
1754 const unsigned char *u2 = (const unsigned char *) s2;
1755 int retval = 0;
1757 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1758 __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
1759 INCR_COUNT(bound_memcmp_count);
1760 for (;;) {
1761 if ((ssize_t) --n == -1)
1762 break;
1763 else if (*u1 != *u2) {
1764 retval = *u1++ - *u2++;
1765 break;
1767 ++u1;
1768 ++u2;
1770 __bound_check(s1, (const void *)u1 - s1, "memcmp s1");
1771 __bound_check(s2, (const void *)u2 - s2, "memcmp s2");
1772 return retval;
1775 void *__bound_memmove(void *dest, const void *src, size_t n)
1777 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1778 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1779 INCR_COUNT(bound_memmove_count);
1780 __bound_check(dest, n, "memmove dest");
1781 __bound_check(src, n, "memmove src");
1782 return memmove(dest, src, n);
1785 void *__bound_memset(void *s, int c, size_t n)
1787 dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
1788 __FILE__, __FUNCTION__, s, c, (unsigned long)n);
1789 INCR_COUNT(bound_memset_count);
1790 __bound_check(s, n, "memset");
1791 return memset(s, c, n);
1794 #if defined(__arm__) && defined(__ARM_EABI__)
1795 void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n)
1797 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1798 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1799 INCR_COUNT(bound_mempcy_count);
1800 __bound_check(dest, n, "memcpy dest");
1801 __bound_check(src, n, "memcpy src");
1802 if (check_overlap(dest, n, src, n, "memcpy"))
1803 return dest;
1804 return __aeabi_memcpy(dest, src, n);
1807 void *__bound___aeabi_memmove(void *dest, const void *src, size_t n)
1809 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1810 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1811 INCR_COUNT(bound_memmove_count);
1812 __bound_check(dest, n, "memmove dest");
1813 __bound_check(src, n, "memmove src");
1814 return __aeabi_memmove(dest, src, n);
1817 void *__bound___aeabi_memmove4(void *dest, const void *src, size_t n)
1819 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1820 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1821 INCR_COUNT(bound_memmove_count);
1822 __bound_check(dest, n, "memmove dest");
1823 __bound_check(src, n, "memmove src");
1824 return __aeabi_memmove4(dest, src, n);
1827 void *__bound___aeabi_memmove8(void *dest, const void *src, size_t n)
1829 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1830 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1831 INCR_COUNT(bound_memmove_count);
1832 __bound_check(dest, n, "memmove dest");
1833 __bound_check(src, n, "memmove src");
1834 return __aeabi_memmove8(dest, src, n);
1837 void *__bound___aeabi_memset(void *s, int c, size_t n)
1839 dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
1840 __FILE__, __FUNCTION__, s, c, (unsigned long)n);
1841 INCR_COUNT(bound_memset_count);
1842 __bound_check(s, n, "memset");
1843 return __aeabi_memset(s, c, n);
1845 #endif
1847 int __bound_strlen(const char *s)
1849 const char *p = s;
1851 dprintf(stderr, "%s, %s(): %p\n",
1852 __FILE__, __FUNCTION__, s);
1853 INCR_COUNT(bound_strlen_count);
1854 while (*p++);
1855 __bound_check(s, p - s, "strlen");
1856 return (p - s) - 1;
1859 char *__bound_strcpy(char *dest, const char *src)
1861 size_t len;
1862 const char *p = src;
1864 dprintf(stderr, "%s, %s(): %p, %p\n",
1865 __FILE__, __FUNCTION__, dest, src);
1866 INCR_COUNT(bound_strcpy_count);
1867 while (*p++);
1868 len = p - src;
1869 __bound_check(dest, len, "strcpy dest");
1870 __bound_check(src, len, "strcpy src");
1871 if (check_overlap(dest, len, src, len, "strcpy"))
1872 return dest;
1873 return strcpy (dest, src);
1876 char *__bound_strncpy(char *dest, const char *src, size_t n)
1878 size_t len = n;
1879 const char *p = src;
1881 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1882 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1883 INCR_COUNT(bound_strncpy_count);
1884 while (len-- && *p++);
1885 len = p - src;
1886 __bound_check(dest, len, "strncpy dest");
1887 __bound_check(src, len, "strncpy src");
1888 if (check_overlap(dest, len, src, len, "strncpy"))
1889 return dest;
1890 return strncpy(dest, src, n);
1893 int __bound_strcmp(const char *s1, const char *s2)
1895 const unsigned char *u1 = (const unsigned char *) s1;
1896 const unsigned char *u2 = (const unsigned char *) s2;
1898 dprintf(stderr, "%s, %s(): %p, %p\n",
1899 __FILE__, __FUNCTION__, s1, s2);
1900 INCR_COUNT(bound_strcmp_count);
1901 while (*u1 && *u1 == *u2) {
1902 ++u1;
1903 ++u2;
1905 __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp s1");
1906 __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp s2");
1907 return *u1 - *u2;
1910 int __bound_strncmp(const char *s1, const char *s2, size_t n)
1912 const unsigned char *u1 = (const unsigned char *) s1;
1913 const unsigned char *u2 = (const unsigned char *) s2;
1914 int retval = 0;
1916 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1917 __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
1918 INCR_COUNT(bound_strncmp_count);
1919 do {
1920 if ((ssize_t) --n == -1)
1921 break;
1922 else if (*u1 != *u2) {
1923 retval = *u1++ - *u2++;
1924 break;
1926 ++u2;
1927 } while (*u1++);
1928 __bound_check(s1, (const char *)u1 - s1, "strncmp s1");
1929 __bound_check(s2, (const char *)u2 - s2, "strncmp s2");
1930 return retval;
1933 char *__bound_strcat(char *dest, const char *src)
1935 char *r = dest;
1936 const char *s = src;
1938 dprintf(stderr, "%s, %s(): %p, %p\n",
1939 __FILE__, __FUNCTION__, dest, src);
1940 INCR_COUNT(bound_strcat_count);
1941 while (*dest++);
1942 while (*src++);
1943 __bound_check(r, (dest - r) + (src - s) - 1, "strcat dest");
1944 __bound_check(s, src - s, "strcat src");
1945 if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strcat"))
1946 return dest;
1947 return strcat(r, s);
1950 char *__bound_strncat(char *dest, const char *src, size_t n)
1952 char *r = dest;
1953 const char *s = src;
1954 size_t len = n;
1956 dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
1957 __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
1958 INCR_COUNT(bound_strncat_count);
1959 while (*dest++);
1960 while (len-- && *src++);
1961 __bound_check(r, (dest - r) + (src - s) - 1, "strncat dest");
1962 __bound_check(s, src - s, "strncat src");
1963 if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strncat"))
1964 return dest;
1965 return strncat(r, s, n);
1968 char *__bound_strchr(const char *s, int c)
1970 const unsigned char *str = (const unsigned char *) s;
1971 unsigned char ch = c;
1973 dprintf(stderr, "%s, %s(): %p, %d\n",
1974 __FILE__, __FUNCTION__, s, ch);
1975 INCR_COUNT(bound_strchr_count);
1976 while (*str) {
1977 if (*str == ch)
1978 break;
1979 ++str;
1981 __bound_check(s, ((const char *)str - s) + 1, "strchr");
1982 return *str == ch ? (char *) str : NULL;
1985 char *__bound_strrchr(const char *s, int c)
1987 const unsigned char *str = (const unsigned char *) s;
1988 unsigned char ch = c;
1990 dprintf(stderr, "%s, %s(): %p, %d\n",
1991 __FILE__, __FUNCTION__, s, ch);
1992 INCR_COUNT(bound_strrchr_count);
1993 while (*str++);
1994 __bound_check(s, (const char *)str - s, "strrchr");
1995 while (str != (const unsigned char *)s) {
1996 if (*--str == ch)
1997 break;
1999 __bound_check(s, (const char *)str - s, "strrchr");
2000 return *str == ch ? (char *) str : NULL;
2003 char *__bound_strdup(const char *s)
2005 const char *p = s;
2006 char *new;
2008 INCR_COUNT(bound_strdup_count);
2009 while (*p++);
2010 __bound_check(s, p - s, "strdup");
2011 new = BOUND_MALLOC ((p - s) + 1);
2012 dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
2013 __FILE__, __FUNCTION__, new, (unsigned long)(p -s));
2014 if (new) {
2015 if (NO_CHECKING_GET() == 0 && no_strdup == 0) {
2016 WAIT_SEM ();
2017 tree = splay_insert((size_t)new, p - s, tree);
2018 if (tree && tree->start == (size_t) new)
2019 tree->type = TCC_TYPE_STRDUP;
2020 POST_SEM ();
2022 memcpy (new, s, p - s);
2024 return new;
2028 An implementation of top-down splaying with sizes
2029 D. Sleator <sleator@cs.cmu.edu>, January 1994.
2031 This extends top-down-splay.c to maintain a size field in each node.
2032 This is the number of nodes in the subtree rooted there. This makes
2033 it possible to efficiently compute the rank of a key. (The rank is
2034 the number of nodes to the left of the given key.) It it also
2035 possible to quickly find the node of a given rank. Both of these
2036 operations are illustrated in the code below. The remainder of this
2037 introduction is taken from top-down-splay.c.
2039 "Splay trees", or "self-adjusting search trees" are a simple and
2040 efficient data structure for storing an ordered set. The data
2041 structure consists of a binary tree, with no additional fields. It
2042 allows searching, insertion, deletion, deletemin, deletemax,
2043 splitting, joining, and many other operations, all with amortized
2044 logarithmic performance. Since the trees adapt to the sequence of
2045 requests, their performance on real access patterns is typically even
2046 better. Splay trees are described in a number of texts and papers
2047 [1,2,3,4].
2049 The code here is adapted from simple top-down splay, at the bottom of
2050 page 669 of [2]. It can be obtained via anonymous ftp from
2051 spade.pc.cs.cmu.edu in directory /usr/sleator/public.
2053 The chief modification here is that the splay operation works even if the
2054 item being splayed is not in the tree, and even if the tree root of the
2055 tree is NULL. So the line:
2057 t = splay(i, t);
2059 causes it to search for item with key i in the tree rooted at t. If it's
2060 there, it is splayed to the root. If it isn't there, then the node put
2061 at the root is the last one before NULL that would have been reached in a
2062 normal binary search for i. (It's a neighbor of i in the tree.) This
2063 allows many other operations to be easily implemented, as shown below.
2065 [1] "Data Structures and Their Algorithms", Lewis and Denenberg,
2066 Harper Collins, 1991, pp 243-251.
2067 [2] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
2068 JACM Volume 32, No 3, July 1985, pp 652-686.
2069 [3] "Data Structure and Algorithm Analysis", Mark Weiss,
2070 Benjamin Cummins, 1992, pp 119-130.
2071 [4] "Data Structures, Algorithms, and Performance", Derick Wood,
2072 Addison-Wesley, 1993, pp 367-375
2075 /* Code adapted for tcc */
2077 #define compare(start,tstart,tsize) (start < tstart ? -1 : \
2078 start >= tstart+tsize ? 1 : 0)
2080 static Tree * splay (size_t addr, Tree *t)
2081 /* Splay using the key start (which may or may not be in the tree.) */
2082 /* The starting root is t, and the tree used is defined by rat */
2084 Tree N, *l, *r, *y;
2085 int comp;
2087 INCR_COUNT_SPLAY(bound_splay);
2088 if (t == NULL) return t;
2089 N.left = N.right = NULL;
2090 l = r = &N;
2092 for (;;) {
2093 comp = compare(addr, t->start, t->size);
2094 if (comp < 0) {
2095 y = t->left;
2096 if (y == NULL) break;
2097 if (compare(addr, y->start, y->size) < 0) {
2098 t->left = y->right; /* rotate right */
2099 y->right = t;
2100 t = y;
2101 if (t->left == NULL) break;
2103 r->left = t; /* link right */
2104 r = t;
2105 t = t->left;
2106 } else if (comp > 0) {
2107 y = t->right;
2108 if (y == NULL) break;
2109 if (compare(addr, y->start, y->size) > 0) {
2110 t->right = y->left; /* rotate left */
2111 y->left = t;
2112 t = y;
2113 if (t->right == NULL) break;
2115 l->right = t; /* link left */
2116 l = t;
2117 t = t->right;
2118 } else {
2119 break;
2122 l->right = t->left; /* assemble */
2123 r->left = t->right;
2124 t->left = N.right;
2125 t->right = N.left;
2127 return t;
2130 #define compare_end(start,tend) (start < tend ? -1 : \
2131 start > tend ? 1 : 0)
2133 static Tree * splay_end (size_t addr, Tree *t)
2134 /* Splay using the key start (which may or may not be in the tree.) */
2135 /* The starting root is t, and the tree used is defined by rat */
2137 Tree N, *l, *r, *y;
2138 int comp;
2140 INCR_COUNT_SPLAY(bound_splay_end);
2141 if (t == NULL) return t;
2142 N.left = N.right = NULL;
2143 l = r = &N;
2145 for (;;) {
2146 comp = compare_end(addr, t->start + t->size);
2147 if (comp < 0) {
2148 y = t->left;
2149 if (y == NULL) break;
2150 if (compare_end(addr, y->start + y->size) < 0) {
2151 t->left = y->right; /* rotate right */
2152 y->right = t;
2153 t = y;
2154 if (t->left == NULL) break;
2156 r->left = t; /* link right */
2157 r = t;
2158 t = t->left;
2159 } else if (comp > 0) {
2160 y = t->right;
2161 if (y == NULL) break;
2162 if (compare_end(addr, y->start + y->size) > 0) {
2163 t->right = y->left; /* rotate left */
2164 y->left = t;
2165 t = y;
2166 if (t->right == NULL) break;
2168 l->right = t; /* link left */
2169 l = t;
2170 t = t->right;
2171 } else {
2172 break;
2175 l->right = t->left; /* assemble */
2176 r->left = t->right;
2177 t->left = N.right;
2178 t->right = N.left;
2180 return t;
2183 static Tree * splay_insert(size_t addr, size_t size, Tree * t)
2184 /* Insert key start into the tree t, if it is not already there. */
2185 /* Return a pointer to the resulting tree. */
2187 Tree * new;
2189 INCR_COUNT_SPLAY(bound_splay_insert);
2190 if (t != NULL) {
2191 t = splay(addr,t);
2192 if (compare(addr, t->start, t->size)==0) {
2193 return t; /* it's already there */
2196 #if TREE_REUSE
2197 if (tree_free_list) {
2198 new = tree_free_list;
2199 tree_free_list = new->left;
2201 else
2202 #endif
2204 new = (Tree *) BOUND_MALLOC (sizeof (Tree));
2206 if (new == NULL) {
2207 bound_alloc_error("not enough memory for bound checking code");
2209 else {
2210 if (t == NULL) {
2211 new->left = new->right = NULL;
2212 } else if (compare(addr, t->start, t->size) < 0) {
2213 new->left = t->left;
2214 new->right = t;
2215 t->left = NULL;
2216 } else {
2217 new->right = t->right;
2218 new->left = t;
2219 t->right = NULL;
2221 new->start = addr;
2222 new->size = size;
2223 new->type = TCC_TYPE_NONE;
2224 new->is_invalid = 0;
2226 return new;
2229 #define compare_destroy(start,tstart) (start < tstart ? -1 : \
2230 start > tstart ? 1 : 0)
2232 static Tree * splay_delete(size_t addr, Tree *t)
2233 /* Deletes addr from the tree if it's there. */
2234 /* Return a pointer to the resulting tree. */
2236 Tree * x;
2238 INCR_COUNT_SPLAY(bound_splay_delete);
2239 if (t==NULL) return NULL;
2240 t = splay(addr,t);
2241 if (compare_destroy(addr, t->start) == 0) { /* found it */
2242 if (t->left == NULL) {
2243 x = t->right;
2244 } else {
2245 x = splay(addr, t->left);
2246 x->right = t->right;
2248 #if TREE_REUSE
2249 t->left = tree_free_list;
2250 tree_free_list = t;
2251 #else
2252 BOUND_FREE(t);
2253 #endif
2254 return x;
2255 } else {
2256 return t; /* It wasn't there */
2260 void splay_printtree(Tree * t, int d)
2262 int i;
2263 if (t == NULL) return;
2264 splay_printtree(t->right, d+1);
2265 for (i=0; i<d; i++) fprintf(stderr," ");
2266 fprintf(stderr,"%p(0x%lx:%u:%u)\n",
2267 (void *) t->start, (unsigned long) t->size,
2268 (unsigned)t->type, (unsigned)t->is_invalid);
2269 splay_printtree(t->left, d+1);