ClickhouseProblem & solution
Memory safety for Postgres extensions in C/C++
Summary
Postgres MemoryContext allocation combined with setjmp/longjmp error handling bypasses C++ destructors, leading to undefined behavior when C++ code runs inside a Postgres extension. C++ exceptions also bypass PG_CATCH, and an uncaught exception in a background worker aborts the process, forcing the postmaster to restart everything due to potential shared memory corruption. ClickHouse’s four Postgres extensions each used a different approach: pg_clickhouse replaced clickhouse-cpp with a new C library, pg_re2 scoped C++ to a single file, pg_chdb isolated libchdb in a helper executable, and pg_stat_ch uses a terminate handler. pg_chdb’s helper process runs outside the Postgres backend, so a libchdb crash fails only the calling operation without triggering cluster crash recovery. A long-term plan for pg_stat_ch moves its C++ dependencies into a helper executable, with PR #129 as the first step to isolate C++ from Postgres code.
Context
ClickHouse’s extensions for Postgres (pg_clickhouse, pg_re2, pg_chdb, pg_stat_ch) each mixed C++ into a C-based Postgres extension. Postgres uses MemoryContext arena allocation with palloc/pfree and setjmp/longjmp for error handling, which can skip C++ destructors and cause undefined behavior. C++ exceptions also bypass PG_CATCH and an uncaught exception aborts the process, potentially forcing postmaster to restart everything.
Takeaways
Postgres’s setjmp/longjmp error handling can skip C++ destructors, leading to undefined behavior when automatic objects with nontrivial destructors exist.
pg_chdb isolates crashes by running libchdb in a separate helper executable via fork+exec, so a crash does not trigger Postgres cluster crash recovery.
pg_stat_ch uses a terminate handler that routes uncaught C++ exceptions through ereport(FATAL) instead of abort(), but this is a mitigation and cannot repair inconsistent shared memory.
FAQ
Why can't C++ exceptions be caught with PG_CATCH?
PG_CATCH is built on setjmp/longjmp and C++ exceptions bypass it; an uncaught C++ exception in a Postgres process leads to an abort. In a background worker this can cause the postmaster to restart everything due to corrupted shared memory.
How does pg_chdb prevent crashes from affecting the Postgres cluster?
pg_chdb runs libchdb in a separate helper executable forked from the backend. A crash in that helper only fails the calling operation without triggering Postgres cluster crash recovery, because postmaster does not manage it as a background worker.
What is the planned long-term hardening for pg_stat_ch?
The long-term plan is to move C++ dependencies into a helper executable, similar to pg_chdb. PR #129 is the first step, isolating C++ in src/exporter with no Postgres dependency and letting bgworker.c handle the C/C++ boundary.
Source and freshness
- Source
- clickhouse.com
- Published
- Added to Yomu
Summaries are generated from the original by a language model. Check the original before relying on it.
Keep reading
Related reading
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.
The best engineering reads, once a week
One useful email. Unsubscribe anytime.