mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
fix: cap justify fill array at 256 chars to shrink ~1.25 MB stack frame (#818)
co_center/co_ljust/co_rjust sized fill_char_t fchars[LBUF_SIZE] — one
entry per LBUF byte — at ~40 bytes each, a ~1.25 MB stack frame. On
Windows's 1 MB default EXE stack reserve, any center()/ljust()/rjust()
call overflowed the stack and killed netmux instantly (0xc00000fd);
worked around in 27cc17c39 by raising the reserve to 8 MB.
The array holds the *fill pattern* (the cyclic pad argument), which is
almost always a handful of characters, so the LBUF sizing was pure
waste. Cap it at CO_FILL_CHARS_MAX (256); parse_fill_chars already
honors its max_chars argument, so a longer fill simply repeats from the
start at that boundary. co_center's frame drops from ~1.31 MB to ~42 KB
(measured: add $0xa878,%rsp), the bulk now the legitimate 32 KB
fill_buf.
A stack array (not heap or static) is required: color_ops.c is compiled
into the freestanding rv64 JIT blob, which has no malloc and no .bss.
co_reverse's elems[LBUF_SIZE] (512 KB) is left as-is — it is sized to
the input string being reversed (a genuine worst case), not a fill
pattern, and 512 KB stays under the 1 MB reserve.
Regression coverage: center_fn.mux TC007 runs center/ljust/rjust with a
400-character (over-cap) fill and asserts correct output width.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
79fb983903
commit
a7a816ea8e
6 changed files with 88 additions and 43 deletions
Binary file not shown.
|
|
@ -3464,6 +3464,18 @@ typedef struct {
|
|||
co_ColorState color; /* color state at this position */
|
||||
} fill_char_t;
|
||||
|
||||
/*
|
||||
* Maximum distinct fill characters parsed from a fill pattern. The fill
|
||||
* is the cyclic pad argument to center()/ljust()/rjust(), almost always a
|
||||
* handful of characters, so one fill_char_t per LBUF byte was a ~1.25 MB
|
||||
* stack frame for nothing (#818 — instant stack overflow on Windows's
|
||||
* 1 MB default reserve). A pattern with more than this many visible
|
||||
* characters repeats from the start at this boundary. color_ops.c is
|
||||
* compiled into the freestanding rv64 blob, so this must be a stack
|
||||
* array, not a heap or static allocation.
|
||||
*/
|
||||
#define CO_FILL_CHARS_MAX 256
|
||||
|
||||
/*
|
||||
* parse_fill_chars — Pre-process fill pattern into per-character colors.
|
||||
*
|
||||
|
|
@ -3656,9 +3668,9 @@ size_t co_center(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
/* Default to space fill. */
|
||||
|
|
@ -3731,9 +3743,9 @@ size_t co_ljust(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
fchars[0].bytes[0] = ' ';
|
||||
|
|
@ -3797,9 +3809,9 @@ size_t co_rjust(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
fchars[0].bytes[0] = ' ';
|
||||
|
|
@ -5382,13 +5394,13 @@ unsigned char co_dfa_ascii(const unsigned char *p)
|
|||
/* ---- co_render_ascii ---- */
|
||||
|
||||
|
||||
#line 5175 "color_ops.c"
|
||||
#line 5187 "color_ops.c"
|
||||
static const int render_ascii_start = 12;
|
||||
|
||||
static const int render_ascii_en_main = 12;
|
||||
|
||||
|
||||
#line 3915 "color_ops.rl"
|
||||
#line 3927 "color_ops.rl"
|
||||
|
||||
|
||||
size_t co_render_ascii(unsigned char *out,
|
||||
|
|
@ -5402,21 +5414,21 @@ size_t co_render_ascii(unsigned char *out,
|
|||
const unsigned char *wp_end = out + LBUF_SIZE - 1;
|
||||
|
||||
|
||||
#line 5191 "color_ops.c"
|
||||
#line 5203 "color_ops.c"
|
||||
{
|
||||
cs = render_ascii_start;
|
||||
}
|
||||
|
||||
#line 3928 "color_ops.rl"
|
||||
#line 3940 "color_ops.rl"
|
||||
|
||||
#line 5194 "color_ops.c"
|
||||
#line 5206 "color_ops.c"
|
||||
{
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
switch ( cs )
|
||||
{
|
||||
tr0:
|
||||
#line 3900 "color_ops.rl"
|
||||
#line 3912 "color_ops.rl"
|
||||
{
|
||||
/* Run visible code point through tr_ascii DFA for approximation. */
|
||||
if (*mark < 0x80) {
|
||||
|
|
@ -5430,9 +5442,9 @@ tr0:
|
|||
}
|
||||
goto st12;
|
||||
tr7:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
#line 3900 "color_ops.rl"
|
||||
#line 3912 "color_ops.rl"
|
||||
{
|
||||
/* Run visible code point through tr_ascii DFA for approximation. */
|
||||
if (*mark < 0x80) {
|
||||
|
|
@ -5449,7 +5461,7 @@ st12:
|
|||
if ( ++p == pe )
|
||||
goto _test_eof12;
|
||||
case 12:
|
||||
#line 5230 "color_ops.c"
|
||||
#line 5242 "color_ops.c"
|
||||
switch( (*p) ) {
|
||||
case 0u: goto st0;
|
||||
case 224u: goto tr9;
|
||||
|
|
@ -5478,62 +5490,62 @@ st0:
|
|||
cs = 0;
|
||||
goto _out;
|
||||
tr8:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st1;
|
||||
st1:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof1;
|
||||
case 1:
|
||||
#line 5264 "color_ops.c"
|
||||
#line 5276 "color_ops.c"
|
||||
if ( 128u <= (*p) && (*p) <= 191u )
|
||||
goto tr0;
|
||||
goto st0;
|
||||
tr9:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st2;
|
||||
st2:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof2;
|
||||
case 2:
|
||||
#line 5274 "color_ops.c"
|
||||
#line 5286 "color_ops.c"
|
||||
if ( 160u <= (*p) && (*p) <= 191u )
|
||||
goto st1;
|
||||
goto st0;
|
||||
tr10:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st3;
|
||||
st3:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof3;
|
||||
case 3:
|
||||
#line 5284 "color_ops.c"
|
||||
#line 5296 "color_ops.c"
|
||||
if ( 128u <= (*p) && (*p) <= 191u )
|
||||
goto st1;
|
||||
goto st0;
|
||||
tr11:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st4;
|
||||
st4:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof4;
|
||||
case 4:
|
||||
#line 5294 "color_ops.c"
|
||||
#line 5306 "color_ops.c"
|
||||
if ( 128u <= (*p) && (*p) <= 159u )
|
||||
goto st1;
|
||||
goto st0;
|
||||
tr12:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st5;
|
||||
st5:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof5;
|
||||
case 5:
|
||||
#line 5304 "color_ops.c"
|
||||
#line 5316 "color_ops.c"
|
||||
if ( (*p) < 148u ) {
|
||||
if ( 128u <= (*p) && (*p) <= 147u )
|
||||
goto st1;
|
||||
|
|
@ -5551,38 +5563,38 @@ case 6:
|
|||
goto st12;
|
||||
goto st0;
|
||||
tr13:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st7;
|
||||
st7:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof7;
|
||||
case 7:
|
||||
#line 5327 "color_ops.c"
|
||||
#line 5339 "color_ops.c"
|
||||
if ( 144u <= (*p) && (*p) <= 191u )
|
||||
goto st3;
|
||||
goto st0;
|
||||
tr14:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st8;
|
||||
st8:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof8;
|
||||
case 8:
|
||||
#line 5337 "color_ops.c"
|
||||
#line 5349 "color_ops.c"
|
||||
if ( 128u <= (*p) && (*p) <= 191u )
|
||||
goto st3;
|
||||
goto st0;
|
||||
tr15:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st9;
|
||||
st9:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof9;
|
||||
case 9:
|
||||
#line 5347 "color_ops.c"
|
||||
#line 5359 "color_ops.c"
|
||||
if ( (*p) < 176u ) {
|
||||
if ( 128u <= (*p) && (*p) <= 175u )
|
||||
goto st3;
|
||||
|
|
@ -5600,14 +5612,14 @@ case 10:
|
|||
goto st6;
|
||||
goto st0;
|
||||
tr16:
|
||||
#line 3899 "color_ops.rl"
|
||||
#line 3911 "color_ops.rl"
|
||||
{ mark = p; }
|
||||
goto st11;
|
||||
st11:
|
||||
if ( ++p == pe )
|
||||
goto _test_eof11;
|
||||
case 11:
|
||||
#line 5370 "color_ops.c"
|
||||
#line 5382 "color_ops.c"
|
||||
if ( 128u <= (*p) && (*p) <= 143u )
|
||||
goto st3;
|
||||
goto st0;
|
||||
|
|
@ -5629,7 +5641,7 @@ case 11:
|
|||
_out: {}
|
||||
}
|
||||
|
||||
#line 3929 "color_ops.rl"
|
||||
#line 3941 "color_ops.rl"
|
||||
|
||||
*wp = '\0';
|
||||
return (size_t)(wp - out);
|
||||
|
|
|
|||
|
|
@ -1975,6 +1975,18 @@ typedef struct {
|
|||
co_ColorState color; /* color state at this position */
|
||||
} fill_char_t;
|
||||
|
||||
/*
|
||||
* Maximum distinct fill characters parsed from a fill pattern. The fill
|
||||
* is the cyclic pad argument to center()/ljust()/rjust(), almost always a
|
||||
* handful of characters, so one fill_char_t per LBUF byte was a ~1.25 MB
|
||||
* stack frame for nothing (#818 — instant stack overflow on Windows's
|
||||
* 1 MB default reserve). A pattern with more than this many visible
|
||||
* characters repeats from the start at this boundary. color_ops.c is
|
||||
* compiled into the freestanding rv64 blob, so this must be a stack
|
||||
* array, not a heap or static allocation.
|
||||
*/
|
||||
#define CO_FILL_CHARS_MAX 256
|
||||
|
||||
/*
|
||||
* parse_fill_chars — Pre-process fill pattern into per-character colors.
|
||||
*
|
||||
|
|
@ -2167,9 +2179,9 @@ size_t co_center(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
/* Default to space fill. */
|
||||
|
|
@ -2242,9 +2254,9 @@ size_t co_ljust(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
fchars[0].bytes[0] = ' ';
|
||||
|
|
@ -2308,9 +2320,9 @@ size_t co_rjust(unsigned char *out,
|
|||
}
|
||||
|
||||
/* Parse fill into per-character colors. */
|
||||
fill_char_t fchars[LBUF_SIZE];
|
||||
fill_char_t fchars[CO_FILL_CHARS_MAX];
|
||||
size_t fill_width = 0;
|
||||
size_t nfchars = parse_fill_chars(fchars, LBUF_SIZE, fill_buf, flen,
|
||||
size_t nfchars = parse_fill_chars(fchars, CO_FILL_CHARS_MAX, fill_buf, flen,
|
||||
&fill_width);
|
||||
if (fill_width == 0) {
|
||||
fchars[0].bytes[0] = ' ';
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -113,11 +113,30 @@
|
|||
eq(strlen(center(abcdef,xyz)), 0)
|
||||
)=
|
||||
{
|
||||
@log smoke=TC006: center truncation. Succeeded.;
|
||||
@log smoke=TC006: center truncation. Succeeded.
|
||||
},
|
||||
{
|
||||
@log smoke=TC006: center truncation. Failed (t=[center(abcdef,3)] w0=[center(abcdef,0)] wx=[center(abcdef,xyz)]).
|
||||
}
|
||||
-
|
||||
#
|
||||
# Test Case #7 - Over-cap fill pattern. The fill array is capped at
|
||||
# CO_FILL_CHARS_MAX (256) visible characters to avoid a ~1.25 MB stack
|
||||
# frame (#818). A longer fill must still produce correct-width output
|
||||
# without crashing - center/ljust/rjust here use a 400-character fill.
|
||||
#
|
||||
&tr.tc007 test_center_fn=
|
||||
@if cand(
|
||||
eq(vwidth(center(X,50,[repeat(ab,200)])), 50),
|
||||
eq(vwidth(ljust(X,50,[repeat(ab,200)])), 50),
|
||||
eq(vwidth(rjust(X,50,[repeat(ab,200)])), 50)
|
||||
)=
|
||||
{
|
||||
@log smoke=TC007: justify over-cap fill width. Succeeded.;
|
||||
@trig me/tr.done
|
||||
},
|
||||
{
|
||||
@log smoke=TC006: center truncation. Failed (t=[center(abcdef,3)] w0=[center(abcdef,0)] wx=[center(abcdef,xyz)]).;
|
||||
@log smoke=TC007: justify over-cap fill width. Failed (c=[vwidth(center(X,50,[repeat(ab,200)]))] l=[vwidth(ljust(X,50,[repeat(ab,200)]))] r=[vwidth(rjust(X,50,[repeat(ab,200)]))]).;
|
||||
@trig me/tr.done
|
||||
}
|
||||
-
|
||||
|
|
|
|||
|
|
@ -2017,7 +2017,9 @@
|
|||
>262
|
||||
"@if cand(strmatch(center(1,1,-+), 1),strmatch(center(X,5,-+), -+X+-),strmatch(center(X,7,-+), -+-X-+-))={@log smoke=TC005: Vary string and width with '-+' fill. Succeeded.},{@log smoke=TC005: Vary string and width with '-+' fill. Failed (c2=[center(X,5,-+)] c3=[center(X,7,-+)]).}"
|
||||
>263
|
||||
"@if cand(strmatch(center(abcdef,3), abc),eq(strlen(center(abcdef,0)), 0),eq(strlen(center(abcdef,xyz)), 0))={@log smoke=TC006: center truncation. Succeeded.;@trig me/tr.done},{@log smoke=TC006: center truncation. Failed (t=[center(abcdef,3)] w0=[center(abcdef,0)] wx=[center(abcdef,xyz)]).;@trig me/tr.done}"
|
||||
"@if cand(strmatch(center(abcdef,3), abc),eq(strlen(center(abcdef,0)), 0),eq(strlen(center(abcdef,xyz)), 0))={@log smoke=TC006: center truncation. Succeeded.},{@log smoke=TC006: center truncation. Failed (t=[center(abcdef,3)] w0=[center(abcdef,0)] wx=[center(abcdef,xyz)]).}"
|
||||
>264
|
||||
"@if cand(eq(vwidth(center(X,50,[repeat(ab,200)])), 50),eq(vwidth(ljust(X,50,[repeat(ab,200)])), 50),eq(vwidth(rjust(X,50,[repeat(ab,200)])), 50))={@log smoke=TC007: justify over-cap fill width. Succeeded.;@trig me/tr.done},{@log smoke=TC007: justify over-cap fill width. Failed (c=[vwidth(center(X,50,[repeat(ab,200)]))] l=[vwidth(ljust(X,50,[repeat(ab,200)]))] r=[vwidth(rjust(X,50,[repeat(ab,200)]))]).;@trig me/tr.done}"
|
||||
<
|
||||
!35
|
||||
"test_chaninfo_fn"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue