The incr_offset offset code was not working with bounds checking. So I reverted part of tccgen.c. See new test code 132. Also added some debugging code that prints location of bounds checking calls. Needed this to find the problem. See lib/bcheck.c, lib/bt-dll.c, lib/bt-exe.c, lib/bt-log.c, tccrun.c
Unified · Split
| @@ -41,7 +41,7 @@ · 40 unmodified lines | |||
| 41 | #define BOUND_STATISTIC (1) | 41 | #define BOUND_STATISTIC (1) |
| 42 | 42 | ||
| 43 | #if BOUND_DEBUG | 43 | #if BOUND_DEBUG |
| 44 | #define dprintf(a...) if (print_calls) fprintf(a) | 44 | #define dprintf(a...) if (print_calls) { bounds_loc; fprintf(a); } |
| 45 | #else | 45 | #else |
| 46 | #define dprintf(a...) | 46 | #define dprintf(a...) |
| 47 | #endif | 47 | #endif |
| @@ -446,6 +446,7 @@ static unsigned long long bound_splay_delete; · 398 unmodified lines | |||
| 446 | #endif | 446 | #endif |
| 447 | 447 | ||
| 448 | int tcc_backtrace(const char *fmt, ...); | 448 | int tcc_backtrace(const char *fmt, ...); |
| 449 | void tcc_location(const char *fmt); | ||
| 449 | 450 | ||
| 450 | /* print a bound error message */ | 451 | /* print a bound error message */ |
| 451 | #define bound_warning(...) \ | 452 | #define bound_warning(...) \ |
| @@ -462,6 +463,13 @@ int tcc_backtrace(const char *fmt, ...); · 10 unmodified lines | |||
| 462 | exit(255); \ | 463 | exit(255); \ |
| 463 | } while (0) | 464 | } while (0) |
| 464 | 465 | ||
| 466 | #define bounds_loc \ | ||
| 467 | do { \ | ||
| 468 | WAIT_SEM (); \ | ||
| 469 | tcc_location("^bcheck.c^"); \ | ||
| 470 | POST_SEM (); \ | ||
| 471 | } while (0) | ||
| 472 | |||
| 465 | static void bound_alloc_error(const char *s) | 473 | static void bound_alloc_error(const char *s) |
| 466 | { | 474 | { |
| 467 | fprintf(stderr,"FATAL: %s\n",s); | 475 | fprintf(stderr,"FATAL: %s\n",s); |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | REDIR(__bt_init) \ | 8 | REDIR(__bt_init) \ |
| 9 | REDIR(__bt_exit) \ | 9 | REDIR(__bt_exit) \ |
| 10 | REDIR(tcc_backtrace) \ | 10 | REDIR(tcc_backtrace) \ |
| 11 | REDIR(tcc_location) \ | ||
| 11 | \ | 12 | \ |
| 12 | REDIR(__bound_ptr_add) \ | 13 | REDIR(__bound_ptr_add) \ |
| 13 | REDIR(__bound_ptr_indir1) \ | 14 | REDIR(__bound_ptr_indir1) \ |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | #include "../tccrun.c" | 8 | #include "../tccrun.c" |
| 9 | 9 | ||
| 10 | int (*__rt_error)(void*, void*, const char *, va_list); | 10 | int (*__rt_error)(void*, void*, const char *, va_list); |
| 11 | void (*__rt_location)(void*, void*, const char *); | ||
| 11 | __attribute__((weak)) void __bound_checking_lock(void); | 12 | __attribute__((weak)) void __bound_checking_lock(void); |
| 12 | __attribute__((weak)) void __bound_checking_unlock(void); | 13 | __attribute__((weak)) void __bound_checking_unlock(void); |
| 13 | 14 | ||
| @@ -33,6 +34,7 @@ void __bt_init(rt_context *p, int num_callers) · 19 unmodified lines | |||
| 33 | rc->num_callers = num_callers - 1; | 34 | rc->num_callers = num_callers - 1; |
| 34 | rc->top_func = main; | 35 | rc->top_func = main; |
| 35 | __rt_error = _rt_error; | 36 | __rt_error = _rt_error; |
| 37 | __rt_location = _rt_location; | ||
| 36 | set_exception_handler(); | 38 | set_exception_handler(); |
| 37 | } else { | 39 | } else { |
| 38 | p->next = rc->next, rc->next = p; | 40 | p->next = rc->next, rc->next = p; |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | #include <string.h> | 6 | #include <string.h> |
| 7 | 7 | ||
| 8 | int (*__rt_error)(void*, void*, const char *, va_list); | 8 | int (*__rt_error)(void*, void*, const char *, va_list); |
| 9 | void (*__rt_location)(void*, void*, const char *); | ||
| 9 | 10 | ||
| 10 | #ifdef _WIN32 | 11 | #ifdef _WIN32 |
| 11 | # define DLL_EXPORT __declspec(dllexport) | 12 | # define DLL_EXPORT __declspec(dllexport) |
| @@ -42,6 +43,15 @@ DLL_EXPORT int tcc_backtrace(const char *fmt, ...) · 30 unmodified lines | |||
| 42 | return ret; | 43 | return ret; |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 46 | DLL_EXPORT void tcc_location(const char *fmt) | ||
| 47 | { | ||
| 48 | if (__rt_location) { | ||
| 49 | void *fp = __builtin_frame_address(1); | ||
| 50 | void *ip = __builtin_return_address(0); | ||
| 51 | __rt_location(fp, ip, fmt); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 45 | #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) | 55 | #if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__) |
| 46 | #pragma GCC diagnostic pop | 56 | #pragma GCC diagnostic pop |
| 47 | #endif | 57 | #endif |
| @@ -6010,6 +6010,7 @@ special_math_val: · 6009 unmodified lines | |||
| 6010 | indir(); | 6010 | indir(); |
| 6011 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); | 6011 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); |
| 6012 | test_lvalue(); | 6012 | test_lvalue(); |
| 6013 | gaddrof(); | ||
| 6013 | /* expect pointer on structure */ | 6014 | /* expect pointer on structure */ |
| 6014 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) | 6015 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
| 6015 | expect("struct or union"); | 6016 | expect("struct or union"); |
| @@ -6020,15 +6021,16 @@ special_math_val: · 4 unmodified lines | |||
| 6020 | expect("field name"); | 6021 | expect("field name"); |
| 6021 | s = find_field(&vtop->type, tok, &cumofs); | 6022 | s = find_field(&vtop->type, tok, &cumofs); |
| 6022 | /* add field offset to pointer */ | 6023 | /* add field offset to pointer */ |
| 6023 | incr_offset(cumofs); | 6024 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
| 6025 | vpushi(cumofs); | ||
| 6026 | gen_op('+'); | ||
| 6024 | /* change type to field type, and set to lvalue */ | 6027 | /* change type to field type, and set to lvalue */ |
| 6025 | vtop->type = s->type; | 6028 | vtop->type = s->type; |
| 6026 | vtop->type.t |= qualifiers; | 6029 | vtop->type.t |= qualifiers; |
| 6027 | /* an array is never an lvalue */ | 6030 | /* an array is never an lvalue */ |
| 6028 | if (vtop->type.t & VT_ARRAY) { | 6031 | if (!(vtop->type.t & VT_ARRAY)) { |
| 6029 | vtop->r &= ~VT_LVAL; | 6032 | vtop->r |= VT_LVAL; |
| 6030 | #ifdef CONFIG_TCC_BCHECK | 6033 | #ifdef CONFIG_TCC_BCHECK |
| 6031 | } else { | ||
| 6032 | /* if bound checking, the referenced pointer must be checked */ | 6034 | /* if bound checking, the referenced pointer must be checked */ |
| 6033 | if (tcc_state->do_bounds_check) | 6035 | if (tcc_state->do_bounds_check) |
| 6034 | vtop->r |= VT_MUSTBOUND; | 6036 | vtop->r |= VT_MUSTBOUND; |
| @@ -53,6 +53,7 @@ typedef struct rt_context · 52 unmodified lines | |||
| 53 | static rt_context g_rtctxt; | 53 | static rt_context g_rtctxt; |
| 54 | static void set_exception_handler(void); | 54 | static void set_exception_handler(void); |
| 55 | static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); | 55 | static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); |
| 56 | static void _rt_location(void *fp, void *ip, const char *fmt); | ||
| 56 | static void rt_exit(int code); | 57 | static void rt_exit(int code); |
| 57 | #endif /* CONFIG_TCC_BACKTRACE */ | 58 | #endif /* CONFIG_TCC_BACKTRACE */ |
| 58 | 59 | ||
| @@ -274,6 +275,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 215 unmodified lines | |||
| 274 | rc->do_jmp = 1; | 275 | rc->do_jmp = 1; |
| 275 | if ((p = tcc_get_symbol(s1, "__rt_error"))) | 276 | if ((p = tcc_get_symbol(s1, "__rt_error"))) |
| 276 | *(void**)p = _rt_error; | 277 | *(void**)p = _rt_error; |
| 278 | if ((p = tcc_get_symbol(s1, "__rt_location"))) | ||
| 279 | *(void**)p = _rt_location; | ||
| 277 | #ifdef CONFIG_TCC_BCHECK | 280 | #ifdef CONFIG_TCC_BCHECK |
| 278 | if (s1->do_bounds_check) { | 281 | if (s1->do_bounds_check) { |
| 279 | rc->bounds_start = (void*)bounds_section->sh_addr; | 282 | rc->bounds_start = (void*)bounds_section->sh_addr; |
| @@ -1089,6 +1092,41 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap) · 809 unmodified lines | |||
| 1089 | return 0; | 1092 | return 0; |
| 1090 | } | 1093 | } |
| 1091 | 1094 | ||
| 1095 | static void _rt_location(void *fp, void *ip, const char *fmt) | ||
| 1096 | { | ||
| 1097 | rt_context *rc = &g_rtctxt; | ||
| 1098 | addr_t pc = 0; | ||
| 1099 | char skip[100]; | ||
| 1100 | int i, ret; | ||
| 1101 | const char *a, *b; | ||
| 1102 | |||
| 1103 | rc->fp = (addr_t)fp; | ||
| 1104 | rc->ip = (addr_t)ip; | ||
| 1105 | |||
| 1106 | skip[0] = 0; | ||
| 1107 | /* If fmt is like "^file.c^..." then skip calls from 'file.c' */ | ||
| 1108 | if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) | ||
| 1109 | memcpy(skip, a, b - a), skip[b - a] = 0; | ||
| 1110 | |||
| 1111 | for (i = 0; ; i++) { | ||
| 1112 | ret = rt_get_caller_pc(&pc, rc, i); | ||
| 1113 | a = ""; | ||
| 1114 | if (ret != -1) { | ||
| 1115 | if (rc->dwarf) | ||
| 1116 | pc = rt_printline_dwarf(rc, pc, "at", skip); | ||
| 1117 | else | ||
| 1118 | pc = rt_printline(rc, pc, "at", skip); | ||
| 1119 | if (pc == (addr_t)-1) | ||
| 1120 | continue; | ||
| 1121 | a = ": "; | ||
| 1122 | } | ||
| 1123 | rt_printf(a); | ||
| 1124 | break; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | rc->ip = rc->fp = 0; | ||
| 1128 | } | ||
| 1129 | |||
| 1092 | /* emit a run time error at position 'pc' */ | 1130 | /* emit a run time error at position 'pc' */ |
| 1093 | static int rt_error(const char *fmt, ...) | 1131 | static int rt_error(const char *fmt, ...) |
| 1094 | { | 1132 | { |
| @@ -0,0 +1,29 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <float.h> | ||
| 3 | |||
| 4 | union ieee_double_extract | ||
| 5 | { | ||
| 6 | struct { | ||
| 7 | unsigned int manl:32; | ||
| 8 | unsigned int manh:20; | ||
| 9 | unsigned int exp:11; | ||
| 10 | unsigned int sig:1; | ||
| 11 | } s; | ||
| 12 | double d; | ||
| 13 | }; | ||
| 14 | |||
| 15 | double scale(double d) | ||
| 16 | { | ||
| 17 | union ieee_double_extract x; | ||
| 18 | |||
| 19 | x.d = d; | ||
| 20 | x.d *= 1000; | ||
| 21 | return x.d; | ||
| 22 | } | ||
| 23 | |||
| 24 | int | ||
| 25 | main(void) | ||
| 26 | { | ||
| 27 | printf("%g\n", scale(42)); | ||
| 28 | return 0; | ||
| 29 | } | ||
| @@ -0,0 +1 @@ | |||
| 1 | 42000 | ||