Check with clang -fsanitize
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86_64-win32 (push) Has been cancelled
build and test / test-i386-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled

Tested code with:
clang -fsanitize=address,undefined,nullability -pie -fPIE -Iinclude -I. -g tcc.c -o tcc.tcc -lm -ldl -lpthread
./tcc.tcc -Iinclude -I. -b -g tcc.c -o tcc.tcc1 -lm -ldl -lpthread

Also checked on i386/x86_64 with -fsanitize=memory (others not supported).

arm-link.c: use read32le/write32le/add32le to avoid unaligned access
tcc.h i386-asm.c: fix signed left shift
lib/bcheck.c: Add _Atomic
libtcc.c: Correct MEM_DEBUG_CHECK3 to avoid unaligned access
riscv64-link.c: Fix R_RISCV_SET16
tccpp.c: Align tal_header_t to avoid unaligned access
tccgen.c x86_64-gen.c: avoid use of uninitialized value

There are still warnings reported:
tccgen.c:4031:13: runtime error: member access within null pointer of type 'TCCState' (aka 'struct TCCState')
tccelf.c:321:22: runtime error: applying zero offset to null pointer
tccelf.c:1132:23: runtime error: applying non-zero offset 169184 to null pointer

A lot of left shift of negative value warnings.

I ignored these for the moment.

Also the -run option does no work well with -fsanitize. It gets confused
because it does not detect that the generated code in memory is used
without -fsanitize option.

There are a lot more -fsanitize options. I did not find serious problems
with them.
This commit is contained in:
herman ten brugge 2025-07-27 11:22:16 +02:00
parent a2902d37a1
commit 8025a829cc
9 changed files with 35 additions and 32 deletions

View File

@ -194,11 +194,11 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
case R_ARM_PLT32:
{
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
x = (*(int *) ptr) & 0xffffff;
x = read32le(ptr) & 0xffffff;
#ifdef DEBUG_RELOC
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
#endif
(*(int *)ptr) &= 0xff000000;
write32le(ptr, read32le(ptr) & 0xff000000);
if (x & 0x800000)
x -= 0x1000000;
x <<= 2;
@ -220,9 +220,9 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
/* Only reached if blx is avail and it is a call */
if (is_thumb) {
x |= h << 24;
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */
write32le(ptr, 0xfa << 24); /* bl -> blx */
}
(*(int *) ptr) |= x;
write32le(ptr, read32le(ptr) | x);
}
return;
/* Since these relocations only concern Thumb-2 and blx instruction was
@ -330,23 +330,23 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
imm4 = (val >> 12) & 0xf;
x = (imm4 << 16) | imm12;
if (type == R_ARM_THM_MOVT_ABS)
*(int *)ptr |= x;
write32le(ptr, read32le(ptr) | x);
else
*(int *)ptr += x;
add32le(ptr, x);
}
return;
case R_ARM_MOVT_PREL:
case R_ARM_MOVW_PREL_NC:
{
int insn = *(int *)ptr;
int insn = read32le(ptr);
int addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
addend = (addend ^ 0x8000) - 0x8000;
val += addend - addr;
if (type == R_ARM_MOVT_PREL)
val >>= 16;
*(int *)ptr = (insn & 0xfff0f000) |
((val & 0xf000) << 4) | (val & 0xfff);
write32le(ptr, (insn & 0xfff0f000) |
((val & 0xf000) << 4) | (val & 0xfff));
}
return;
case R_ARM_THM_MOVT_ABS:
@ -361,21 +361,21 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
imm4 = (val >> 12) & 0xf;
x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4;
if (type == R_ARM_THM_MOVT_ABS)
*(int *)ptr |= x;
write32le(ptr, read32le(ptr) | x);
else
*(int *)ptr += x;
add32le(ptr, x);
}
return;
case R_ARM_PREL31:
{
int x;
x = (*(int *)ptr) & 0x7fffffff;
(*(int *)ptr) &= 0x80000000;
x = read32le(ptr) & 0x7fffffff;
write32le(ptr, read32le(ptr) & 0x80000000);
x = (x * 2) / 2;
x += val - addr;
if((x^(x>>1))&0x40000000)
tcc_error_noabort("can't relocate value at %x,%d",addr, type);
(*(int *)ptr) |= x & 0x7fffffff;
write32le(ptr, read32le(ptr) | (x & 0x7fffffff));
}
return;
case R_ARM_ABS32:
@ -392,33 +392,33 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
qrel++;
}
}
*(int *)ptr += val;
add32le(ptr, val);
return;
case R_ARM_REL32:
*(int *)ptr += val - addr;
add32le(ptr, val - addr);
return;
case R_ARM_GOTPC:
*(int *)ptr += s1->got->sh_addr - addr;
add32le(ptr, s1->got->sh_addr - addr);
return;
case R_ARM_GOTOFF:
*(int *)ptr += val - s1->got->sh_addr;
add32le(ptr, val - s1->got->sh_addr);
return;
case R_ARM_GOT32:
/* we load the got offset */
*(int *)ptr += get_sym_attr(s1, sym_index, 0)->got_offset;
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
return;
case R_ARM_GOT_PREL:
/* we load the pc relative got offset */
*(int *)ptr += s1->got->sh_addr +
get_sym_attr(s1, sym_index, 0)->got_offset -
addr;
add32le(ptr, s1->got->sh_addr +
get_sym_attr(s1, sym_index, 0)->got_offset -
addr);
return;
case R_ARM_COPY:
return;
case R_ARM_V4BX:
/* trade Thumb support for ARMv4 support */
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
if ((0x0ffffff0 & read32le(ptr)) == 0x012FFF10)
write32le(ptr, read32le(ptr) ^ 0xE12FFF10 ^ 0xE1A0F000); /* BX Rm -> MOV PC, Rm */
return;
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:

View File

@ -136,7 +136,7 @@ enum {
# define OP_EA32 0
#endif
#define OP_EA 0x40000000
#define OP_EA 0x40000000u
#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
#ifdef TCC_TARGET_X86_64

View File

@ -351,7 +351,7 @@ static unsigned char print_heap;
static unsigned char print_statistic;
static unsigned char no_strdup;
static unsigned char use_sem;
static int never_fatal;
static _Atomic int never_fatal;
#if HAVE_TLS_FUNC
#if defined(_WIN32)
static int no_checking = 0;
@ -393,7 +393,7 @@ static __thread int no_checking = 0;
#define NO_CHECKING_GET() no_checking
#define NO_CHECKING_SET(v) no_checking = v
#else
static int no_checking = 0;
static _Atomic int no_checking = 0;
#define NO_CHECKING_GET() no_checking
#define NO_CHECKING_SET(v) no_checking = v
#endif

View File

@ -314,7 +314,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
#define MEM_DEBUG_MAGIC3 0xFEEDDEB3
#define MEM_DEBUG_FILE_LEN 40
#define MEM_DEBUG_CHECK3(header) \
((mem_debug_header_t*)((char*)header + header->size))->magic3
(((unsigned char *) header->magic3) + header->size)
#define MEM_USER_PTR(header) \
((char *)header + offsetof(mem_debug_header_t, magic3))
#define MEM_HEADER_PTR(ptr) \

View File

@ -347,7 +347,7 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
*ptr = (*ptr & ~0xff) | (val & 0xff);
return;
case R_RISCV_SET16:
*ptr = (*ptr & ~0xffff) | (val & 0xffff);
write16le(ptr, (read16le(ptr) & ~0xffff) | (val & 0xffff));
return;
case R_RISCV_SUB6:
*ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f);

2
tcc.h
View File

@ -1689,7 +1689,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
retval |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0) {
if ((byte & 0x40) && (i + 1) * 7 < 64)
retval |= -1LL << ((i + 1) * 7);
retval |= (uint64_t)-1LL << ((i + 1) * 7);
break;
}
}

View File

@ -1374,6 +1374,7 @@ ST_FUNC void save_reg_upstack(int r, int n)
l = get_temp_local_var(size, align, &r2);
sv.r = VT_LOCAL | VT_LVAL;
sv.c.i = l;
sv.sym = NULL;
store(p->r & VT_VALMASK, &sv);
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
/* x86 specific: need to pop fp register ST0 if saved */
@ -3768,6 +3769,7 @@ ST_FUNC void vstore(void)
sv.type.t = VT_PTRDIFF_T;
sv.r = VT_LOCAL | VT_LVAL;
sv.c.i = vtop[-1].c.i;
sv.sym = NULL;
load(r, &sv);
vtop[-1].r = r | VT_LVAL;
}

View File

@ -157,7 +157,7 @@ typedef struct TinyAlloc {
} TinyAlloc;
typedef struct tal_header_t {
unsigned size;
ALIGNED(PTR_SIZE) unsigned size;
#ifdef TAL_DEBUG
int line_num; /* negative line_num used for double free check */
char file_name[TAL_DEBUG_FILE_LEN + 1];
@ -246,7 +246,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
tal_header_t *header;
void *ret;
int is_own;
unsigned adj_size = (size + 3) & -4;
unsigned adj_size = (size + PTR_SIZE - 1) & -PTR_SIZE;
TinyAlloc *al = *pal;
tail_call:

View File

@ -396,6 +396,7 @@ void load(int r, SValue *sv)
v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
v1.sym = NULL;
fr = r;
if (!(reg_classes[fr] & (RC_INT|RC_R11)))
fr = get_reg(RC_INT);