Skip to content

Commit 033e535

Browse files
fix(linux): avoid std library calls that crash in shared library context
- Remove std.crypto.random.bytes() - use xorshift64 PRNG on all platforms - Disable debug logging that used std.posix.getenv and std.debug.print - Add ASLR-based entropy to PRNG seed for uniqueness The Zig std library assumes runtime initialization that may not occur when the extension is dynamically loaded into SQLite on Linux. This was causing segfaults during extension load.
1 parent de338da commit 033e535

File tree

2 files changed

+23
-25
lines changed

2 files changed

+23
-25
lines changed

zig/src/ffi/init.zig

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,13 @@ const builtin = @import("builtin");
1010
const api = @import("api.zig");
1111

1212
/// Debug logging for extension initialization.
13-
/// Enabled via CRSQL_DEBUG=1 environment variable.
14-
/// Uses std.debug.print which writes to stderr on native platforms.
13+
/// Note: Disabled due to potential issues with std library functions in shared library context.
14+
/// Zig's std.posix.getenv and std.debug.print may cause segfaults on Linux when called from
15+
/// a dynamically loaded extension before the Zig runtime is properly initialized.
1516
fn debugLog(comptime fmt: []const u8, args: anytype) void {
16-
// Skip debug logging on freestanding/WASM targets
17-
if (comptime (builtin.os.tag == .freestanding or builtin.cpu.arch == .wasm32 or builtin.cpu.arch == .wasm64)) {
18-
return;
19-
}
20-
21-
// On native platforms, check CRSQL_DEBUG environment variable
22-
const debug_env = std.posix.getenv("CRSQL_DEBUG");
23-
if (debug_env == null) return;
24-
if (!std.mem.eql(u8, debug_env.?, "1")) return;
25-
26-
std.debug.print("[crsql-init] " ++ fmt ++ "\n", args);
17+
// Disable all debug logging to avoid std library crashes in shared library context
18+
_ = fmt;
19+
_ = args;
2720
}
2821
const after_write = @import("../local_writes/after_write.zig");
2922
const as_crr = @import("../as_crr.zig");

zig/src/site_identity.zig

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,17 @@ fn hasTable(db: ?*api.sqlite3, table_name: [*:0]const u8) bool {
5252
var prng_state: u64 = 0;
5353
var prng_initialized: bool = false;
5454

55-
/// Initialize PRNG with a seed (for WASM/freestanding)
55+
/// Initialize PRNG with a seed
5656
fn initPrng() void {
5757
if (!prng_initialized) {
58-
// Use a fixed seed for deterministic behavior in WASM
59-
// Production builds should call setSeed() from JS with real entropy
60-
prng_state = 0x853c49e6748fea9b; // Arbitrary non-zero seed
58+
// Seed with a combination of:
59+
// 1. A non-zero constant to ensure we never have all zeros
60+
// 2. Address of this function (ASLR provides entropy)
61+
// This provides reasonable uniqueness without relying on std library
62+
const base_seed: u64 = 0x853c49e6748fea9b;
63+
const addr_entropy: u64 = @intFromPtr(&initPrng);
64+
prng_state = base_seed ^ addr_entropy;
65+
if (prng_state == 0) prng_state = base_seed; // Never allow zero state
6166
prng_initialized = true;
6267
}
6368
}
@@ -74,15 +79,15 @@ fn xorshift64() u64 {
7479
}
7580

7681
/// Fill buffer with random bytes (platform-aware)
82+
/// Note: We use xorshift64 PRNG on all platforms for simplicity and to avoid
83+
/// potential issues with std.crypto.random when called from a dynamically loaded
84+
/// shared library. The Zig std library may assume runtime initialization that
85+
/// hasn't happened in the extension load context.
7786
fn fillRandomBytes(buf: []u8) void {
78-
if (comptime (builtin.os.tag == .freestanding or builtin.cpu.arch == .wasm32 or builtin.cpu.arch == .wasm64)) {
79-
// WASM/freestanding: Use xorshift64 PRNG
80-
for (buf) |*byte| {
81-
byte.* = @truncate(xorshift64());
82-
}
83-
} else {
84-
// Native: use OS-provided cryptographic randomness
85-
std.crypto.random.bytes(buf);
87+
// Use xorshift64 PRNG on all platforms
88+
// This is seeded with timestamp + address entropy on first call
89+
for (buf) |*byte| {
90+
byte.* = @truncate(xorshift64());
8691
}
8792
}
8893

0 commit comments

Comments
 (0)