Files
bun-src/test/regression/issue/28632.test.ts
T
2026-08-27 21:09:14 +00:00

88 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// https://github.com/oven-sh/bun/issues/28632
import { SQL } from "bun";
import { beforeAll, expect, test } from "bun:test";
import { describeWithContainer, isASAN, isDebug, isDockerEnabled, rss } from "harness";
if (isDockerEnabled()) {
describeWithContainer(
"issue #28632: MySQL adapter should not leak memory on repeated queries",
{
image: "mysql_plain",
concurrent: true,
},
container => {
let sql: SQL;
beforeAll(async () => {
await container.ready;
sql = new SQL({
url: `mysql://root@${container.host}:${container.port}/bun_sql_test`,
max: 1,
});
});
test("prepared statement re-execution should not leak name_or_index", async () => {
// Create a wide table to amplify the per-column leak signal
await sql`DROP TABLE IF EXISTS leak_test_28632`;
await sql`CREATE TABLE leak_test_28632 (
primary_id VARCHAR(255) PRIMARY KEY,
column_alpha_bravo TEXT, column_charlie_delta TEXT, column_echo_foxtrot TEXT,
column_golf_hotel TEXT, column_india_juliet TEXT, column_kilo_lima TEXT,
column_mike_november TEXT, column_oscar_papa TEXT, column_quebec_romeo TEXT,
column_sierra_tango TEXT, column_uniform_victor TEXT, column_whiskey_xray TEXT,
column_yankee_zulu TEXT, column_one_two_three TEXT, column_four_five_six TEXT,
column_seven_eight TEXT, column_nine_ten TEXT, column_eleven_twelve TEXT,
column_thirteen_fourtn TEXT, column_fifteen_sixtn TEXT, column_seventeen TEXT,
column_eighteen TEXT, column_nineteen TEXT, column_twenty_extra TEXT,
column_twentyone TEXT, column_twentytwo TEXT, column_twentythree TEXT,
column_twentyfour TEXT, column_twentyfive TEXT, column_twentysix TEXT,
column_twentyseven TEXT, column_twentyeight TEXT, column_twentynine TEXT,
column_thirty_extra TEXT, column_thirtyone TEXT, column_thirtytwo TEXT,
column_thirtythree TEXT, column_thirtyfour TEXT, column_thirtyfive TEXT,
column_thirtysix TEXT, column_thirtyseven TEXT, column_thirtyeight TEXT,
column_thirtynine TEXT, column_forty_extra TEXT, column_fortyone TEXT,
column_fortytwo TEXT, column_fortythree TEXT, column_fortyfour TEXT,
column_fortyfive TEXT
)`;
await sql`INSERT INTO leak_test_28632 (primary_id) VALUES ('123')`;
// Warm up to stabilize RSS
for (let i = 0; i < 500; i++) {
await sql`SELECT * FROM leak_test_28632 WHERE primary_id = ${"123"} LIMIT 1`;
}
Bun.gc(true);
await Bun.sleep(50);
const rssAfterWarmup = rss();
// Run queries — each re-decodes 50 column definitions. Collect every 500
// so the RSS delta reflects the name_or_index leak rather than the
// controller's opportunistic-GC cadence (which no longer fires at this
// allocation volume): without this, peak uncollected garbage between
// opportunistic passes commits extra MarkedBlock pages that Bun.gc(true)
// at the end does not synchronously decommit.
for (let i = 0; i < 5000; i++) {
await sql`SELECT * FROM leak_test_28632 WHERE primary_id = ${"123"} LIMIT 1`;
if (i % 500 === 499) Bun.gc(true);
}
Bun.gc(true);
await Bun.sleep(50);
const rssAfterQueries = rss();
const growthMB = (rssAfterQueries - rssAfterWarmup) / 1024 / 1024;
// Without the fix, ~17MB growth (50 leaked name_or_index allocs × 5000 queries).
// With the fix, ~7MB (allocator noise + ASAN shadow memory). Under ASAN the
// Rust global allocator routes every alloc through the interceptor, so the
// per-query free/alloc churn (row cells, etc.) lands in ASAN's 256 MB
// quarantine and shows up as RSS even though nothing leaks — give it 3×
// headroom there. Debug builds enable ASAN by default on Linux/macOS, so
// treat them the same. The non-ASAN bound is what guards the actual
// regression.
expect(growthMB).toBeLessThan(isASAN || isDebug ? 36 : 12);
await sql`DROP TABLE IF EXISTS leak_test_28632`.catch(() => {});
});
},
);
}