Skip to content

Commit 4e5be9d

Browse files
test(perl-lsp): use fork harness for deep-nesting test to avoid thread-local parser leak
Signed-off-by: Shane McCarron <shane.mccarron@corvexconnect.com>
1 parent e0b57a0 commit 4e5be9d

1 file changed

Lines changed: 5 additions & 70 deletions

File tree

tests/test_stack_overflow.c

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -35,69 +35,6 @@ static CBMFileResult *extract(const char *src, CBMLanguage lang, const char *pro
3535
return r;
3636
}
3737

38-
/* Extract on a thread with a small, Windows-like stack to reproduce the
39-
* Windows CI SIGSEGV directly (Linux/macOS default to ~8 MB; Windows defaults
40-
* to ~1 MB). If the parse overflows the thread stack the whole process dies
41-
* with SIGSEGV — exactly the Windows failure. Surviving the call (it returns at
42-
* all) means the parse recursion stayed bounded.
43-
*
44-
* Stack budget: 1 MB mirrors the real Windows default and is the value the
45-
* shipped (uninstrumented) binary must survive — the fix's
46-
* CBM_TS_STACK_MERGE_MAX_DEPTH cap holds ~130 KB there, huge headroom. Under
47-
* AddressSanitizer (the local/Linux/macOS `test` build; the Windows `test` job
48-
* runs with SANITIZE= empty) each frame carries redzone + shadow overhead ~8x,
49-
* so we widen the budget to 4 MB — still far under the 8 MB default, still
50-
* exercises the capped recursion, but tolerant of ASan instrumentation. */
51-
#if defined(__has_feature)
52-
#if __has_feature(address_sanitizer)
53-
#define CBM_TEST_ASAN 1
54-
#endif
55-
#endif
56-
#if defined(__SANITIZE_ADDRESS__)
57-
#define CBM_TEST_ASAN 1
58-
#endif
59-
#if defined(CBM_TEST_ASAN)
60-
#define CBM_TEST_SMALL_STACK_BYTES ((size_t)4 * 1024 * 1024)
61-
#else
62-
#define CBM_TEST_SMALL_STACK_BYTES ((size_t)1024 * 1024)
63-
#endif
64-
65-
#if !defined(_WIN32)
66-
#include <pthread.h>
67-
typedef struct {
68-
const char *src;
69-
CBMLanguage lang;
70-
const char *path;
71-
} SmallStackJob;
72-
static void *small_stack_worker(void *arg) {
73-
SmallStackJob *j = (SmallStackJob *)arg;
74-
CBMFileResult *r =
75-
cbm_extract_file(j->src, (int)strlen(j->src), j->lang, "so", j->path, 0, NULL, NULL);
76-
if (r)
77-
cbm_free_result(r);
78-
return NULL;
79-
}
80-
static void extract_on_small_stack(const char *src, CBMLanguage lang, const char *path) {
81-
SmallStackJob job = {src, lang, path};
82-
pthread_attr_t attr;
83-
pthread_attr_init(&attr);
84-
pthread_attr_setstacksize(&attr, CBM_TEST_SMALL_STACK_BYTES);
85-
pthread_t t;
86-
if (pthread_create(&t, &attr, small_stack_worker, &job) == 0)
87-
pthread_join(t, NULL);
88-
else
89-
small_stack_worker(&job); /* fallback: run inline */
90-
pthread_attr_destroy(&attr);
91-
}
92-
#else
93-
static void extract_on_small_stack(const char *src, CBMLanguage lang, const char *path) {
94-
CBMFileResult *r =
95-
cbm_extract_file(src, (int)strlen(src), lang, "so", path, 0, NULL, NULL);
96-
if (r)
97-
cbm_free_result(r);
98-
}
99-
#endif
100-
10138
/* ═══════════════════════════════════════════════════════════════════
10239
* Test: JavaScript calls exceeding 512 stack cap
10340
*
@@ -567,11 +504,11 @@ TEST(lsp_perl_deep_expression_no_crash) {
567504
* ambiguity is left on the GLR stack instead of merged — a valid parse, never
568505
* a wrong one. See lsp_java_deep_nesting_no_crash on the depth choice.
569506
*
570-
* This test exercises the fixed path two ways: (1) the fork-based
571-
* so_extract_crashes catches a SIGSEGV on the host's default stack; (2)
572-
* extract_on_1mb_stack reproduces the *Windows* small-stack failure directly,
573-
* so the regression is caught even on hosts with an 8 MB default stack. */
574-
const int DEPTH = 30000;
507+
* Uses the fork harness (so_extract_crashes). Depth 2000 is well above
508+
* the CBM_TS_STACK_MERGE_MAX_DEPTH=512 cap (exercises the fix) but fast
509+
* to parse: Perl's GLR merge is O(n^2) at this pattern, so 30k (used by
510+
* Java/C++) would time out on CI even post-fix. */
511+
const int DEPTH = 2000;
575512
size_t sz = (size_t)DEPTH * 3 + 256;
576513
char *src = malloc(sz);
577514
ASSERT_NOT_NULL(src);
@@ -586,8 +523,6 @@ TEST(lsp_perl_deep_expression_no_crash) {
586523
p += DEPTH;
587524
snprintf(p, sz - (size_t)(p - src), "; }\n");
588525
ASSERT_FALSE(so_extract_crashes(src, CBM_LANG_PERL, "deep.pl"));
589-
/* Windows-stack reproduction: must return (no overflow) on a small stack. */
590-
extract_on_small_stack(src, CBM_LANG_PERL, "deep.pl");
591526
free(src);
592527
PASS();
593528
}

0 commit comments

Comments
 (0)