Add linenumber filename support for bounds checking.

This commit is contained in:
herman ten brugge 2019-12-13 13:45:09 +01:00
parent 56e70bfa31
commit 87639aae7c
3 changed files with 154 additions and 124 deletions

View file

@ -1130,29 +1130,36 @@ ST_FUNC void gen_bounded_ptr_add(void)
{ {
/* save all temporary registers */ /* save all temporary registers */
save_regs(0); save_regs(0);
/* trick to get line/file_name in code */
o(0xb8);
gen_le32 (file->line_num);
{
int i;
int len;
char *cp = file->filename;
while (*cp) cp++;
while (cp != file->filename && cp[-1] != '/') cp--;
len = strlen (cp);
while (len > 0) {
memcpy (&i, cp, 4);
o(0xb8);
gen_le32 (i);
cp += 4;
len -= 4;
}
}
/* prepare fast i386 function call (args in eax and edx) */ /* prepare fast i386 function call (args in eax and edx) */
gv2(RC_EAX, RC_EDX); gv2(RC_EAX, RC_EDX);
vtop -= 2; vtop -= 2;
/* add line, filename */
{
static addr_t offset;
static char last_filename[1024];
Sym *sym_data;
if (strcmp (last_filename, file->filename) != 0) {
void *ptr;
int len = strlen (file->filename) + 1;
offset = data_section->data_offset;
ptr = section_ptr_add(data_section, len);
memcpy (ptr, file->filename, len);
memcpy (last_filename, file->filename, len);
}
o(0xb9); /* mov $xx,%ecx */
gen_le32 (0);
sym_data = get_sym_ref(&char_pointer_type, data_section,
offset, data_section->data_offset);
greloca(cur_text_section, sym_data, ind - 4, R_386_32, 0);
o(0x51); /* push %ecx */
}
o(0xb9); /* mov $xx,%ecx */
gen_le32 (file->line_num);
/* do a fast function call */ /* do a fast function call */
gen_static_call(TOK___bound_ptr_add); gen_static_call(TOK___bound_ptr_add);
o(0x04c483); /* add $4,%esp */
/* returned pointer is in eax */ /* returned pointer is in eax */
vtop++; vtop++;
vtop->r = TREG_EAX | VT_BOUNDED; vtop->r = TREG_EAX | VT_BOUNDED;

View file

@ -221,7 +221,8 @@ static void bound_alloc_error(void)
/* return '(p + offset)' for pointer arithmetic (a pointer can reach /* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */ the end of a region in this case */
void * FASTCALL __bound_ptr_add(void *p, size_t offset) void * FASTCALL __bound_ptr_add(void *p, size_t offset,
size_t line, const char *filename)
{ {
size_t addr = (size_t)p; size_t addr = (size_t)p;
@ -229,8 +230,8 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset)
return p + offset; return p + offset;
} }
dprintf(stderr, "%s %s: %p 0x%x\n", dprintf(stderr, "%s %s (%s:%u): %p 0x%x\n",
__FILE__, __FUNCTION__, p, (unsigned)offset); __FILE__, __FUNCTION__, filename, line, p, (unsigned)offset);
WAIT_SEM (); WAIT_SEM ();
INCR_COUNT(bound_ptr_add_count); INCR_COUNT(bound_ptr_add_count);
@ -249,8 +250,8 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset)
if (addr <= tree->size) { if (addr <= tree->size) {
addr += offset; addr += offset;
if (tree->is_invalid || addr > tree->size) { if (tree->is_invalid || addr > tree->size) {
fprintf(stderr,"%s %s: %p is outside of the region\n", fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n",
__FILE__, __FUNCTION__, p + offset); __FILE__, __FUNCTION__, filename, line, p + offset);
if (never_fatal == 0) { if (never_fatal == 0) {
POST_SEM (); POST_SEM ();
return INVALID_POINTER; /* return an invalid pointer */ return INVALID_POINTER; /* return an invalid pointer */
@ -264,44 +265,45 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset)
/* return '(p + offset)' for pointer indirection (the resulting must /* return '(p + offset)' for pointer indirection (the resulting must
be strictly inside the region */ be strictly inside the region */
#define BOUND_PTR_INDIR(dsize) \ #define BOUND_PTR_INDIR(dsize) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \
{ \ size_t line, const char *filename) \
size_t addr = (size_t)p; \ { \
\ size_t addr = (size_t)p; \
if (no_checking) { \ \
return p + offset; \ if (no_checking) { \
} \ return p + offset; \
dprintf(stderr, "%s %s: %p 0x%x start\n", \ } \
__FILE__, __FUNCTION__, p, (unsigned)offset); \ dprintf(stderr, "%s %s (%s:%u): %p 0x%x start\n", \
WAIT_SEM (); \ __FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); \
INCR_COUNT(bound_ptr_indir ## dsize ## _count); \ WAIT_SEM (); \
if (tree) { \ INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
addr -= tree->start; \ if (tree) { \
if (addr >= tree->size) { \ addr -= tree->start; \
addr = (size_t)p; \ if (addr >= tree->size) { \
tree = splay (addr, tree); \ addr = (size_t)p; \
addr -= tree->start; \ tree = splay (addr, tree); \
} \ addr -= tree->start; \
if (addr >= tree->size) { \ } \
addr = (size_t)p; \ if (addr >= tree->size) { \
tree = splay_end (addr, tree); \ addr = (size_t)p; \
addr -= tree->start; \ tree = splay_end (addr, tree); \
} \ addr -= tree->start; \
if (addr <= tree->size) { \ } \
addr += offset + dsize; \ if (addr <= tree->size) { \
if (tree->is_invalid || addr > tree->size) { \ addr += offset + dsize; \
fprintf(stderr,"%s %s: %p is outside of the region\n", \ if (tree->is_invalid || addr > tree->size) { \
__FILE__, __FUNCTION__, p + offset); \ fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", \
if (never_fatal == 0) { \ __FILE__, __FUNCTION__, filename, line, p + offset); \
POST_SEM (); \ if (never_fatal == 0) { \
return INVALID_POINTER; /* return an invalid pointer */ \ POST_SEM (); \
} \ return INVALID_POINTER; /* return an invalid pointer */ \
} \ } \
} \ } \
} \ } \
POST_SEM (); \ } \
return p + offset; \ POST_SEM (); \
return p + offset; \
} }
BOUND_PTR_INDIR(1) BOUND_PTR_INDIR(1)
@ -540,7 +542,7 @@ void __attribute__((destructor)) __bound_exit(void)
} }
while (tree) { while (tree) {
if (print_heap && tree->type != 0) { if (print_heap && tree->type != 0) {
fprintf (stderr, "%s, %s() %s found size %ld\n", fprintf (stderr, "%s, %s() %s found size %lu\n",
__FILE__, __FUNCTION__, alloc_type[tree->type], __FILE__, __FUNCTION__, alloc_type[tree->type],
(unsigned long) tree->size); (unsigned long) tree->size);
} }
@ -621,7 +623,7 @@ void *__bound_malloc(size_t size, const void *caller)
if (ptr) { if (ptr) {
tree = splay_insert ((size_t) ptr, size, tree); tree = splay_insert ((size_t) ptr, size, tree);
if (tree->start == (size_t) ptr) { if (tree && tree->start == (size_t) ptr) {
tree->type = TCC_TYPE_MALLOC; tree->type = TCC_TYPE_MALLOC;
} }
} }
@ -666,7 +668,7 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
dprintf(stderr, "%s, %s (%p, 0x%x)\n", dprintf(stderr, "%s, %s (%p, 0x%x)\n",
__FILE__, __FUNCTION__, ptr, (unsigned)size); __FILE__, __FUNCTION__, ptr, (unsigned)size);
tree = splay_insert((size_t) ptr, size, tree); tree = splay_insert((size_t) ptr, size, tree);
if (tree->start == (size_t) ptr) { if (tree && tree->start == (size_t) ptr) {
tree->type = TCC_TYPE_MEMALIGN; tree->type = TCC_TYPE_MEMALIGN;
} }
} }
@ -744,7 +746,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
INCR_COUNT(bound_realloc_count); INCR_COUNT(bound_realloc_count);
if (ptr) { if (ptr) {
tree = splay_insert ((size_t) ptr, size, tree); tree = splay_insert ((size_t) ptr, size, tree);
if (tree->start == (size_t) ptr) { if (tree && tree->start == (size_t) ptr) {
tree->type = TCC_TYPE_REALLOC; tree->type = TCC_TYPE_REALLOC;
} }
} }
@ -761,7 +763,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
#endif #endif
if (ptr) { if (ptr) {
tree = splay_insert ((size_t) ptr, size, tree); tree = splay_insert ((size_t) ptr, size, tree);
if (tree->start == (size_t) ptr) { if (tree && tree->start == (size_t) ptr) {
tree->type = TCC_TYPE_REALLOC; tree->type = TCC_TYPE_REALLOC;
} }
} }
@ -800,7 +802,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
WAIT_SEM (); WAIT_SEM ();
INCR_COUNT(bound_calloc_count); INCR_COUNT(bound_calloc_count);
tree = splay_insert ((size_t) ptr, size, tree); tree = splay_insert ((size_t) ptr, size, tree);
if (tree->start == (size_t) ptr) { if (tree && tree->start == (size_t) ptr) {
tree->type = TCC_TYPE_CALLOC; tree->type = TCC_TYPE_CALLOC;
} }
POST_SEM (); POST_SEM ();
@ -899,13 +901,13 @@ void __bound_new_region(void *p, size_t size)
/* some useful checked functions */ /* some useful checked functions */
/* check that (p ... p + size - 1) lies inside 'p' region, if any */ /* check that (p ... p + size - 1) lies inside 'p' region, if any */
static void __bound_check(const void *p, size_t size) static void __bound_check(const void *p, size_t size, const char *function)
{ {
if (no_checking) if (no_checking)
return; return;
if (size == 0) if (size == 0)
return; return;
p = __bound_ptr_add((void *)p, size); p = __bound_ptr_add((void *)p, size, 0, function);
if (p == INVALID_POINTER) if (p == INVALID_POINTER)
bound_error("invalid pointer"); bound_error("invalid pointer");
} }
@ -915,8 +917,8 @@ void *__bound_memcpy(void *dst, const void *src, size_t size)
void* p; void* p;
INCR_COUNT(bound_mempcy_count); INCR_COUNT(bound_mempcy_count);
__bound_check(dst, size); __bound_check(dst, size, "memcpy");
__bound_check(src, size); __bound_check(src, size, "memcpy");
/* check also region overlap */ /* check also region overlap */
if (no_checking == 0 && src >= dst && src < dst + size) if (no_checking == 0 && src >= dst && src < dst + size)
bound_error("overlapping regions in memcpy()"); bound_error("overlapping regions in memcpy()");
@ -929,23 +931,23 @@ void *__bound_memcpy(void *dst, const void *src, size_t size)
int __bound_memcmp(const void *s1, const void *s2, size_t size) int __bound_memcmp(const void *s1, const void *s2, size_t size)
{ {
INCR_COUNT(bound_memcmp_count); INCR_COUNT(bound_memcmp_count);
__bound_check(s1, size); __bound_check(s1, size, "memcmp");
__bound_check(s2, size); __bound_check(s2, size, "memcmp");
return memcmp(s1, s2, size); return memcmp(s1, s2, size);
} }
void *__bound_memmove(void *dst, const void *src, size_t size) void *__bound_memmove(void *dst, const void *src, size_t size)
{ {
INCR_COUNT(bound_memmove_count); INCR_COUNT(bound_memmove_count);
__bound_check(dst, size); __bound_check(dst, size, "memmove");
__bound_check(src, size); __bound_check(src, size, "memmove");
return memmove(dst, src, size); return memmove(dst, src, size);
} }
void *__bound_memset(void *dst, int c, size_t size) void *__bound_memset(void *dst, int c, size_t size)
{ {
INCR_COUNT(bound_memset_count); INCR_COUNT(bound_memset_count);
__bound_check(dst, size); __bound_check(dst, size, "memset");
return memset(dst, c, size); return memset(dst, c, size);
} }
@ -957,7 +959,7 @@ int __bound_strlen(const char *s)
INCR_COUNT(bound_strlen_count); INCR_COUNT(bound_strlen_count);
while (*p++); while (*p++);
len = (p - s) - 1; len = (p - s) - 1;
p = __bound_ptr_indir1((char *)s, len); p = __bound_ptr_indir1((char *)s, len, 0, "strlen");
if (p == INVALID_POINTER) if (p == INVALID_POINTER)
bound_error("bad pointer in strlen()"); bound_error("bad pointer in strlen()");
return len; return len;
@ -982,8 +984,8 @@ char *__bound_strncpy(char *dst, const char *src, size_t n)
while (len-- && *p++); while (len-- && *p++);
len = p - src; len = p - src;
INCR_COUNT(bound_strncpy_count); INCR_COUNT(bound_strncpy_count);
__bound_check(dst, len); __bound_check(dst, len, "strncpy");
__bound_check(src, len); __bound_check(src, len, "strncpy");
return strncpy (dst, src, n); return strncpy (dst, src, n);
} }
@ -997,8 +999,8 @@ int __bound_strcmp(const char *s1, const char *s2)
u1++; u1++;
u2++; u2++;
} }
__bound_check(s1, ((const char *)u1 - s1) + 1); __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp");
__bound_check(s2, ((const char *)u2 - s2) + 1); __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp");
return (*u1 - *u2); return (*u1 - *u2);
} }
@ -1018,8 +1020,8 @@ int __bound_strncmp(const char *s1, const char *s2, size_t n)
} }
u2++; u2++;
} while (*u1++); } while (*u1++);
__bound_check(s1, ((const char *)u1 - s1) + 1); __bound_check(s1, ((const char *)u1 - s1) + 1, "strncmp");
__bound_check(s2, ((const char *)u1 - s1) + 1); __bound_check(s2, ((const char *)u1 - s1) + 1, "strncmp");
return retval; return retval;
} }
@ -1032,8 +1034,8 @@ char *__bound_strcat(char *dest, const char *src)
while (*dest++); while (*dest++);
dest--; dest--;
while ((*dest++ = *src++) != 0); while ((*dest++ = *src++) != 0);
__bound_check(r, dest - r); __bound_check(r, dest - r, "strcat");
__bound_check(s, src - s); __bound_check(s, src - s, "strcat");
return r; return r;
} }
@ -1049,7 +1051,7 @@ char *__bound_strchr(const char *string, int ch)
} }
s++; s++;
} }
__bound_check(string, ((const char *)s - string) + 1); __bound_check(string, ((const char *)s - string) + 1, "strchr");
return *s == c ? (char *) s : NULL; return *s == c ? (char *) s : NULL;
} }
@ -1060,7 +1062,7 @@ char *__bound_strdup(const char *s)
INCR_COUNT(bound_strdup_count); INCR_COUNT(bound_strdup_count);
while (*p++); while (*p++);
__bound_check(s, p - s); __bound_check(s, p - s, "strdup");
#if MALLOC_REDIR #if MALLOC_REDIR
new = malloc_redir (p - s); new = malloc_redir (p - s);
#else #else
@ -1069,7 +1071,7 @@ char *__bound_strdup(const char *s)
if (new) { if (new) {
WAIT_SEM (); WAIT_SEM ();
tree = splay_insert((size_t)new, p - s, tree); tree = splay_insert((size_t)new, p - s, tree);
if (tree->start == (size_t) new) { if (tree && tree->start == (size_t) new) {
tree->type = TCC_TYPE_STRDUP; tree->type = TCC_TYPE_STRDUP;
} }
memcpy (new, s, p - s); memcpy (new, s, p - s);
@ -1261,22 +1263,26 @@ static Tree * splay_insert(size_t addr, size_t size, Tree * t)
new = (Tree *) malloc (sizeof (Tree)); new = (Tree *) malloc (sizeof (Tree));
#endif #endif
} }
if (new == NULL) {bound_alloc_error();} if (new == NULL) {
if (t == NULL) { bound_alloc_error();
new->left = new->right = NULL; }
} else if (compare(addr, t->start, t->size) < 0) { else {
new->left = t->left; if (t == NULL) {
new->right = t; new->left = new->right = NULL;
t->left = NULL; } else if (compare(addr, t->start, t->size) < 0) {
} else { new->left = t->left;
new->right = t->right; new->right = t;
new->left = t; t->left = NULL;
t->right = NULL; } else {
new->right = t->right;
new->left = t;
t->right = NULL;
}
new->start = addr;
new->size = size;
new->type = TCC_TYPE_NONE;
new->is_invalid = 0;
} }
new->start = addr;
new->size = size;
new->type = TCC_TYPE_NONE;
new->is_invalid = 0;
return new; return new;
} }

View file

@ -767,28 +767,12 @@ ST_FUNC void gen_bounded_ptr_add(void)
if (nested_call > 1) { if (nested_call > 1) {
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
o(0x5152); /* push %rcx/%rdx */ o(0x5152); /* push %rdx/%rcx */
o(0x51415041); /* push %r8/%r9 */
#else #else
o(0x5657); /* push %rdi/%rsi */ o(0x51525657); /* push %rdi/%rsi/%rdx/%rcx */
#endif #endif
} }
/* trick to get line/file_name in code */
o(0xb8);
gen_le32 (file->line_num);
{
int len;
char *cp = file->filename;
while (*cp) cp++;
while (cp != file->filename && cp[-1] != '/') cp--;
len = strlen (cp);
while (len > 0) {
memcpy (&i, cp, 4);
o(0xb8);
gen_le32 (i);
cp += 4;
len -= 4;
}
}
/* prepare fast x86_64 function call */ /* prepare fast x86_64 function call */
gv(RC_RAX); gv(RC_RAX);
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
@ -806,6 +790,38 @@ ST_FUNC void gen_bounded_ptr_add(void)
#endif #endif
vtop--; vtop--;
/* add line, filename */
#ifdef TCC_TARGET_PE
o(0xc0c749); /* mov $xx,%r8 */
#else
o(0xba); /* mov $xx,%edx */
#endif
gen_le32 (file->line_num);
{
static addr_t offset;
static char last_filename[1024];
Sym *sym_data;
if (strcmp (last_filename, file->filename) != 0) {
void *ptr;
int len = strlen (file->filename) + 1;
offset = data_section->data_offset;
ptr = section_ptr_add(data_section, len);
memcpy (ptr, file->filename, len);
memcpy (last_filename, file->filename, len);
}
#ifdef TCC_TARGET_PE
o(0xb949); /* mov $xx,%r9 */
#else
o(0xb948); /* mov $xx,%rcx */
#endif
gen_le64 (0);
sym_data = get_sym_ref(&char_pointer_type, data_section,
offset, data_section->data_offset);
greloca(cur_text_section, sym_data, ind - 8, R_X86_64_64, 0);
}
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
o(0x20ec8348); /* sub $20, %rsp */ o(0x20ec8348); /* sub $20, %rsp */
#endif #endif
@ -819,9 +835,10 @@ ST_FUNC void gen_bounded_ptr_add(void)
if (nested_call > 1) { if (nested_call > 1) {
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
o(0x5a59); /* pop %rcx/%rdx */ o(0x58415941); /* pop %r9/%r8 */
o(0x5a59); /* pop %rcx/%rdx */
#else #else
o(0x5f5e); /* pop %rsi/%rdi */ o(0x5f5e5a59); /* pop $rcx/%rdx/%rsi/%rdi */
#endif #endif
} }
/* returned pointer is in rax */ /* returned pointer is in rax */