tcc-doc.texi: - Document attribute bound_no_checking tcctok.h: - Add bound_no_checking attribute tcc.h: - Add no_bcheck function attribute tccgen.c: - Use function attribute no_bcheck in merge_funcattr/parse_attribute/gen_function bcheck.c: - Fix no_checking in __bound_new_region/__bound_free/__bound_check tests/tests2/114_bound_signal.c: - Fix code with new attribute bound_no_checking tests/tests2/103_implicit_memmove.c: - Fix memmove prototype
Unified · Split
| @@ -112,6 +112,12 @@ static sem_t bounds_sem; · 111 unmodified lines | ||
| 112 | 112 | #define WAIT_SEM() if (use_sem) while (sem_wait (&bounds_sem) < 0 \ |
| 113 | 113 | && errno == EINTR) |
| 114 | 114 | #define POST_SEM() if (use_sem) sem_post (&bounds_sem) |
| 115 | +#elif 0 | |
| 116 | +static pthread_mutex_t bounds_mtx; | |
| 117 | +#define INIT_SEM() pthread_mutex_init (&bounds_mtx, NULL) | |
| 118 | +#define EXIT_SEM() pthread_mutex_destroy (&bounds_mtx) | |
| 119 | +#define WAIT_SEM() if (use_sem) pthread_mutex_lock (&bounds_mtx) | |
| 120 | +#define POST_SEM() if (use_sem) pthread_mutex_unlock (&bounds_mtx) | |
| 115 | 121 | #else |
| 116 | 122 | static pthread_spinlock_t bounds_spin; |
| 117 | 123 | /* about 25% faster then semaphore. */ |
| @@ -618,6 +624,9 @@ void __bound_new_region(void *p, size_t size) · 500 unmodified lines | ||
| 618 | 624 | alloca_list_type *cur; |
| 619 | 625 | alloca_list_type *new; |
| 620 | 626 | |
| 627 | + if (no_checking) | |
| 628 | + return; | |
| 629 | + | |
| 621 | 630 | dprintf(stderr, "%s, %s(): %p, 0x%lx\n", |
| 622 | 631 | __FILE__, __FUNCTION__, p, (unsigned long)size); |
| 623 | 632 | GET_CALLER_FP (fp); |
| @@ -638,8 +647,7 @@ void __bound_new_region(void *p, size_t size) · 14 unmodified lines | ||
| 638 | 647 | last = cur; |
| 639 | 648 | cur = cur->next; |
| 640 | 649 | } |
| 641 | − if (no_checking == 0) | |
| 642 | − tree = splay_insert((size_t)p, size, tree); | |
| 650 | + tree = splay_insert((size_t)p, size, tree); | |
| 643 | 651 | if (new) { |
| 644 | 652 | new->fp = fp; |
| 645 | 653 | new->p = p; |
| @@ -1188,7 +1196,7 @@ void __bound_free(void *ptr, const void *caller) · 542 unmodified lines | ||
| 1188 | 1196 | size_t addr = (size_t) ptr; |
| 1189 | 1197 | void *p; |
| 1190 | 1198 | |
| 1191 | − if (ptr == NULL || tree == NULL || no_checking | |
| 1199 | + if (ptr == NULL || tree == NULL | |
| 1192 | 1200 | #if MALLOC_REDIR |
| 1193 | 1201 | || ((unsigned char *) ptr >= &initial_pool[0] && |
| 1194 | 1202 | (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)]) |
| @@ -1198,25 +1206,27 @@ void __bound_free(void *ptr, const void *caller) · 3 unmodified lines | ||
| 1198 | 1206 | |
| 1199 | 1207 | dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr); |
| 1200 | 1208 | |
| 1201 | − WAIT_SEM (); | |
| 1202 | − INCR_COUNT(bound_free_count); | |
| 1203 | − tree = splay (addr, tree); | |
| 1204 | − if (tree->start == addr) { | |
| 1205 | − if (tree->is_invalid) { | |
| 1206 | − POST_SEM (); | |
| 1207 | − bound_error("freeing invalid region"); | |
| 1208 | − return; | |
| 1209 | + if (no_checking == 0) { | |
| 1210 | + WAIT_SEM (); | |
| 1211 | + INCR_COUNT(bound_free_count); | |
| 1212 | + tree = splay (addr, tree); | |
| 1213 | + if (tree->start == addr) { | |
| 1214 | + if (tree->is_invalid) { | |
| 1215 | + POST_SEM (); | |
| 1216 | + bound_error("freeing invalid region"); | |
| 1217 | + return; | |
| 1218 | + } | |
| 1219 | + tree->is_invalid = 1; | |
| 1220 | + memset (ptr, 0x5a, tree->size); | |
| 1221 | + p = free_reuse_list[free_reuse_index]; | |
| 1222 | + free_reuse_list[free_reuse_index] = ptr; | |
| 1223 | + free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE; | |
| 1224 | + if (p) | |
| 1225 | + tree = splay_delete((size_t)p, tree); | |
| 1226 | + ptr = p; | |
| 1209 | 1227 | } |
| 1210 | − tree->is_invalid = 1; | |
| 1211 | − memset (ptr, 0x5a, tree->size); | |
| 1212 | − p = free_reuse_list[free_reuse_index]; | |
| 1213 | − free_reuse_list[free_reuse_index] = ptr; | |
| 1214 | − free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE; | |
| 1215 | − if (p) | |
| 1216 | − tree = splay_delete((size_t)p, tree); | |
| 1217 | − ptr = p; | |
| 1228 | + POST_SEM (); | |
| 1218 | 1229 | } |
| 1219 | − POST_SEM (); | |
| 1220 | 1230 | BOUND_FREE (ptr); |
| 1221 | 1231 | } |
| 1222 | 1232 | |
| @@ -1340,8 +1350,7 @@ int __bound_munmap (void *start, size_t size) · 117 unmodified lines | ||
| 1340 | 1350 | /* check that (p ... p + size - 1) lies inside 'p' region, if any */ |
| 1341 | 1351 | static void __bound_check(const void *p, size_t size, const char *function) |
| 1342 | 1352 | { |
| 1343 | − if (no_checking == 0 && size != 0 && | |
| 1344 | − __bound_ptr_add((void *)p, size) == INVALID_POINTER) { | |
| 1353 | + if (size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) { | |
| 1345 | 1354 | bound_error("invalid pointer %p, size 0x%lx in %s", |
| 1346 | 1355 | p, (unsigned long)size, function); |
| 1347 | 1356 | } |
| @@ -951,34 +951,53 @@ Here are some examples of caught errors: · 950 unmodified lines | ||
| 951 | 951 | |
| 952 | 952 | Signal handlers are not compatible with bounds checking. The code |
| 953 | 953 | below can be used to protect signal handlers. |
| 954 | −The call to __bound_checking(1) will disable bounds checking in the | |
| 955 | −whole application. | |
| 954 | +The @code{__attribute__((bound_no_checking))} will prevent all bound checking | |
| 955 | +code generation. If a signal handler calls another function this | |
| 956 | +function must also use @code{__attribute__((bound_no_checking))}. | |
| 956 | 957 | |
| 957 | −The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to | |
| 958 | +The fork() function call in a multi threaded application is also a problem. | |
| 959 | +To solve this all bounds checking can be disabled by calling | |
| 960 | +@code{__bound_checking(1)}. The call to @code{__bound_checking(1)} will disable bounds | |
| 961 | +checking in the whole application. | |
| 962 | + | |
| 963 | +The @code{BOUNDS_CHECKING_OFF} and @code{BOUNDS_CHECKING_ON} can also be used to | |
| 958 | 964 | disable bounds checking for some code. This is not recommended. |
| 959 | 965 | It is better to fix the code. |
| 960 | 966 | |
| 961 | 967 | @example |
| 962 | 968 | |
| 963 | −#ifdef __BOUNDS_CHECKING_ON | |
| 969 | +#if defined(__TINYC__) && __BOUNDS_CHECKING_ON | |
| 970 | +#undef __attribute__ | |
| 964 | 971 | extern void __bound_checking (int no_check); |
| 965 | 972 | #define BOUNDS_CHECKING_OFF __bound_checking(1) |
| 966 | 973 | #define BOUNDS_CHECKING_ON __bound_checking(-1) |
| 974 | +#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking)) | |
| 967 | 975 | #else |
| 968 | 976 | #define BOUNDS_CHECKING_OFF |
| 969 | 977 | #define BOUNDS_CHECKING_ON |
| 978 | +#define BOUNDS_NO_CHECKING | |
| 970 | 979 | #endif |
| 971 | 980 | |
| 972 | −void real_signal_handler(int sig, siginfo_t *info, void *ucontext) | |
| 981 | +void signal_handler(int sig, void *info, void *ucontext) BOUNDS_NO_CHECKING | |
| 973 | 982 | @{ |
| 974 | − ... | |
| 983 | + ... signal handler code without generated bounds checking code. | |
| 975 | 984 | @} |
| 976 | 985 | |
| 977 | −void signal_handler(int sig, void *info, void *ucontext) | |
| 986 | +void run(const char *cmd) | |
| 978 | 987 | @{ |
| 979 | − BOUNDS_CHECKING_OFF; | |
| 980 | − real_signal_handler(sig, info, data); | |
| 981 | − BOUNDS_CHECKING_ON; | |
| 988 | + switch (fork()) @{ | |
| 989 | + case 0: | |
| 990 | + BOUNDS_CHECKING_OFF; | |
| 991 | + ... | |
| 992 | + exec... | |
| 993 | + exit(1); | |
| 994 | + case -1: | |
| 995 | + ... | |
| 996 | + break; | |
| 997 | + default: | |
| 998 | + ... | |
| 999 | + break; | |
| 1000 | + @} | |
| 982 | 1001 | @} |
| 983 | 1002 | |
| 984 | 1003 | @end example |
| @@ -505,7 +505,8 @@ struct FuncAttr { · 504 unmodified lines | ||
| 505 | 505 | func_dtor : 1, /* attribute((destructor)) */ |
| 506 | 506 | func_args : 8, /* PE __stdcall args */ |
| 507 | 507 | func_alwinl : 1, /* always_inline */ |
| 508 | − xxxx :15; | |
| 508 | + no_bcheck : 1, /* no bound checking */ | |
| 509 | + xxxx :14; | |
| 509 | 510 | }; |
| 510 | 511 | |
| 511 | 512 | /* symbol management */ |
| @@ -1501,6 +1501,8 @@ static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1) · 1500 unmodified lines | ||
| 1501 | 1501 | fa->func_ctor = 1; |
| 1502 | 1502 | if (fa1->func_dtor) |
| 1503 | 1503 | fa->func_dtor = 1; |
| 1504 | + if (fa1->no_bcheck) | |
| 1505 | + fa->no_bcheck = 1; | |
| 1504 | 1506 | } |
| 1505 | 1507 | |
| 1506 | 1508 | /* Merge attributes. */ |
| @@ -4122,6 +4124,10 @@ redo: · 2615 unmodified lines | ||
| 4122 | 4124 | case TOK_ALWAYS_INLINE2: |
| 4123 | 4125 | ad->f.func_alwinl = 1; |
| 4124 | 4126 | break; |
| 4127 | + case TOK_NO_BOUND_CHECK1: | |
| 4128 | + case TOK_NO_BOUND_CHECK2: | |
| 4129 | + ad->f.no_bcheck = 1; | |
| 4130 | + break; | |
| 4125 | 4131 | case TOK_SECTION1: |
| 4126 | 4132 | case TOK_SECTION2: |
| 4127 | 4133 | skip('('); |
| @@ -8079,10 +8085,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 3951 unmodified lines | ||
| 8079 | 8085 | 'cur_text_section' */ |
| 8080 | 8086 | static void gen_function(Sym *sym) |
| 8081 | 8087 | { |
| 8088 | + unsigned char save_bcheck = tcc_state->do_bounds_check; | |
| 8082 | 8089 | /* Initialize VLA state */ |
| 8083 | 8090 | struct scope f = { 0 }; |
| 8084 | 8091 | cur_scope = root_scope = &f; |
| 8085 | 8092 | |
| 8093 | + if (sym->type.ref->f.no_bcheck) | |
| 8094 | + tcc_state->do_bounds_check = 0; | |
| 8095 | + | |
| 8086 | 8096 | nocode_wanted = 0; |
| 8087 | 8097 | ind = cur_text_section->data_offset; |
| 8088 | 8098 | if (sym->a.aligned) { |
| @@ -8135,6 +8145,7 @@ static void gen_function(Sym *sym) · 46 unmodified lines | ||
| 8135 | 8145 | check_vstack(); |
| 8136 | 8146 | /* do this after funcend debug info */ |
| 8137 | 8147 | next(); |
| 8148 | + tcc_state->do_bounds_check = save_bcheck; | |
| 8138 | 8149 | } |
| 8139 | 8150 | |
| 8140 | 8151 | static void gen_inline_functions(TCCState *s) |
| @@ -134,6 +134,8 @@ · 133 unmodified lines | ||
| 134 | 134 | DEF(TOK_DESTRUCTOR2, "__destructor__") |
| 135 | 135 | DEF(TOK_ALWAYS_INLINE1, "always_inline") |
| 136 | 136 | DEF(TOK_ALWAYS_INLINE2, "__always_inline__") |
| 137 | + DEF(TOK_NO_BOUND_CHECK1, "bound_no_checking") | |
| 138 | + DEF(TOK_NO_BOUND_CHECK2, "__bound_no_checking__") | |
| 137 | 139 | |
| 138 | 140 | DEF(TOK_MODE, "__mode__") |
| 139 | 141 | DEF(TOK_MODE_QI, "__QI__") |
| @@ -8,7 +8,7 @@ int foo (struct S *a, struct S *b) · 7 unmodified lines | ||
| 8 | 8 | return 0; |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | −void *memmove(void*,void*,long); | |
| 11 | +void *memmove(void*,const void*,__SIZE_TYPE__); | |
| 12 | 12 | void foo2 (struct S *a, struct S *b) |
| 13 | 13 | { |
| 14 | 14 | memmove(a, b, sizeof *a); |
| @@ -8,12 +8,25 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <errno.h> |
| 9 | 9 | #include <setjmp.h> |
| 10 | 10 | |
| 11 | +/* See tcc-doc.info */ | |
| 12 | +#if defined(__TINYC__) && __BOUNDS_CHECKING_ON | |
| 13 | +#undef __attribute__ | |
| 14 | +extern void __bound_checking (int no_check); | |
| 15 | +#define BOUNDS_CHECKING_OFF __bound_checking(1) | |
| 16 | +#define BOUNDS_CHECKING_ON __bound_checking(-1) | |
| 17 | +#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking)) | |
| 18 | +#else | |
| 19 | +#define BOUNDS_CHECKING_OFF | |
| 20 | +#define BOUNDS_CHECKING_ON | |
| 21 | +#define BOUNDS_NO_CHECKING | |
| 22 | +#endif | |
| 23 | + | |
| 11 | 24 | static volatile int run = 1; |
| 12 | 25 | static int dummy[10]; |
| 13 | 26 | static sem_t sem; |
| 14 | 27 | |
| 15 | 28 | static void |
| 16 | −add (void) | |
| 29 | +add (void) BOUNDS_NO_CHECKING | |
| 17 | 30 | { |
| 18 | 31 | int i; |
| 19 | 32 | |
| @@ -41,29 +54,12 @@ do_signal (void *unused) · 21 unmodified lines | ||
| 41 | 54 | return NULL; |
| 42 | 55 | } |
| 43 | 56 | |
| 44 | −/* See tcc-doc.info */ | |
| 45 | −#ifdef __BOUNDS_CHECKING_ON | |
| 46 | −extern void __bound_checking (int no_check); | |
| 47 | −#define BOUNDS_CHECKING_OFF __bound_checking(1) | |
| 48 | −#define BOUNDS_CHECKING_ON __bound_checking(-1) | |
| 49 | −#else | |
| 50 | −#define BOUNDS_CHECKING_OFF | |
| 51 | −#define BOUNDS_CHECKING_ON | |
| 52 | −#endif | |
| 53 | − | |
| 54 | −static void real_signal_handler(int sig) | |
| 57 | +static void signal_handler(int sig) BOUNDS_NO_CHECKING | |
| 55 | 58 | { |
| 56 | 59 | add(); |
| 57 | 60 | sem_post (&sem); |
| 58 | 61 | } |
| 59 | 62 | |
| 60 | −static void signal_handler(int sig) | |
| 61 | −{ | |
| 62 | − BOUNDS_CHECKING_OFF; | |
| 63 | − real_signal_handler(sig); | |
| 64 | − BOUNDS_CHECKING_ON; | |
| 65 | −} | |
| 66 | − | |
| 67 | 63 | int |
| 68 | 64 | main (void) |
| 69 | 65 | { |