Browse Source

Update bound checking code.

Add __attribute__((constructor)) to __bounds_init.
- remove tcc_add_bcheck from i386-link.c and x86_64-link.c
- add simplified tcc_add_bcheck to tccelf.c
- Update tccrun.c to call constructor/destructor.
Set dynsym sh_info to number of local symbols in tccelf.c
Reduce stack size when bounds checking is enabled.
Added variable TCC_LIBBCHECK for windows support.
Add signal stack to detect stack overflow.
Add all & parameters in lbound_section and remove them if not used.
Close fd in tcc_relocate in tccrun.c
Fix section type constructor/destructor in tccelf.c
Add check code in tests/boundtest.c for mem/str functions.
Remove -ba from documentation.
Add bounds check signal info in documentation.

bcheck.c:
- Fix initial_pool alignment.
. Fix printf statements.
. Add prototypes for all external interface functions.
- Add TCC_BOUNDS_WARN_POINTER_ADD environment variable.
. Add ctype and errno data.
- Fix alloca when multithreading is used.
- Add lock for __bound_checking and __bound_never_fatal.
- Catch pthread_create and use locks when called.
- Detect in loaded in shared lib and use locks when found
- Use spin locks instead of semaphore locks.
- Make spin locked code as small as possible.
- Fix mem/str functions checking.
- Fix overlap checking mem/str functions.
mob/mob.Elronnd
herman ten brugge 4 years ago
parent
commit
3877618785
  1. 9
      i386-gen.c
  2. 75
      i386-link.c
  3. 1126
      lib/bcheck.c
  4. 43
      tcc-doc.texi
  5. 8
      tcc.h
  6. 33
      tccelf.c
  7. 140
      tccgen.c
  8. 2
      tccpe.c
  9. 66
      tccrun.c
  10. 2
      tests/Makefile
  11. 197
      tests/boundtest.c
  12. 17
      x86_64-gen.c
  13. 85
      x86_64-link.c

9
i386-gen.c

@ -95,7 +95,6 @@ ST_DATA const int reg_classes[NB_REGS] = {
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
#endif
@ -402,8 +401,10 @@ ST_FUNC void gfunc_call(int nb_args)
Sym *func_sym;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) {
save_temp_local (nb_args);
gbound_args(nb_args);
}
#endif
args_size = 0;
@ -485,6 +486,10 @@ ST_FUNC void gfunc_call(int nb_args)
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
gadd_sp(args_size);
vtop--;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
restore_temp_local ();
#endif
}
#ifdef TCC_TARGET_PE

75
i386-link.c

@ -235,79 +235,4 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
}
}
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
addr_t *ptr;
int loc_glob;
int sym_index;
int bsym_index;
if (0 == s1->do_bounds_check)
return;
/* XXX: add an object file to do that */
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
*ptr = 0;
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
bsym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
bounds_section->sh_num, "__bounds_start");
/* pull bcheck.o from libtcc1.a */
sym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bound_init");
if (s1->output_type != TCC_OUTPUT_MEMORY) {
/* add 'call __bound_init()' in .init section */
Section *init_section = find_section(s1, ".init");
unsigned char *pinit;
#ifdef TCC_TARGET_PE
pinit = section_ptr_add(init_section, 3);
pinit[0] = 0x55; /* push %rbp */
pinit[1] = 0x89; /* mov %esp,%ebp */
pinit[2] = 0xe5;
#endif
pinit = section_ptr_add(init_section, 5);
pinit[0] = 0xe8;
write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index);
/* R_386_PC32 = R_X86_64_PC32 = 2 */
pinit = section_ptr_add(init_section, 6);
pinit[0] = 0xb8; /* mov xx,%eax */
write32le(pinit + 1, 0);
pinit[5] = 0x50; /* push %eax */
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 5, R_386_32, bsym_index);
sym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bounds_add_static_var");
pinit = section_ptr_add(init_section, 5);
pinit[0] = 0xe8;
write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index);
/* R_386_PC32 = R_X86_64_PC32 = 2 */
pinit = section_ptr_add(init_section, 3);
pinit[0] = 0x83; /* add $0x4,%esp */
pinit[1] = 0xc4;
pinit[2] = 0x04;
#ifdef TCC_TARGET_PE
{
int init_index = set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
init_section->sh_num, "__init_start");
Sym sym;
init_section->sh_flags |= SHF_EXECINSTR;
pinit = section_ptr_add(init_section, 2);
pinit[0] = 0xc9; /* leave */
pinit[1] = 0xc3; /* ret */
sym.c = init_index;
add_init_array (s1, &sym);
}
#endif
}
}
#endif
#endif /* !TARGET_DEFS_ONLY */

1126
lib/bcheck.c

File diff suppressed because it is too large

43
tcc-doc.texi

@ -356,8 +356,10 @@ 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 libaries. The main executable should always be compiled with the @option{-b}.
There are four environment variables that can be used:
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
@ -368,10 +370,7 @@ Print statistic information at exit of program.
Try to continue in case of a bound checking error.
@end table
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) when using libtcc for the moment.
@item -ba
Generate address checking tests when using @option{-b}. This will be a lot slower but finds more errors.
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
@item -bt N
Display N callers in stack traces. This is useful with @option{-g} or
@ -947,6 +946,40 @@ Here are some examples of caught errors:
@end table
Signal handlers are not compatible with bounds checking. The code
below can be used to protect signal handlers.
The call to __bound_checking(1) will disable bounds checking in the
whole application.
The BOUNDS_CHECKING_OFF and 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.
@example
#ifdef __BOUNDS_CHECKING_ON
extern void __bound_checking (int no_check);
#define BOUNDS_CHECKING_OFF __bound_checking(1)
#define BOUNDS_CHECKING_ON __bound_checking(-1)
#else
#define BOUNDS_CHECKING_OFF
#define BOUNDS_CHECKING_ON
#endif
void real_signal_handler(int sig, siginfo_t *info, void *ucontext)
@{
...
@}
void signal_handler(int sig, void *info, void *ucontext)
@{
BOUNDS_CHECKING_OFF;
real_signal_handler(sig, info, data);
BOUNDS_CHECKING_ON;
@}
@end example
@node Libtcc
@chapter The @code{libtcc} library

8
tcc.h

@ -292,6 +292,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifndef TCC_LIBTCC1
# define TCC_LIBTCC1 "libtcc1.a"
#endif
#ifndef TCC_LIBBCHECK
# define TCC_LIBBCHECK "bcheck.o"
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
@ -1375,6 +1378,9 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA const char *funcname;
#ifdef CONFIG_TCC_BCHECK
ST_DATA addr_t func_bound_offset;
#endif
ST_FUNC void tcc_debug_start(TCCState *s1);
ST_FUNC void tcc_debug_end(TCCState *s1);
@ -1440,6 +1446,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
#endif
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void gbound_args(int nb_args);
ST_FUNC void save_temp_local(int nb_args);
ST_FUNC void restore_temp_local(void);
#endif
/* ------------ tccelf.c ------------ */

33
tccelf.c

@ -85,6 +85,23 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
lbounds_section = new_section(s, ".lbounds",
SHT_PROGBITS, SHF_ALLOC);
}
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
addr_t *ptr;
if (0 == s1->do_bounds_check)
return;
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
*ptr = 0;
set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
bounds_section->sh_num, "__bounds_start");
/* pull bcheck.o from libtcc1.a */
set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bound_init");
}
#endif
ST_FUNC void tccelf_stab_new(TCCState *s)
@ -1288,7 +1305,7 @@ static int tcc_add_support(TCCState *s1, const char *filename)
}
#endif
static void add_array (const char *section, TCCState *s1, Sym *sym)
static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
{
Section *s;
unsigned char *ptr;
@ -1296,6 +1313,9 @@ static void add_array (const char *section, TCCState *s1, Sym *sym)
s = find_section(s1, section);
if (s) {
s->sh_flags |= SHF_WRITE;
#ifndef TCC_TARGET_PE
s->sh_type = sh_type;
#endif
ptr = section_ptr_add(s, PTR_SIZE);
memset (ptr, 0, PTR_SIZE);
put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
@ -1304,12 +1324,12 @@ static void add_array (const char *section, TCCState *s1, Sym *sym)
ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
{
add_array (".init_array", s1, sym);
add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
}
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
{
add_array (".fini_array", s1, sym);
add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
}
/* add tcc runtime libraries */
@ -1336,7 +1356,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
tcc_add_library_err(s1, "pthread");
tcc_add_library_err(s1, "dl");
tcc_add_support(s1, "bcheck.o");
tcc_add_support(s1, TCC_LIBBCHECK);
}
#endif
tcc_add_support(s1, TCC_LIBTCC1);
@ -2040,6 +2060,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
Section *s;
ElfW(Ehdr) ehdr;
ElfW(Shdr) shdr, *sh;
ElfW(Sym) *sym;
file_type = s1->output_type;
shnum = s1->nb_sections;
@ -2110,6 +2131,10 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
sort_syms(s1, symtab_section);
if (s1->dynsym)
for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
s1->dynsym->sh_info++;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[sec_order[i]];
if (s->sh_type != SHT_NOBITS) {

140
tccgen.c

@ -110,6 +110,16 @@ ST_DATA struct temp_local_variable {
short align;
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
short nb_temp_local_vars;
#ifdef CONFIG_TCC_BCHECK
static short call_nesting;
static char used_location[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
static int nb_bound_local_param;
struct {
unsigned long data_offset;
int v;
} *bound_local_param;
ST_DATA addr_t func_bound_offset;
#endif
static struct scope {
struct scope *prev;
@ -1383,11 +1393,6 @@ ST_FUNC void save_reg_upstack(int r, int n)
bt = VT_PTR;
sv.type.t = bt;
size = type_size(&sv.type, &align);
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
l = loc = (loc - size) & -align;
else
#endif
l = get_temp_local_var(size,align);
sv.r = VT_LOCAL | VT_LVAL;
sv.c.i = l;
@ -1496,7 +1501,11 @@ static int get_temp_local_var(int size,int align){
found=0;
for(i=0;i<nb_temp_local_vars;i++){
temp_var=&arr_temp_local_vars[i];
if(temp_var->size<size||align!=temp_var->align){
if(temp_var->size<size||align!=temp_var->align
#ifdef CONFIG_TCC_BCHECK
|| (tcc_state->do_bounds_check && used_location[i])
#endif
){
continue;
}
/*check if temp_var is free*/
@ -1596,6 +1605,50 @@ ST_FUNC void gbound_args(int nb_args)
vrott(i);
}
}
ST_FUNC void save_temp_local(int nb_args)
{
int i, j;
if (call_nesting++ == 0)
for (i = 1; i <= nb_args; ++i)
for (j = 0; j < nb_temp_local_vars; j++)
if (vtop[1 - i].c.i == arr_temp_local_vars[j].location) {
used_location[j] = 1;
break;
}
}
ST_FUNC void restore_temp_local()
{
if (--call_nesting == 0)
memset (used_location, 0, sizeof (used_location));
}
static void add_bound_param(CType *type, int size, int v, int c)
{
addr_t *bounds_ptr;
/* Add arrays/structs/unions because we always take address */
int taken = (type->t & VT_ARRAY)
|| (type->t & VT_BTYPE) == VT_STRUCT;
if (taken == 0) {
/* Add parameter to check */
nb_bound_local_param++;
bound_local_param =
tcc_realloc (bound_local_param,
nb_bound_local_param *
sizeof (*bound_local_param));
bound_local_param[nb_bound_local_param-1].data_offset =
lbounds_section->data_offset;
bound_local_param[nb_bound_local_param-1].v = v;
}
/* add local bound info */
bounds_ptr = section_ptr_add(lbounds_section,
2 * sizeof(addr_t));
bounds_ptr[0] = c;
bounds_ptr[1] = taken ? size : ~size;
}
#endif
static void incr_bf_adr(int o)
@ -3418,6 +3471,7 @@ ST_FUNC void vstore(void)
vswap();
/* source */
vtop->r &= ~VT_MUSTBOUND;
vpushv(vtop - 2);
vtop->type.t = VT_PTR;
gaddrof();
@ -5083,6 +5137,23 @@ ST_FUNC void unary(void)
if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
!(vtop->type.t & VT_ARRAY))
test_lvalue();
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && vtop->sym) {
int i;
/* Mark parameter as being used for address off */
for (i = 0; i < nb_bound_local_param; i++) {
if (bound_local_param[i].v == vtop->sym->v) {
addr_t *bounds_ptr =
(addr_t *) (lbounds_section->data +
bound_local_param[i].data_offset);
bounds_ptr[1] = ~bounds_ptr[1];
bound_local_param[i].v = 0;
break;
}
}
}
#endif
mk_pointer(&vtop->type);
gaddrof();
break;
@ -7435,8 +7506,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if ((r & VT_VALMASK) == VT_LOCAL) {
sec = NULL;
#ifdef CONFIG_TCC_BCHECK
if (bcheck && ((type->t & VT_ARRAY) ||
(type->t & VT_BTYPE) == VT_STRUCT)) {
if (bcheck && v) {
/* add padding between stack variables */
loc--;
}
#endif
@ -7444,17 +7515,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
addr = loc;
#ifdef CONFIG_TCC_BCHECK
/* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track
'&' operators, so we add only arrays/structs/unions */
if (bcheck && ((type->t & VT_ARRAY) ||
(type->t & VT_BTYPE) == VT_STRUCT)) {
addr_t *bounds_ptr;
/* add padding between regions */
if (bcheck && v) {
add_bound_param (type, size, v, addr);
/* add padding between stack variables */
loc--;
/* then add local bound info */
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = addr;
bounds_ptr[1] = size;
}
#endif
if (v) {
@ -7633,12 +7697,52 @@ static void gen_function(Sym *sym, AttributeDef *ad)
sym_push2(&local_stack, SYM_FIELD, 0, 0);
local_scope = 1; /* for function parameters */
gfunc_prolog(sym);
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check
&& sym->type.ref->f.func_type != FUNC_ELLIPSIS) {
Sym *fpar;
/* Add function arguments in case & is used */
for (fpar = sym->type.ref->next; fpar; fpar = fpar->next) {
Sym *fsym = sym_find (fpar->v & ~SYM_FIELD);
if (fsym && (fsym->r & VT_VALMASK) == VT_LOCAL) {
int align;
int size = type_size(&fsym->type, &align);
if (size > 0)
add_bound_param (&fsym->type, size, fsym->v, fsym->c);
}
}
}
#endif
local_scope = 0;
rsym = 0;
clear_temp_local_var_list();
block(0);
gsym(rsym);
nocode_wanted = 0;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check) {
addr_t o = func_bound_offset;
/* Remove parameters where address off is not used */
while (o != lbounds_section->data_offset) {
addr_t *bounds_ptr = (addr_t *) (lbounds_section->data + o);
if ((ssize_t) bounds_ptr[1] < 0) {
lbounds_section->data_offset -= 2 * sizeof (addr_t);
memmove(bounds_ptr, bounds_ptr + 2,
lbounds_section->data_offset - o);
}
else {
o += 2 * sizeof (addr_t);
}
}
tcc_free (bound_local_param);
nb_bound_local_param = 0;
bound_local_param = NULL;
}
#endif
gfunc_epilog();
cur_text_section->data_offset = ind;
/* reset local stack */

2
tccpe.c

@ -1897,7 +1897,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
const char **pp, *p;
#ifdef TCC_IS_NATIVE
if (s1->do_bounds_check)
tcc_add_support(s1, "bcheck.o");
tcc_add_support(s1, TCC_LIBBCHECK);
#endif
tcc_add_support(s1, TCC_LIBTCC1);
for (pp = libs; 0 != (p = *pp); ++pp) {

66
tccrun.c

@ -86,6 +86,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
ptr_diff = (char*)prx - (char*)ptr;
close(fd);
}
#else
ptr = tcc_malloc(size);
@ -119,6 +120,17 @@ ST_FUNC void tcc_run_free(TCCState *s1)
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
/* PE target overwrites runtime_main */
#ifndef TCC_TARGET_PE
typedef void (*init_array_func)(int, char **, char **);
typedef void (*fini_array_func)(void);
init_array_func *__init_array_start;
init_array_func *__init_array_end;
fini_array_func *__fini_array_start;
fini_array_func *__fini_array_end;
#endif
int i;
int ret;
int (*prog_main)(int, char **);
s1->runtime_main = s1->nostdlib ? "_start" : "main";
@ -140,31 +152,34 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
errno = 0; /* clean errno value */
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
void (*bound_init)(void);
void (*bound_exit)(void);
void (*bounds_add_static_var)(size_t *p);
size_t *bounds_start;
int ret;
if (s1->do_bounds_check)
/* set error function */
s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
/* XXX: use .init section so that it also work in binary ? */
bound_init = tcc_get_symbol_err(s1, "__bound_init");
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
bounds_add_static_var = tcc_get_symbol_err(s1, "__bounds_add_static_var");
bounds_start = tcc_get_symbol_err(s1, "__bounds_start");
#endif
bound_init();
bounds_add_static_var (bounds_start);
#ifndef TCC_TARGET_PE
__init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
__init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
__fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
__fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
if (__init_array_start && __init_array_end) {
i = 0;
while (&__init_array_start[i] != __init_array_end)
(*__init_array_start[i++])(argc, argv, environ);
}
#endif
ret = (*prog_main)(argc, argv);
ret = (*prog_main)(argc, argv);
bound_exit();
return ret;
#ifndef TCC_TARGET_PE
if (__fini_array_start && __fini_array_end) {
i = 0;
while (&__fini_array_end[i] != __fini_array_start)
(*__fini_array_end[--i])();
}
#endif
return (*prog_main)(argc, argv);
return ret;
}
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
@ -649,6 +664,9 @@ static void set_exception_handler(void)
/* install TCC signal handlers to print debug info on fatal
runtime errors */
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
#ifdef SIGSTKSZ
sigact.sa_flags |= SA_ONSTACK;
#endif
sigact.sa_sigaction = sig_error;
sigemptyset(&sigact.sa_mask);
sigaction(SIGFPE, &sigact, NULL);
@ -656,6 +674,18 @@ static void set_exception_handler(void)
sigaction(SIGSEGV, &sigact, NULL);
sigaction(SIGBUS, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL);
#ifdef SIGSTKSZ
/* This allows stack overflow to be reported instead of a SEGV */
{
stack_t ss;
static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
ss.ss_sp = stack;
ss.ss_size = SIGSTKSZ;
ss.ss_flags = 0;
sigaltstack(&ss, NULL);
}
#endif
}
#else /* WIN32 */

2
tests/Makefile

@ -168,7 +168,7 @@ memtest:
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14 16
BOUNDS_OK = 1 4 8 10 14 16 18
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
btest: boundtest.c

197
tests/boundtest.c

@ -230,6 +230,202 @@ int test17()
return 0;
}
#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
extern void __bound_never_fatal (int neverfatal);
extern const char *__bound_error_msg;
static void init18(char *a, char *b)
{
memset (a, 'a', 10);
a[3] = 0;
a[9] = 0;
memset (b, 'b', 10);
__bound_error_msg = "";
}
/* ok (catch all errors) */
int test18()
{
char pad1[10];
char a[10];
char pad2[10];
char b[10];
char pad3[10];
memset (pad1, 0, sizeof(pad1));
memset (pad2, 0, sizeof(pad2));
memset (pad3, 0, sizeof(pad3));
/* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
__bound_never_fatal (-2);
/* memcpy */
init18(a,b);
memcpy(&a[1],&b[0],10);
CHECK("memcpy dest");
init18(a,b);
memcpy(&a[0],&b[1],10);
CHECK("memcpy src");
init18(a,b);
memcpy(&a[0],&a[3],4);
CHECK("overlapping regions");
init18(a,b);
memcpy(&a[3],&a[0],4);
CHECK("overlapping regions");
/* memcmp */
init18(a,b);
memcmp(&b[1],&b[0],10);
CHECK("memcmp s1");
init18(a,b);
memcmp(&b[0],&b[1],10);
CHECK("memcmp s2");
/* memmove */
init18(a,b);
memmove(&b[1],&b[0],10);
CHECK("memmove dest");
init18(a,b);
memmove(&b[0],&b[1],10);
CHECK("memmove src");
/* memset */
init18(a,b);
memset(&b[1],'b',10);
CHECK("memset");
/* strlen */
init18(a,b);
strlen(&b[0]);
CHECK("strlen");
/* strcpy */
init18(a,b);
strcpy(&a[7], &a[0]);
CHECK("strcpy dest");
init18(a,b);
strcpy(&a[0], &b[7]);
CHECK("strcpy src");
init18(a,b);
strcpy(&a[0], &a[1]);
CHECK("overlapping regions");
init18(a,b);
strcpy(&a[2], &a[0]);
CHECK("overlapping regions");
/* strncpy */
init18(a,b);
strncpy(&a[7], &a[0], 10);
CHECK("strncpy dest");
init18(a,b);
strncpy(&a[0], &b[7], 10);
CHECK("strncpy src");
init18(a,b);
strncpy(&a[0], &a[1], 10);
CHECK("overlapping regions");
strncpy(&a[2], &a[0], 10);
CHECK("overlapping regions");
/* strcmp */
init18(a,b);
strcmp(&b[2], &b[0]);
CHECK("strcmp s1");
init18(a,b);
strcmp(&b[0], &b[2]);
CHECK("strcmp s2");
/* strncmp */
init18(a,b);
strncmp(&b[5], &b[0], 10);
CHECK("strncmp s1");
init18(a,b);
strncmp(&b[0], &b[5], 10);
CHECK("strncmp s2");
/* strcat */
init18(a,b);
strcat(&a[7], &a[0]);
CHECK("strcat dest");
init18(a,b);
strcat(&a[0], &b[5]);
CHECK("strcat src");
init18(a,b);
strcat(&a[0], &a[4]);
CHECK("overlapping regions");
init18(a,b);
strcat(&a[3], &a[0]);
CHECK("overlapping regions");
/* strchr */
init18(a,b);
strchr(&b[0], 'a');
CHECK("strchr");
/* strdup */
init18(a,b);
free(strdup(&b[0]));
CHECK("strdup");
__bound_never_fatal (2);
/* memcpy */
init18(a,b);
memcpy(&a[0],&b[0],10);
init18(a,b);
memcpy(&a[0],&a[3],3);
init18(a,b);
memcpy(&a[3],&a[0],3);
/* memcmp */
init18(a,b);
memcmp(&b[0],&b[0],10);
/* memmove */
init18(a,b);
memmove(&b[0],&b[5],5);
init18(a,b);
memmove(&b[5],&b[0],5);
/* memset */
init18(a,b);
memset(&b[0],'b',10);
/* strlen */
init18(a,b);
strlen (&a[0]);
/* strcpy */
init18(a,b);
strcpy (&a[0], &a[7]);
/* strncpy */
init18(a,b);
strncpy (&a[0], &a[7], 4);
/* strcmp */
init18(a,b);
strcmp (&a[0], &a[4]);
/* strncmp */
init18(a,b);
strncmp (&a[0], &a[4], 10);
/* strcat */
init18(a,b);
strcat (&a[0], &a[7]);
/* strchr */
init18(a,b);
strchr (&a[0], 0);
/* strdup */
init18(a,b);
free (strdup (&a[0]));
return 0;
}
int (*table_test[])(void) = {
test1,
test2,
@ -248,6 +444,7 @@ int (*table_test[])(void) = {
test15,
test16,
test17,
test18,
};
int main(int argc, char **argv)

17
x86_64-gen.c

@ -637,7 +637,6 @@ static void gcall_or_jmp(int is_jmp)
}
#if defined(CONFIG_TCC_BCHECK)
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
static void gen_bounds_call(int v)
@ -784,8 +783,10 @@ void gfunc_call(int nb_args)
int arg;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) {
save_temp_local (nb_args);
gbound_args(nb_args);
}
#endif
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
@ -906,6 +907,10 @@ void gfunc_call(int nb_args)
}
vtop--;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
restore_temp_local ();
#endif
}
@ -1271,8 +1276,10 @@ void gfunc_call(int nb_args)
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) {
save_temp_local (nb_args);
gbound_args(nb_args);
}
#endif
/* calculate the number of integer/float register arguments, remember
@ -1453,6 +1460,10 @@ void gfunc_call(int nb_args)
if (args_size)
gadd_sp(args_size);
vtop--;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
restore_temp_local ();
#endif
}
#define FUNC_PROLOG_SIZE 11

85
x86_64-link.c

@ -287,89 +287,4 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
}
}
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
addr_t *ptr;
int loc_glob;
int sym_index;
int bsym_index;
if (0 == s1->do_bounds_check)
return;
/* XXX: add an object file to do that */
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
*ptr = 0;
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
bsym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
bounds_section->sh_num, "__bounds_start");
/* pull bcheck.o from libtcc1.a */
sym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bound_init");
if (s1->output_type != TCC_OUTPUT_MEMORY) {
/* add 'call __bound_init()' in .init section */
Section *init_section = find_section(s1, ".init");
unsigned char *pinit;
#ifdef TCC_TARGET_PE
pinit = section_ptr_add(init_section, 8);
pinit[0] = 0x55; /* push %rbp */
pinit[1] = 0x48; /* mov %rsp,%rpb */
pinit[2] = 0x89;
pinit[3] = 0xe5;
pinit[4] = 0x48; /* sub $0x10,%rsp */
pinit[5] = 0x83;
pinit[6] = 0xec;
pinit[7] = 0x10;
#endif
pinit = section_ptr_add(init_section, 5);
pinit[0] = 0xe8;
write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index);
/* R_386_PC32 = R_X86_64_PC32 = 2 */
pinit = section_ptr_add(init_section, 13);
pinit[0] = 0x48; /* mov xx,%rax */
pinit[1] = 0xb8;
write64le(pinit + 2, 0);
#ifdef TCC_TARGET_PE
pinit[10] = 0x48; /* mov %rax,%rcx */
pinit[11] = 0x89;
pinit[12] = 0xc1;
#else
pinit[10] = 0x48; /* mov %rax,%rdi */
pinit[11] = 0x89;
pinit[12] = 0xc7;
#endif
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 11, R_X86_64_64, bsym_index);
sym_index = set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bounds_add_static_var");
pinit = section_ptr_add(init_section, 5);
pinit[0] = 0xe8;
write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index);
/* R_386_PC32 = R_X86_64_PC32 = 2 */
#ifdef TCC_TARGET_PE
{
int init_index = set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
init_section->sh_num, "__init_start");
Sym sym;
init_section->sh_flags |= SHF_EXECINSTR;
pinit = section_ptr_add(init_section, 2);
pinit[0] = 0xc9; /* leave */
pinit[1] = 0xc3; /* ret */
sym.c = init_index;
add_init_array (s1, &sym);
}
#endif
}
}
#endif
#endif /* !TARGET_DEFS_ONLY */

Loading…
Cancel
Save