stage1/decompressor: Ensure limlz streams always end on a literal token

This commit is contained in:
Mintsuki
2026-04-20 14:40:37 +02:00
parent 6239cb53f3
commit ff63204fc9
2 changed files with 12 additions and 0 deletions

View File

@@ -75,6 +75,8 @@ _start:
mov esi, ecx
lea ecx, [eax+0x4] ; count = matchlen + 4
rep movsb ; copy match
cmp edx, ebx ; guard against streams that end on a match
jae .Lcrc
jmp .Ltoken
; CRC32 verification
.Lcrc:

View File

@@ -218,6 +218,7 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
dp[i] = best_cost; pick[i].lit = best_lit;
pick[i].mlen = best_len; pick[i].off = best_off;
}
int terminated = 0;
for (i = 0; i < srcsz; ) {
byte * tokenp;
size_t lit = pick[i].lit, ml = pick[i].mlen;
@@ -241,6 +242,7 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
i += lit;
if (i >= srcsz) {
*tokenp = (byte)(token_hi << 3);
terminated = 1;
break;
}
unsigned mode_bit = (off > 255) ? 1u : 0u;
@@ -260,6 +262,14 @@ static size_t limlzpack(void * dst, size_t dstcap, const void * srcv, size_t src
goto fail;
i += ml;
}
/* A match-ended parse leaves no trailing token; the decompressor keys
* termination off a zero-or-more-byte literal copy reaching ipe, so always
* emit a final lit=0 token when the main loop didn't already. */
if (!terminated) {
if (out >= out_end)
goto fail;
*out++ = 0;
}
free(mch); free(pick); free(bestm); free(dp);
return (size_t)(out - dstp);
fail: