| @@ -35,6 +35,7 @@ · 34 unmodified lines |
| 35 | 35 | #endif |
| 36 | 36 | |
| 37 | 37 | #define BOUND_DEBUG |
| 38 | +#define BOUND_STATISTIC |
| 38 | 39 | |
| 39 | 40 | #ifdef BOUND_DEBUG |
| 40 | 41 | #define dprintf(a...) if (print_calls) fprintf(a) |
| @@ -50,8 +51,7 @@ · 9 unmodified lines |
| 50 | 51 | || defined(__DragonFly__) \ |
| 51 | 52 | || defined(__OpenBSD__) \ |
| 52 | 53 | || defined(__NetBSD__) \ |
| 53 | | − || defined(__dietlibc__) \ |
| 54 | | − || defined(_WIN32) |
| 54 | + || defined(__dietlibc__) |
| 55 | 55 | #undef HAVE_MEMALIGN |
| 56 | 56 | #define INIT_SEM() |
| 57 | 57 | #define EXIT_SEM() |
| @@ -59,6 +59,16 @@ · 1 unmodified line |
| 59 | 59 | #define POST_SEM() |
| 60 | 60 | #define HAS_ENVIRON 0 |
| 61 | 61 | #define MALLOC_REDIR (0) |
| 62 | +#elif defined(_WIN32) |
| 63 | +#include <windows.h> |
| 64 | +#undef HAVE_MEMALIGN |
| 65 | +static CRITICAL_SECTION bounds_sem; |
| 66 | +#define INIT_SEM() InitializeCriticalSection(&bounds_sem) |
| 67 | +#define EXIT_SEM() DeleteCriticalSection(&bounds_sem) |
| 68 | +#define WAIT_SEM() EnterCriticalSection(&bounds_sem) |
| 69 | +#define POST_SEM() LeaveCriticalSection(&bounds_sem) |
| 70 | +#define HAS_ENVIRON 0 |
| 71 | +#define MALLOC_REDIR (0) |
| 62 | 72 | #else |
| 63 | 73 | #include <sys/mman.h> |
| 64 | 74 | #include <errno.h> |
| @@ -86,6 +96,7 @@ static unsigned char initial_pool[256]; · 21 unmodified lines |
| 86 | 96 | #define TCC_TYPE_CALLOC (2) |
| 87 | 97 | #define TCC_TYPE_REALLOC (3) |
| 88 | 98 | #define TCC_TYPE_MEMALIGN (4) |
| 99 | +#define TCC_TYPE_STRDUP (5) |
| 89 | 100 | |
| 90 | 101 | /* this pointer is generated when bound check is incorrect */ |
| 91 | 102 | #define INVALID_POINTER ((void *)(-2)) |
| @@ -149,9 +160,45 @@ static alloca_list_type *alloca_list = NULL; · 57 unmodified lines |
| 149 | 160 | static int inited = 0; |
| 150 | 161 | static int print_calls = 0; |
| 151 | 162 | static int print_heap = 0; |
| 163 | +static int print_statistic = 0; |
| 152 | 164 | static int never_fatal = 0; |
| 153 | 165 | static int no_checking = 0; |
| 154 | 166 | |
| 167 | +#ifdef BOUND_STATISTIC |
| 168 | +static unsigned long bound_ptr_add_count; |
| 169 | +static unsigned long bound_ptr_indir1_count; |
| 170 | +static unsigned long bound_ptr_indir2_count; |
| 171 | +static unsigned long bound_ptr_indir4_count; |
| 172 | +static unsigned long bound_ptr_indir8_count; |
| 173 | +static unsigned long bound_ptr_indir12_count; |
| 174 | +static unsigned long bound_ptr_indir16_count; |
| 175 | +static unsigned long bound_local_new_count; |
| 176 | +static unsigned long bound_local_delete_count; |
| 177 | +static unsigned long bound_malloc_count; |
| 178 | +static unsigned long bound_calloc_count; |
| 179 | +static unsigned long bound_realloc_count; |
| 180 | +static unsigned long bound_free_count; |
| 181 | +static unsigned long bound_memalign_count; |
| 182 | +static unsigned long bound_mmap_count; |
| 183 | +static unsigned long bound_munmap_count; |
| 184 | +static unsigned long bound_alloca_count; |
| 185 | +static unsigned long bound_mempcy_count; |
| 186 | +static unsigned long bound_memcmp_count; |
| 187 | +static unsigned long bound_memmove_count; |
| 188 | +static unsigned long bound_memset_count; |
| 189 | +static unsigned long bound_strlen_count; |
| 190 | +static unsigned long bound_strcpy_count; |
| 191 | +static unsigned long bound_strncpy_count; |
| 192 | +static unsigned long bound_strcmp_count; |
| 193 | +static unsigned long bound_strncmp_count; |
| 194 | +static unsigned long bound_strcat_count; |
| 195 | +static unsigned long bound_strchr_count; |
| 196 | +static unsigned long bound_strdup_count; |
| 197 | +#define INCR_COUNT(x) x++ |
| 198 | +#else |
| 199 | +#define INCR_COUNT(x) |
| 200 | +#endif |
| 201 | + |
| 155 | 202 | /* enable/disable checking. This can be used for signal handlers. */ |
| 156 | 203 | void __bound_checking (int no_check) |
| 157 | 204 | { |
| @@ -186,6 +233,7 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset) · 28 unmodified lines |
| 186 | 233 | __FILE__, __FUNCTION__, p, (unsigned)offset); |
| 187 | 234 | |
| 188 | 235 | WAIT_SEM (); |
| 236 | + INCR_COUNT(bound_ptr_add_count); |
| 189 | 237 | if (tree) { |
| 190 | 238 | tree = splay (addr, tree); |
| 191 | 239 | addr -= tree->start; |
| @@ -223,6 +271,7 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ · 31 unmodified lines |
| 223 | 271 | dprintf(stderr, "%s %s: %p 0x%x start\n", \ |
| 224 | 272 | __FILE__, __FUNCTION__, p, (unsigned)offset); \ |
| 225 | 273 | WAIT_SEM (); \ |
| 274 | + INCR_COUNT(bound_ptr_indir ## dsize ## _count); \ |
| 226 | 275 | if (tree) { \ |
| 227 | 276 | tree = splay (addr, tree); \ |
| 228 | 277 | addr -= tree->start; \ |
| @@ -284,6 +333,7 @@ void FASTCALL __bound_local_new(void *p1) · 55 unmodified lines |
| 284 | 333 | addr = p[0]; |
| 285 | 334 | if (addr == 0) |
| 286 | 335 | break; |
| 336 | + INCR_COUNT(bound_local_new_count); |
| 287 | 337 | if (addr == 1) { |
| 288 | 338 | dprintf(stderr, "%s, %s() alloca/vla used\n", |
| 289 | 339 | __FILE__, __FUNCTION__); |
| @@ -315,6 +365,7 @@ void FASTCALL __bound_local_delete(void *p1) · 25 unmodified lines |
| 315 | 365 | addr = p[0]; |
| 316 | 366 | if (addr == 0) |
| 317 | 367 | break; |
| 368 | + INCR_COUNT(bound_local_delete_count); |
| 318 | 369 | if (addr == 1) { |
| 319 | 370 | while (alloca_list && alloca_list->fp == fp) { |
| 320 | 371 | alloca_list_type *next = alloca_list->next; |
| @@ -350,6 +401,7 @@ void __bound_init(void) · 29 unmodified lines |
| 350 | 401 | |
| 351 | 402 | print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL; |
| 352 | 403 | print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL; |
| 404 | + print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL; |
| 353 | 405 | never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL; |
| 354 | 406 | |
| 355 | 407 | dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__); |
| @@ -444,7 +496,7 @@ void __attribute__((destructor)) __bound_exit(void) · 88 unmodified lines |
| 444 | 496 | { |
| 445 | 497 | int i; |
| 446 | 498 | static const char * const alloc_type[] = { |
| 447 | | − "", "malloc", "calloc", "realloc", "memalign" |
| 499 | + "", "malloc", "calloc", "realloc", "memalign", "strdup" |
| 448 | 500 | }; |
| 449 | 501 | |
| 450 | 502 | dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__); |
| @@ -488,6 +540,39 @@ void __attribute__((destructor)) __bound_exit(void) · 37 unmodified lines |
| 488 | 540 | } |
| 489 | 541 | EXIT_SEM (); |
| 490 | 542 | inited = 0; |
| 543 | +#ifdef BOUND_STATISTIC |
| 544 | + if (print_statistic) { |
| 545 | + fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count); |
| 546 | + fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count); |
| 547 | + fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count); |
| 548 | + fprintf (stderr, "bound_ptr_indir4_count %llu\n", bound_ptr_indir4_count); |
| 549 | + fprintf (stderr, "bound_ptr_indir8_count %llu\n", bound_ptr_indir8_count); |
| 550 | + fprintf (stderr, "bound_ptr_indir12_count %llu\n", bound_ptr_indir12_count); |
| 551 | + fprintf (stderr, "bound_ptr_indir16_count %llu\n", bound_ptr_indir16_count); |
| 552 | + fprintf (stderr, "bound_local_new_count %llu\n", bound_local_new_count); |
| 553 | + fprintf (stderr, "bound_local_delete_count %llu\n", bound_local_delete_count); |
| 554 | + fprintf (stderr, "bound_malloc_count %llu\n", bound_malloc_count); |
| 555 | + fprintf (stderr, "bound_calloc_count %llu\n", bound_calloc_count); |
| 556 | + fprintf (stderr, "bound_realloc_count %llu\n", bound_realloc_count); |
| 557 | + fprintf (stderr, "bound_free_count %llu\n", bound_free_count); |
| 558 | + fprintf (stderr, "bound_memalign_count %llu\n", bound_memalign_count); |
| 559 | + fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count); |
| 560 | + fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count); |
| 561 | + fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count); |
| 562 | + fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count); |
| 563 | + fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count); |
| 564 | + fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count); |
| 565 | + fprintf (stderr, "bound_memset_count %llu\n", bound_memset_count); |
| 566 | + fprintf (stderr, "bound_strlen_count %llu\n", bound_strlen_count); |
| 567 | + fprintf (stderr, "bound_strcpy_count %llu\n", bound_strcpy_count); |
| 568 | + fprintf (stderr, "bound_strncpy_count %llu\n", bound_strncpy_count); |
| 569 | + fprintf (stderr, "bound_strcmp_count %llu\n", bound_strcmp_count); |
| 570 | + fprintf (stderr, "bound_strncmp_count %llu\n", bound_strncmp_count); |
| 571 | + fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count); |
| 572 | + fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count); |
| 573 | + fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count); |
| 574 | + } |
| 575 | +#endif |
| 491 | 576 | } |
| 492 | 577 | } |
| 493 | 578 | |
| @@ -516,6 +601,7 @@ void *__bound_malloc(size_t size, const void *caller) · 22 unmodified lines |
| 516 | 601 | separated by at least one byte. With the glibc malloc, it may |
| 517 | 602 | be in fact not necessary */ |
| 518 | 603 | WAIT_SEM (); |
| 604 | + INCR_COUNT(bound_malloc_count); |
| 519 | 605 | #if MALLOC_REDIR |
| 520 | 606 | ptr = malloc_redir (size); |
| 521 | 607 | #else |
| @@ -544,6 +630,7 @@ void *__bound_memalign(size_t size, size_t align, const void *caller) · 22 unmodified lines |
| 544 | 630 | void *ptr; |
| 545 | 631 | |
| 546 | 632 | WAIT_SEM (); |
| 633 | + INCR_COUNT(bound_memalign_count); |
| 547 | 634 | |
| 548 | 635 | #ifndef HAVE_MEMALIGN |
| 549 | 636 | if (align > 4) { |
| @@ -599,6 +686,7 @@ void __bound_free(void *ptr, const void *caller) · 49 unmodified lines |
| 599 | 686 | dprintf(stderr, "%s, %s (%p)\n", __FILE__, __FUNCTION__, ptr); |
| 600 | 687 | |
| 601 | 688 | WAIT_SEM (); |
| 689 | + INCR_COUNT(bound_free_count); |
| 602 | 690 | tree = splay (addr, tree); |
| 603 | 691 | if (tree->start == addr) { |
| 604 | 692 | if (tree->is_invalid) { |
| @@ -645,6 +733,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller) · 40 unmodified lines |
| 645 | 733 | ptr = realloc (ptr, size); |
| 646 | 734 | #endif |
| 647 | 735 | WAIT_SEM (); |
| 736 | + INCR_COUNT(bound_realloc_count); |
| 648 | 737 | if (ptr) { |
| 649 | 738 | tree = splay_insert ((size_t) ptr, size, tree); |
| 650 | 739 | if (tree->start == (size_t) ptr) { |
| @@ -701,6 +790,7 @@ void *__bound_calloc(size_t nmemb, size_t size) · 50 unmodified lines |
| 701 | 790 | if (ptr) { |
| 702 | 791 | memset (ptr, 0, size); |
| 703 | 792 | WAIT_SEM (); |
| 793 | + INCR_COUNT(bound_calloc_count); |
| 704 | 794 | tree = splay_insert ((size_t) ptr, size, tree); |
| 705 | 795 | if (tree->start == (size_t) ptr) { |
| 706 | 796 | tree->type = TCC_TYPE_CALLOC; |
| @@ -721,6 +811,7 @@ void *__bound_mmap (void *start, size_t size, int prot, · 14 unmodified lines |
| 721 | 811 | result = mmap (start, size, prot, flags, fd, offset); |
| 722 | 812 | if (result) { |
| 723 | 813 | WAIT_SEM (); |
| 814 | + INCR_COUNT(bound_mmap_count); |
| 724 | 815 | tree = splay_insert((size_t)result, size, tree); |
| 725 | 816 | POST_SEM (); |
| 726 | 817 | } |
| @@ -734,6 +825,7 @@ int __bound_munmap (void *start, size_t size) · 7 unmodified lines |
| 734 | 825 | dprintf(stderr, "%s, %s (%p, 0x%x)\n", |
| 735 | 826 | __FILE__, __FUNCTION__, start, (unsigned)size); |
| 736 | 827 | WAIT_SEM (); |
| 828 | + INCR_COUNT(bound_munmap_count); |
| 737 | 829 | tree = splay_delete ((size_t) start, tree); |
| 738 | 830 | POST_SEM (); |
| 739 | 831 | result = munmap (start, size); |
| @@ -751,6 +843,7 @@ void __bound_new_region(void *p, size_t size) · 11 unmodified lines |
| 751 | 843 | dprintf(stderr, "%s, %s (%p, 0x%x)\n", |
| 752 | 844 | __FILE__, __FUNCTION__, p, (unsigned)size); |
| 753 | 845 | WAIT_SEM (); |
| 846 | + INCR_COUNT(bound_alloca_count); |
| 754 | 847 | GET_CALLER_FP (fp); |
| 755 | 848 | last = NULL; |
| 756 | 849 | cur = alloca_list; |
| @@ -813,6 +906,7 @@ void *__bound_memcpy(void *dst, const void *src, size_t size) · 56 unmodified lines |
| 813 | 906 | { |
| 814 | 907 | void* p; |
| 815 | 908 | |
| 909 | + INCR_COUNT(bound_mempcy_count); |
| 816 | 910 | __bound_check(dst, size); |
| 817 | 911 | __bound_check(src, size); |
| 818 | 912 | /* check also region overlap */ |
| @@ -824,8 +918,17 @@ void *__bound_memcpy(void *dst, const void *src, size_t size) · 5 unmodified lines |
| 824 | 918 | return p; |
| 825 | 919 | } |
| 826 | 920 | |
| 921 | +int __bound_memcmp(const void *s1, const void *s2, size_t size) |
| 922 | +{ |
| 923 | + INCR_COUNT(bound_memcmp_count); |
| 924 | + __bound_check(s1, size); |
| 925 | + __bound_check(s2, size); |
| 926 | + return memcmp(s1, s2, size); |
| 927 | +} |
| 928 | + |
| 827 | 929 | void *__bound_memmove(void *dst, const void *src, size_t size) |
| 828 | 930 | { |
| 931 | + INCR_COUNT(bound_memmove_count); |
| 829 | 932 | __bound_check(dst, size); |
| 830 | 933 | __bound_check(src, size); |
| 831 | 934 | return memmove(dst, src, size); |
| @@ -833,25 +936,22 @@ void *__bound_memmove(void *dst, const void *src, size_t size) · 1 unmodified line |
| 833 | 936 | |
| 834 | 937 | void *__bound_memset(void *dst, int c, size_t size) |
| 835 | 938 | { |
| 939 | + INCR_COUNT(bound_memset_count); |
| 836 | 940 | __bound_check(dst, size); |
| 837 | 941 | return memset(dst, c, size); |
| 838 | 942 | } |
| 839 | 943 | |
| 840 | | −/* XXX: could be optimized */ |
| 841 | 944 | int __bound_strlen(const char *s) |
| 842 | 945 | { |
| 843 | | − const char *p; |
| 946 | + const char *p = s; |
| 844 | 947 | size_t len; |
| 845 | 948 | |
| 846 | | − len = 0; |
| 847 | | − for(;;) { |
| 848 | | − p = __bound_ptr_indir1((char *)s, len); |
| 849 | | − if (p == INVALID_POINTER) |
| 850 | | − bound_error("bad pointer in strlen()"); |
| 851 | | − if (*p == '\0') |
| 852 | | − break; |
| 853 | | − len++; |
| 854 | | − } |
| 949 | + INCR_COUNT(bound_strlen_count); |
| 950 | + while (*p++); |
| 951 | + len = (p - s) - 1; |
| 952 | + p = __bound_ptr_indir1((char *)s, len); |
| 953 | + if (p == INVALID_POINTER) |
| 954 | + bound_error("bad pointer in strlen()"); |
| 855 | 955 | return len; |
| 856 | 956 | } |
| 857 | 957 | |
| @@ -860,11 +960,101 @@ char *__bound_strcpy(char *dst, const char *src) · 2 unmodified lines |
| 860 | 960 | size_t len; |
| 861 | 961 | void *p; |
| 862 | 962 | |
| 963 | + INCR_COUNT(bound_strcpy_count); |
| 863 | 964 | len = __bound_strlen(src); |
| 864 | 965 | p = __bound_memcpy(dst, src, len + 1); |
| 865 | 966 | return p; |
| 866 | 967 | } |
| 867 | 968 | |
| 969 | +char *__bound_strncpy(char *dst, const char *src, size_t n) |
| 970 | +{ |
| 971 | + size_t len; |
| 972 | + void *p; |
| 973 | + |
| 974 | + INCR_COUNT(bound_strncpy_count); |
| 975 | + __bound_check(dst, n); |
| 976 | + __bound_check(src, n); |
| 977 | + return strncpy (dst, src, n); |
| 978 | +} |
| 979 | + |
| 980 | +int __bound_strcmp(const char *s1, const char *s2) |
| 981 | +{ |
| 982 | + const unsigned char *u1 = (const unsigned char *) s1; |
| 983 | + const unsigned char *u2 = (const unsigned char *) s2; |
| 984 | + |
| 985 | + INCR_COUNT(bound_strcmp_count); |
| 986 | + while (*u1 && *u1 == *u2) { |
| 987 | + u1++; |
| 988 | + u2++; |
| 989 | + } |
| 990 | + __bound_check(s1, ((const char *)u1 - s1) + 1); |
| 991 | + __bound_check(s2, ((const char *)u2 - s2) + 1); |
| 992 | + return (*u1 - *u2); |
| 993 | +} |
| 994 | + |
| 995 | +int __bound_strncmp(const char *s1, const char *s2, size_t n) |
| 996 | +{ |
| 997 | + INCR_COUNT(bound_strncmp_count); |
| 998 | + __bound_check(s1, n); |
| 999 | + __bound_check(s2, n); |
| 1000 | + return strncmp(s1, s2, n); |
| 1001 | +} |
| 1002 | + |
| 1003 | +char *__bound_strcat(char *dest, const char *src) |
| 1004 | +{ |
| 1005 | + char *r = dest; |
| 1006 | + const char *s = src; |
| 1007 | + |
| 1008 | + INCR_COUNT(bound_strcat_count); |
| 1009 | + while (*dest++); |
| 1010 | + dest--; |
| 1011 | + while ((*dest++ = *src++) != 0); |
| 1012 | + __bound_check(r, dest - r); |
| 1013 | + __bound_check(s, src - s); |
| 1014 | + return r; |
| 1015 | +} |
| 1016 | + |
| 1017 | +char *__bound_strchr(const char *string, int ch) |
| 1018 | +{ |
| 1019 | + const unsigned char *s = (const unsigned char *) string; |
| 1020 | + unsigned char c = ch; |
| 1021 | + |
| 1022 | + INCR_COUNT(bound_strchr_count); |
| 1023 | + while (*s) { |
| 1024 | + if (*s == c) { |
| 1025 | + break; |
| 1026 | + } |
| 1027 | + s++; |
| 1028 | + } |
| 1029 | + __bound_check(string, ((const char *)s - string) + 1); |
| 1030 | + return *s == c ? (char *) s : NULL; |
| 1031 | +} |
| 1032 | + |
| 1033 | +char *__bound_strdup(const char *s) |
| 1034 | +{ |
| 1035 | + const char *p = s; |
| 1036 | + char *new; |
| 1037 | + |
| 1038 | + INCR_COUNT(bound_strdup_count); |
| 1039 | + while (*p++); |
| 1040 | + __bound_check(s, p - s); |
| 1041 | +#if MALLOC_REDIR |
| 1042 | + new = malloc_redir (p - s); |
| 1043 | +#else |
| 1044 | + new = malloc (p - s); |
| 1045 | +#endif |
| 1046 | + if (new) { |
| 1047 | + WAIT_SEM (); |
| 1048 | + tree = splay_insert((size_t)new, p - s, tree); |
| 1049 | + if (tree->start == (size_t) new) { |
| 1050 | + tree->type = TCC_TYPE_STRDUP; |
| 1051 | + } |
| 1052 | + memcpy (new, s, p - s); |
| 1053 | + POST_SEM (); |
| 1054 | + } |
| 1055 | + return new; |
| 1056 | +} |
| 1057 | + |
| 868 | 1058 | /* |
| 869 | 1059 | An implementation of top-down splaying with sizes |
| 870 | 1060 | D. Sleator <sleator@cs.cmu.edu>, January 1994. |