kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit dc1dc1f96640de20daa2a4b9accfb0a26b839218
parent 693766af7c518ae065bcfabbbc9f22692bb47d79
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 16 Jun 2026 15:35:46 -0700

link: parse linker-script integer literals as unsigned (fix high-half UB)

The hex/decimal accumulator was a signed i64, so a literal with the top bit
set (e.g. a high-half kernel ORIGIN 0xFFFFFFFF80000000) triggered signed
left-shift/overflow UB, aborting under UBSan before layout. Accumulate in u64
and reinterpret into the i64 int_val; addresses are bit patterns.

Diffstat:
Msrc/link/link_script.c | 13++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/link/link_script.c b/src/link/link_script.c @@ -348,7 +348,10 @@ static KitLinkExpr* parse_atom(LSP* p); static KitLinkExpr* parse_int(LSP* p) { KitLinkExpr* e; size_t start = p->pos; - i64 v = 0; + /* Accumulate unsigned: linker-script addresses routinely set the top bit + * (e.g. 0xFFFFFFFF80000000 high-half kernels); a signed shift/multiply would + * be UB there. The value is a bit pattern, reinterpreted into int_val below. */ + u64 v = 0; if (p->pos + 1 < p->len && p->src[p->pos] == '0' && (p->src[p->pos + 1] == 'x' || p->src[p->pos + 1] == 'X')) { p->pos += 2; @@ -387,20 +390,20 @@ static KitLinkExpr* parse_int(LSP* p) { if (p->pos < p->len) { char suffix = p->src[p->pos]; if (suffix == 'K' || suffix == 'k') { - v *= 1024ll; + v *= 1024ull; ++p->pos; } else if (suffix == 'M' || suffix == 'm') { - v *= 1024ll * 1024ll; + v *= 1024ull * 1024ull; ++p->pos; } else if (suffix == 'G' || suffix == 'g') { - v *= 1024ll * 1024ll * 1024ll; + v *= 1024ull * 1024ull * 1024ull; ++p->pos; } } e = lsp_new_expr(p); if (!e) return NULL; e->kind = KIT_LE_INT; - e->v.int_val = v; + e->v.int_val = (i64)v; return e; }