From 8a8388c6ffd8f6fada2c6f0f1a8d73afd55e6ff2 Mon Sep 17 00:00:00 2001 From: herman ten brugge Date: Tue, 6 Jan 2026 07:49:02 +0100 Subject: [PATCH] Solve some bug reports The savannah web site had some new bug report last december. A lot of them are assemmbly bugs. See testcase 60 for an overview. --- arm-asm.c | 5 +- arm-gen.c | 5 +- arm64-asm.c | 5 +- arm64-gen.c | 6 +- c67-gen.c | 5 +- i386-gen.c | 8 ++- riscv64-asm.c | 5 +- riscv64-gen.c | 5 +- tccasm.c | 25 +++++-- tccgen.c | 3 + tests/tests2/60_errors_and_warnings.c | 80 ++++++++++++++++++++++ tests/tests2/60_errors_and_warnings.expect | 42 ++++++++++++ x86_64-gen.c | 14 ++-- 13 files changed, 191 insertions(+), 17 deletions(-) diff --git a/arm-asm.c b/arm-asm.c index 2f9cca46..417c7d04 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -149,8 +149,11 @@ ST_FUNC void g(int c) if (nocode_wanted) return; ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c; ind = ind1; } diff --git a/arm-gen.c b/arm-gen.c index 81fa185a..eb44e22f 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -257,8 +257,11 @@ void o(uint32_t i) if (!cur_text_section) tcc_error("compiler error! This happens f.ex. if the compiler\n" "can't evaluate constant expressions outside of a function."); - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; diff --git a/arm64-asm.c b/arm64-asm.c index a97fd642..aa7e1ce4 100644 --- a/arm64-asm.c +++ b/arm64-asm.c @@ -31,8 +31,11 @@ ST_FUNC void g(int c) if (nocode_wanted) return; ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c; ind = ind1; } diff --git a/arm64-gen.c b/arm64-gen.c index d72a1b5e..5958f272 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -117,8 +117,11 @@ ST_FUNC void o(unsigned int c) int ind1 = ind + 4; if (nocode_wanted) return; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } write32le(cur_text_section->data + ind, c); ind = ind1; } @@ -274,6 +277,7 @@ static int arm64_type_size(int t) case VT_DOUBLE: return 3; case VT_LDOUBLE: return 4; case VT_BOOL: return 0; + case VT_VOID: return 0; } assert(0); return 0; diff --git a/c67-gen.c b/c67-gen.c index ea8ab822..ac8b3a01 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -195,8 +195,11 @@ void C67_g(int c) fprintf(f, " %08X", c); #endif ind1 = ind + 4; - if (ind1 > (int) cur_text_section->data_allocated) + if ((unsigned)ind1 > (int) cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c & 0xff; cur_text_section->data[ind + 1] = (c >> 8) & 0xff; cur_text_section->data[ind + 2] = (c >> 16) & 0xff; diff --git a/i386-gen.c b/i386-gen.c index 11106542..0a45fc7f 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -126,8 +126,11 @@ ST_FUNC void g(int c) if (nocode_wanted) return; ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c; ind = ind1; } @@ -363,7 +366,8 @@ ST_FUNC void load(int r, SValue *sv) r = 5; } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { opc = 0xbe0f; /* movsbl */ - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { + } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) || + (ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) { opc = 0xb60f; /* movzbl */ } else if ((ft & VT_TYPE) == VT_SHORT) { opc = 0xbf0f; /* movswl */ diff --git a/riscv64-asm.c b/riscv64-asm.c index 74cf4452..2cb3b866 100644 --- a/riscv64-asm.c +++ b/riscv64-asm.c @@ -98,8 +98,11 @@ ST_FUNC void g(int c) if (nocode_wanted) return; ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c; ind = ind1; } diff --git a/riscv64-gen.c b/riscv64-gen.c index 19c76682..750eea80 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -115,8 +115,11 @@ ST_FUNC void o(unsigned int c) int ind1 = ind + 4; if (nocode_wanted) return; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } write32le(cur_text_section->data + ind, c); ind = ind1; } diff --git a/tccasm.c b/tccasm.c index 9e89f5a3..14f2e891 100644 --- a/tccasm.c +++ b/tccasm.c @@ -398,6 +398,8 @@ ST_FUNC int asm_int_expr(TCCState *s1) asm_expr(s1, &e); if (e.sym) expect("constant"); + if ((int)e.v != e.v) + tcc_error("integer out of range %lld", (long long)e.v); return e.v; } @@ -515,7 +517,7 @@ static void asm_parse_directive(TCCState *s1, int global) tok1 = TOK_ASMDIR_align; } if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) { - if (n < 0 || (n & (n-1)) != 0) + if (n <= 0 || (n & (n-1)) != 0) tcc_error("alignment must be a positive power of two"); offset = (ind + n - 1) & -n; size = offset - ind; @@ -677,17 +679,21 @@ static void asm_parse_directive(TCCState *s1, int global) } case TOK_ASMDIR_org: { - unsigned long n; ExprValue e; ElfSym *esym; next(); asm_expr(s1, &e); n = e.v; + if (n != e.v || n < 0) + range: + tcc_error(".org out of range"); esym = elfsym(e.sym); if (esym) { if (esym->st_shndx != cur_text_section->sh_num) expect("constant or same-section symbol"); n += esym->st_value; + if (n < esym->st_value) + goto range; } if (n < ind) tcc_error("attempt to .org backwards"); @@ -713,6 +719,8 @@ static void asm_parse_directive(TCCState *s1, int global) do { Sym *sym; next(); + if (tok < TOK_IDENT || tok >= SYM_FIRST_ANOM) + tcc_error("Illegal symbol %s", get_tok_str(tok1, NULL)); sym = get_asm_sym(tok, NULL); if (tok1 != TOK_ASMDIR_hidden) sym->type.t &= ~VT_STATIC; @@ -799,7 +807,7 @@ static void asm_parse_directive(TCCState *s1, int global) if (tok == TOK_STR) pstrcat(ident, sizeof(ident), tokc.str.data); else - pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); + pstrcat(ident, sizeof(ident), get_tok_str(tok, &tokc)); tcc_warning_c(warn_unsupported)("ignoring .ident %s", ident); next(); } @@ -808,10 +816,11 @@ static void asm_parse_directive(TCCState *s1, int global) { Sym *sym; + tok1 = tok; next(); sym = asm_label_find(tok); if (!sym) { - tcc_error("label not found: %s", get_tok_str(tok, NULL)); + tcc_error("label not found: %s", get_tok_str(tok1, NULL)); } /* XXX .size name,label2-label1 */ tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL)); @@ -828,7 +837,10 @@ static void asm_parse_directive(TCCState *s1, int global) const char *newtype; int st_type; + tok1 = tok; next(); + if (tok < TOK_IDENT || tok >= SYM_FIRST_ANOM) + tcc_error("Illegal symbol %s", get_tok_str(tok1, NULL)); sym = get_asm_sym(tok, NULL); next(); skip(','); @@ -1177,11 +1189,14 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, modifier = *str++; index = find_constraint(operands, nb_operands, str, &str); if (index < 0) + error: tcc_error("invalid operand reference after %%"); op = &operands[index]; if (modifier == 'l') { cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1); } else { + if (op->vt == NULL) + goto error; sv = *op->vt; if (op->reg >= 0) { sv.r = op->reg; @@ -1318,6 +1333,8 @@ ST_FUNC void asm_instr(void) tcc_error("too many asm operands"); if (tok < TOK_UIDENT) expect("label identifier"); + memset(operands + nb_operands + nb_labels, 0, + sizeof(operands[0])); operands[nb_operands + nb_labels++].id = tok; csym = label_find(tok); diff --git a/tccgen.c b/tccgen.c index 10ddb617..6519a46b 100644 --- a/tccgen.c +++ b/tccgen.c @@ -7837,6 +7837,9 @@ static void init_putv(init_params *p, CType *type, unsigned long c) ElfW_Rel *rel; esym = elfsym(vtop->sym); ssec = tcc_state->sections[esym->st_shndx]; + if (esym->st_value + (int)vtop->c.i + size > ssec->data_offset) + section_add(ssec, esym->st_value + (int)vtop->c.i + + size - ssec->data_offset, 1); memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size); if (ssec->reloc) { /* We need to copy over all memory contents, and that diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index b89d7343..398ed236 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -551,4 +551,84 @@ int main(int argc, char **argv) } +#elif defined test_jmp_label + +int main(void) { + asm goto("jmp %[label]" : : : : label); +} + +#elif defined test_void_ternary + +int main() { + unsigned long b = 0; + if ((b ? (void)0 : (long long)b)) +} + +#elif defined test_init_int_string + +int fsB = ""; + +//#elif defined test_constant1 +// results differs on 32/64 bits targets +// reports 64: constant expression expected +// reports 32: constant exceeds 32 bit +//e[1.0 < r() +// +//#elif defined test_constant2 +// results differs on 32/64 bits targets +// reports 64: constant expression expected +// reports 32: constant exceeds 32 bit +//e[1 < r()-1. + +#elif defined test_asm1 + +asm (".align 8589934592"); + +#elif defined test_asm2 + +asm (".balign 8589934592"); + +#elif defined test_asm3 + +asm (".global "); + +#elif defined test_asm4 + +asm (".type (a,cr0,digit)"); + +#elif defined test_asm5 + +asm (".type $6"); + +#elif defined test_asm6 + +asm (".global $-3"); + +#elif defined test_asm7 + +asm (".global (dx,0X2D,digit)"); + +#elif defined test_asm8 + +asm (".size 0XA"); + +#elif defined test_asm9 + +asm (".weak (fs:0)"); + +#elif defined test_asm10 + +asm (".align 0"); + +#elif defined test_asm11 + +asm (".org 33824993159184"); + +//#elif defined test_big +// results differs on 32/64 bits targets +// reports 64: error: program too big +// reports 32: memory full +//asm (".org 0x7fffffff"); +//asm (".byte 1, 2, 3, 4"); + #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index a90f4153..0588f552 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -262,3 +262,45 @@ bar 15 12 34 [test_scope_3] 60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type 60_errors_and_warnings.c:549: error: initialization of incomplete type + +[test_jmp_label] +60_errors_and_warnings.c:557: error: invalid operand reference after % + +[test_void_ternary] +60_errors_and_warnings.c:564: error: invalid operand types for binary operation + +[test_init_int_string] +60_errors_and_warnings.c:569: warning: assignment makes integer from pointer without a cast + +[test_asm1] +60_errors_and_warnings.c:584: error: integer out of range 8589934592 + +[test_asm2] +60_errors_and_warnings.c:588: error: integer out of range 8589934592 + +[test_asm3] +60_errors_and_warnings.c:592: error: Illegal symbol .global + +[test_asm4] +60_errors_and_warnings.c:597: error: Illegal symbol .type + +[test_asm5] +60_errors_and_warnings.c:601: error: Illegal symbol .type + +[test_asm6] +60_errors_and_warnings.c:605: error: Illegal symbol .global + +[test_asm7] +60_errors_and_warnings.c:609: error: Illegal symbol .global + +[test_asm8] +60_errors_and_warnings.c:613: error: label not found: .size + +[test_asm9] +60_errors_and_warnings.c:617: error: Illegal symbol .weak + +[test_asm10] +60_errors_and_warnings.c:620: error: alignment must be a positive power of two + +[test_asm11] +60_errors_and_warnings.c:624: error: .org out of range diff --git a/x86_64-gen.c b/x86_64-gen.c index 0e63e685..95b72e93 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -175,8 +175,11 @@ ST_FUNC void g(int c) if (nocode_wanted) return; ind1 = ind + 1; - if (ind1 > cur_text_section->data_allocated) + if ((unsigned)ind1 > cur_text_section->data_allocated) { + if (ind1 < 0) + tcc_error("program too big"); section_realloc(cur_text_section, ind1); + } cur_text_section->data[ind] = c; ind = ind1; } @@ -444,7 +447,8 @@ void load(int r, SValue *sv) b = 0xdb, r = 5; /* fldt */ } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { b = 0xbe0f; /* movsbl */ - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { + } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) || + (ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) { b = 0xb60f; /* movzbl */ } else if ((ft & VT_TYPE) == VT_SHORT) { b = 0xbf0f; /* movswl */ @@ -538,7 +542,8 @@ void load(int r, SValue *sv) o(0x44 + REG_VALUE(r)*8); /* %xmmN */ o(0xf024); } else { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + if (!nocode_wanted) + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); if ((ft & VT_BTYPE) == VT_FLOAT) { o(0x100ff3); } else { @@ -548,7 +553,8 @@ void load(int r, SValue *sv) o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); } } else if (r == TREG_ST0) { - assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); + if (!nocode_wanted) + assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); /* gen_cvt_ftof(VT_LDOUBLE); */ /* movsd %xmmN,-0x10(%rsp) */ o(0x110ff2);