Skip to content

Fix optimizer crash in JDBC prepare by initializing active_query#1

Closed
thijs-s wants to merge 1 commit into
mainfrom
fix/jdbc-optimizer-active-query
Closed

Fix optimizer crash in JDBC prepare by initializing active_query#1
thijs-s wants to merge 1 commit into
mainfrom
fix/jdbc-optimizer-active-query

Conversation

@thijs-s

@thijs-s thijs-s commented May 15, 2026

Copy link
Copy Markdown

Initialize active_query in ClientContext::PrepareInternal to ensure the optimizer has a valid context during statement preparation. This fixes a null pointer dereference encountered by optimizer extensions when accessing GetCurrentQuery() via the JDBC driver.

The implementation uses a new ActiveQueryGuard RAII helper to ensure strict exception safety and proper resource cleanup.

Initialize `active_query` in `ClientContext::PrepareInternal` to ensure the optimizer has a valid context during statement preparation. This fixes a null pointer dereference encountered by optimizer extensions when accessing `GetCurrentQuery()` via the JDBC driver.

The implementation uses a new `ActiveQueryGuard` RAII helper to ensure strict exception safety and proper resource cleanup.
@thijs-s thijs-s closed this May 15, 2026
thijs-s pushed a commit that referenced this pull request May 22, 2026
In the current implementation, we suffer invalid memory access with the
unit test.
ASAN reports see below
```sh
hjiang@hjiangs-MacBook-Pro$ ./build/debug/test/unittest "[block_allocator]"
Filters: [block_allocator]
[0/1] (0%): BlockAllocator usage and de-allocation on different threads                                                              =================================================================
==23765==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00016f4ff6f8 at pc 0x00010d437368 bp 0x00016f58abf0 sp 0x00016f58abe8
READ of size 8 at 0x00016f4ff6f8 thread T1
    #0 0x00010d437364 in std::__1::unique_ptr<duckdb::BlockQueue, std::__1::default_delete<duckdb::BlockQueue>>::get[abi:ne200100]() const unique_ptr.h:281
    #1 0x00010d2cddd4 in duckdb::unique_ptr<duckdb::BlockQueue, std::__1::default_delete<duckdb::BlockQueue>, false>::operator->() const unique_ptr.hpp:41
    duckdb#2 0x00010d2cd000 in duckdb::BlockAllocatorThreadLocalState::Clear() block_allocator.cpp:141
    duckdb#3 0x00010d434348 in duckdb::BlockAllocatorThreadLocalState::~BlockAllocatorThreadLocalState() block_allocator.cpp:97
    duckdb#4 0x00010d2cb87c in duckdb::BlockAllocatorThreadLocalState::~BlockAllocatorThreadLocalState() block_allocator.cpp:96
    duckdb#5 0x00019527fdc8 in invocation function for block in dyld::ThreadLocalVariables::finalizeList(void*)+0x34 (libdyld.dylib:arm64e+0x3dc8)
```

The root cause is (which is the plain english explanation for the unit
test)
- Assume we have two threads: A and B
- BlockAllocator is created in thread-A, and allocates memory in
thread-B, which means there's one [thread-local
state](https://github.com/duckdb/duckdb/blob/67a0a733f12119424dddee68aed6ad271792ec42/src/storage/block_allocator.cpp#L204)
created in thread-B and records free blocks
- When BlockAllocator is destructed in thread-A, a new thread-local
state will be created and cleared => thread-A's thread-local state is
unchanged
- Now when thread-A destructs, it [attempts to access
BlockAllocator](https://github.com/duckdb/duckdb/blob/67a0a733f12119424dddee68aed6ad271792ec42/src/storage/block_allocator.cpp#L139-L149),
which leads to invalid memory access

In one word, there's no guarantee on lifecycle for BlockAllocator and
threa-local state, this PR simply adds a guard to block possible invalid
access.

BlockAllocator is a [per-db
instance](https://github.com/duckdb/duckdb/blob/67a0a733f12119424dddee68aed6ad271792ec42/src/include/duckdb/main/config.hpp#L175-L176),
so the issue could happen in cases where user creates a DB in one worker
thread and performs query.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant