mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-26 03:50:07 +08:00
bcheck: remove static (compile-time) control
Providing both run-time and compile-time control for bounds checking as an user interface appears unnecessary and confusing. Also: - replace 'bound_...' by 'bounds_...' for consistency - tcc-doc: put related info into one place and cleanup The __bounds_checking(x) function is still missing explanation. (I.e. what happens if the accumulated value drops below zero.)
This commit is contained in:
parent
a34a9775ba
commit
f9870f7860
@ -198,7 +198,7 @@ static Tree * splay_delete(size_t addr, Tree *t);
|
||||
void splay_printtree(Tree * t, int d);
|
||||
|
||||
/* external interface */
|
||||
void __bound_checking (int no_check);
|
||||
void __bounds_checking (int no_check);
|
||||
void __bound_never_fatal (int no_check);
|
||||
DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
|
||||
DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
|
||||
@ -359,7 +359,7 @@ static void fetch_and_add(int* variable, int value)
|
||||
}
|
||||
|
||||
/* enable/disable checking. This can be used in signal handlers. */
|
||||
void __bound_checking (int no_check)
|
||||
void __bounds_checking (int no_check)
|
||||
{
|
||||
fetch_and_add (&no_checking, no_check);
|
||||
}
|
||||
|
104
tcc-doc.texi
104
tcc-doc.texi
@ -351,26 +351,8 @@ invalid pointer} instead of the laconic @code{Segmentation
|
||||
fault}.
|
||||
|
||||
@item -b
|
||||
Generate additional support code to check
|
||||
memory allocations and array/pointer bounds. @option{-g} is implied. Note
|
||||
that the generated code is slower and bigger in this case.
|
||||
The bound checking code is not included in shared libraries. The main executable should always be compiled with the @option{-b}.
|
||||
|
||||
There are five environment variables that can be used:
|
||||
@table @option
|
||||
@item TCC_BOUNDS_WARN_POINTER_ADD
|
||||
Print warning when pointer add creates an illegal pointer.
|
||||
@item TCC_BOUNDS_PRINT_CALLS
|
||||
Print bound checking calls. Can be used for debugging.
|
||||
@item TCC_BOUNDS_PRINT_HEAP
|
||||
Print heap objects that are not freed at exit of program.
|
||||
@item TCC_BOUNDS_PRINT_STATISTIC
|
||||
Print statistic information at exit of program.
|
||||
@item TCC_BOUNDS_NEVER_FATAL
|
||||
Try to continue in case of a bound checking error.
|
||||
@end table
|
||||
|
||||
Note: @option{-b} is only available on i386 (linux and windows), x86_64 (linux and windows), arm, arm64 and riscv64 for the moment.
|
||||
Generate additional support code to check memory allocations and array/pointer
|
||||
bounds (@pxref{Bounds}). @option{-g} is implied.
|
||||
|
||||
@item -bt[N]
|
||||
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
|
||||
@ -686,8 +668,6 @@ are supported.
|
||||
@item Binary digits can be entered (@code{0b101} instead of
|
||||
@code{5}).
|
||||
|
||||
@item @code{__BOUNDS_CHECKING_ON} is defined if bound checking is activated.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node asm
|
||||
@ -881,16 +861,7 @@ GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
|
||||
@cindex bound checks
|
||||
@cindex memory checks
|
||||
|
||||
This feature is activated with the @option{-b} (@pxref{Invoke}).
|
||||
|
||||
Note that pointer size is @emph{unchanged} and that code generated
|
||||
with bound checks is @emph{fully compatible} with unchecked
|
||||
code. When a pointer comes from unchecked code, it is assumed to be
|
||||
valid. Even very obscure C code with casts should work correctly.
|
||||
|
||||
For more information about the ideas behind this method, see
|
||||
@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}.
|
||||
|
||||
This feature is activated with the @option{-b} option (@pxref{Invoke}).
|
||||
Here are some examples of caught errors:
|
||||
|
||||
@table @asis
|
||||
@ -946,41 +917,58 @@ Here are some examples of caught errors:
|
||||
free(tab);
|
||||
@}
|
||||
@end example
|
||||
|
||||
@end table
|
||||
|
||||
Signal handlers are not compatible with bounds checking. The code
|
||||
below can be used to protect signal handlers.
|
||||
The @code{__attribute__((bound_no_checking))} will prevent all bound checking
|
||||
code generation. If a signal handler calls another function this
|
||||
function must also use @code{__attribute__((bound_no_checking))}.
|
||||
TCC defines @code{__BOUNDS_CHECKING_ON} if activated.
|
||||
|
||||
The fork() function call in a multi threaded application is also a problem.
|
||||
To solve this all bounds checking can be disabled by calling
|
||||
@code{__bound_checking(1)}. The call to @code{__bound_checking(1)} will disable bounds
|
||||
checking in the whole application.
|
||||
There are five environment variables that can be used to control the behavior:
|
||||
@itemize
|
||||
@item TCC_BOUNDS_WARN_POINTER_ADD
|
||||
- Print warning when pointer add creates an illegal pointer.
|
||||
@item TCC_BOUNDS_PRINT_CALLS
|
||||
- Print bound checking calls. Can be used for debugging.
|
||||
@item TCC_BOUNDS_PRINT_HEAP
|
||||
- Print heap objects that are not freed at exit of program.
|
||||
@item TCC_BOUNDS_PRINT_STATISTIC
|
||||
- Print statistic information at exit of program.
|
||||
@item TCC_BOUNDS_NEVER_FATAL
|
||||
- Try to continue in case of a bound checking error.
|
||||
@end itemize
|
||||
|
||||
The @code{BOUNDS_CHECKING_OFF} and @code{BOUNDS_CHECKING_ON} can also be used to
|
||||
disable bounds checking for some code. This is not recommended.
|
||||
It is better to fix the code.
|
||||
Also, a function @code{__bounds_checking(x)} can be used to turn off/on bounds
|
||||
checking from usercode (see below).
|
||||
|
||||
Notes:
|
||||
@itemize
|
||||
@item Only available on i386 (linux and windows), x86_64 (linux and windows),
|
||||
arm, arm64 and riscv64 for the moment.
|
||||
@item The generated code is slower and bigger.
|
||||
@item The bound checking code is not included in shared libraries. The main
|
||||
executable should always be compiled with the @option{-b}.
|
||||
@item Pointer size is @emph{unchanged} and code generated with bound checks is
|
||||
@emph{fully compatible} with unchecked code. When a pointer comes from
|
||||
unchecked code, it is assumed to be valid. Even very obscure C code with
|
||||
casts should work correctly.
|
||||
@item Signal handlers are not compatible with bounds checking. The fork()
|
||||
function call in a multi threaded application is also a problem.
|
||||
The code below can be used to solve this.
|
||||
@end itemize
|
||||
|
||||
@example
|
||||
|
||||
#if defined(__TINYC__) && __BOUNDS_CHECKING_ON
|
||||
#undef __attribute__
|
||||
extern void __bound_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bound_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bound_checking(-1)
|
||||
#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking))
|
||||
#ifdef __BOUNDS_CHECKING_ON
|
||||
extern void __bounds_checking (int x);
|
||||
# define BOUNDS_CHECKING_OFF __bounds_checking(1)
|
||||
# define BOUNDS_CHECKING_ON __bounds_checking(-1)
|
||||
#else
|
||||
#define BOUNDS_CHECKING_OFF
|
||||
#define BOUNDS_CHECKING_ON
|
||||
#define BOUNDS_NO_CHECKING
|
||||
# define BOUNDS_CHECKING_OFF
|
||||
# define BOUNDS_CHECKING_ON
|
||||
#endif
|
||||
|
||||
void signal_handler(int sig, void *info, void *ucontext) BOUNDS_NO_CHECKING
|
||||
void signal_handler(int sig, void *info, void *ucontext)
|
||||
@{
|
||||
BOUNDS_CHECKING_OFF;
|
||||
... signal handler code without generated bounds checking code.
|
||||
BOUNDS_CHECKING_ON;
|
||||
@}
|
||||
|
||||
void run(const char *cmd)
|
||||
@ -999,9 +987,11 @@ void run(const char *cmd)
|
||||
break;
|
||||
@}
|
||||
@}
|
||||
|
||||
@end example
|
||||
|
||||
For more information about the ideas behind this method, see
|
||||
@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}.
|
||||
|
||||
@node Libtcc
|
||||
@chapter The @code{libtcc} library
|
||||
|
||||
|
3
tcc.h
3
tcc.h
@ -505,8 +505,7 @@ struct FuncAttr {
|
||||
func_dtor : 1, /* attribute((destructor)) */
|
||||
func_args : 8, /* PE __stdcall args */
|
||||
func_alwinl : 1, /* always_inline */
|
||||
no_bcheck : 1, /* no bound checking */
|
||||
xxxx :14;
|
||||
xxxx : 15;
|
||||
};
|
||||
|
||||
/* symbol management */
|
||||
|
38
tccgen.c
38
tccgen.c
@ -1501,8 +1501,6 @@ static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1)
|
||||
fa->func_ctor = 1;
|
||||
if (fa1->func_dtor)
|
||||
fa->func_dtor = 1;
|
||||
if (fa1->no_bcheck)
|
||||
fa->no_bcheck = 1;
|
||||
}
|
||||
|
||||
/* Merge attributes. */
|
||||
@ -4129,12 +4127,6 @@ redo:
|
||||
case TOK_ALWAYS_INLINE2:
|
||||
ad->f.func_alwinl = 1;
|
||||
break;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
case TOK_NO_BOUND_CHECK1:
|
||||
case TOK_NO_BOUND_CHECK2:
|
||||
ad->f.no_bcheck = 1;
|
||||
break;
|
||||
#endif
|
||||
case TOK_SECTION1:
|
||||
case TOK_SECTION2:
|
||||
skip('(');
|
||||
@ -5967,26 +5959,6 @@ special_math_val:
|
||||
if (t < TOK_UIDENT)
|
||||
expect("identifier");
|
||||
s = sym_find(t);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* HACK to undo alias definition in tccpp.c
|
||||
if function has no bound checking */
|
||||
if (tcc_state->do_bounds_check == 0 && s &&
|
||||
(s->type.t & VT_BTYPE) == VT_FUNC && (s->asm_label & SYM_FIELD)) {
|
||||
const char *name = get_tok_str(s->asm_label & ~SYM_FIELD, NULL);
|
||||
|
||||
if (name && strncmp (name, "__bound_", strlen("__bound_")) == 0) {
|
||||
char str[100];
|
||||
int v = s->v;
|
||||
|
||||
sprintf (str, "!%s", name); /* illegal name */
|
||||
t = tok_alloc(str, strlen(str))->tok;
|
||||
s = sym_find(t);
|
||||
if (s == NULL)
|
||||
s = external_global_sym(t, &func_old_type);
|
||||
s->asm_label = v | SYM_FIELD; /* use old name as alias */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!s || IS_ASM_SYM(s)) {
|
||||
const char *name = get_tok_str(t, NULL);
|
||||
if (tok != '(')
|
||||
@ -8122,14 +8094,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
'cur_text_section' */
|
||||
static void gen_function(Sym *sym)
|
||||
{
|
||||
/* Initialize VLA state */
|
||||
struct scope f = { 0 };
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
unsigned char save_bcheck = tcc_state->do_bounds_check;
|
||||
|
||||
if (sym->type.ref->f.no_bcheck)
|
||||
tcc_state->do_bounds_check = 0;
|
||||
#endif
|
||||
cur_scope = root_scope = &f;
|
||||
nocode_wanted = 0;
|
||||
ind = cur_text_section->data_offset;
|
||||
@ -8183,9 +8148,6 @@ static void gen_function(Sym *sym)
|
||||
check_vstack();
|
||||
/* do this after funcend debug info */
|
||||
next();
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
tcc_state->do_bounds_check = save_bcheck;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gen_inline_functions(TCCState *s)
|
||||
|
4
tcctok.h
4
tcctok.h
@ -134,10 +134,6 @@
|
||||
DEF(TOK_DESTRUCTOR2, "__destructor__")
|
||||
DEF(TOK_ALWAYS_INLINE1, "always_inline")
|
||||
DEF(TOK_ALWAYS_INLINE2, "__always_inline__")
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
DEF(TOK_NO_BOUND_CHECK1, "bound_no_checking")
|
||||
DEF(TOK_NO_BOUND_CHECK2, "__bound_no_checking__")
|
||||
#endif
|
||||
|
||||
DEF(TOK_MODE, "__mode__")
|
||||
DEF(TOK_MODE_QI, "__QI__")
|
||||
|
@ -11,14 +11,12 @@
|
||||
/* See tcc-doc.info */
|
||||
#if defined(__TINYC__) && __BOUNDS_CHECKING_ON
|
||||
#undef __attribute__
|
||||
extern void __bound_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bound_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bound_checking(-1)
|
||||
#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking))
|
||||
extern void __bounds_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bounds_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bounds_checking(-1)
|
||||
#else
|
||||
#define BOUNDS_CHECKING_OFF
|
||||
#define BOUNDS_CHECKING_ON
|
||||
#define BOUNDS_NO_CHECKING
|
||||
#endif
|
||||
|
||||
static volatile int run = 1;
|
||||
@ -26,15 +24,16 @@ static int dummy[10];
|
||||
static sem_t sem;
|
||||
|
||||
static void
|
||||
add (void) BOUNDS_NO_CHECKING
|
||||
add (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
BOUNDS_CHECKING_OFF;
|
||||
for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) {
|
||||
dummy[i]++;
|
||||
}
|
||||
/* Should not be translated into __bound_memset */
|
||||
memset (&dummy[0], 0, sizeof(dummy));
|
||||
BOUNDS_CHECKING_ON;
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -56,10 +55,12 @@ do_signal (void *unused)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void signal_handler(int sig) BOUNDS_NO_CHECKING
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
BOUNDS_CHECKING_OFF;
|
||||
add();
|
||||
sem_post (&sem);
|
||||
BOUNDS_CHECKING_ON;
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user