Native SIGSEGV in DuckDB JDBC when repeatedly executing queries with window functions and LIMIT 0
- Dominant language
- C++
- Stars
- 127
- Forks
- 80
- Avg merge
- 13h 49m
- Merged PRs (30d)
- 48
Description
### What happens?
Repeatedly executing a query that contains a window function (`RANK() OVER (...)`), an `ORDER BY`, and a `LIMIT 0` causes a native `SIGSEGV` crash in DuckDB JDBC. The JVM process is aborted with exit code 134. The crash occurs in `org.duckdb.DuckDBNative.duckdb_jdbc_execute_pending`.
The crash is reproducible in **both** the `source` mode (single-table query) and the `split` mode (split query), running single-threaded with `threads=1`. Both queries use `LIMIT 0` and should return an empty result set without crashing.
### To Reproduce
### Driver
Use DuckDB JDBC:
```xml
org.duckdb
duckdb_jdbc
1.5.5.1
```
### Reproducer
Save the following as `repro/DuckDBVpCrash1279455Stable.java`:
```java
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* Stable minimized reproducer for the DuckDB JDBC native crash observed in
* hs_err_pid1279455.log from SQLancer's VP split side.
*
* Shape preserved from the crash context:
* - split-side query
* - disabled_optimizers='filter_pushdown,join_order'
* - RANK() OVER (...) over a reconstructed VP relation
* - right side pre-aggregated by row id and joined back
* - ORDER BY ... LIMIT 0
*
* Tested with org.duckdb:duckdb_jdbc:1.5.5.1 on OpenJDK 17.
*/
public final class DuckDBVpCrash1279455Stable {
private static String sourceQuery(String sourceTable) {
return """
SELECT RANK() OVER (ORDER BY vp_rowid, vp_rowid)
FROM %s
ORDER BY vp_rowid
LIMIT 0
""".formatted(sourceTable);
}
private static String splitQuery(String leftTable, String rightTable) {
return """
SELECT RANK() OVER (ORDER BY vp_rowid, vp_rowid)
FROM (
SELECT l.vp_rowid AS vp_rowid, r.c7 AS c7
FROM %s l
JOIN (SELECT vp_rowid, COUNT(*) AS vp_count FROM %s GROUP BY vp_rowid) rg
ON l.vp_rowid = rg.vp_rowid
JOIN %s r
ON r.vp_rowid = rg.vp_rowid
) vp_source
ORDER BY vp_source.vp_rowid
LIMIT 0
""".formatted(leftTable, rightTable, rightTable);
}
private DuckDBVpCrash1279455Stable() {
}
public static void main(String[] args) throws Exception {
int repetitions = args.length == 0 ? 200 : Integer.parseInt(args[0]);
String logId = args.length < 2 ? "1279455" : sanitize(args[1]);
String mode = args.length < 3 ? "split" : args[2].toLowerCase();
if (!mode.equals("source") && !mode.equals("split")) {
throw new IllegalArgumentException("mode must be 'source' or 'split'");
}
boolean sourceOnly = mode.equals("source");
Path databaseFile = Path.of("repro_duckdb" + logId + "_db_min.duckdb").toAbsolutePath();
String sourceTable = "source_" + logId;
String leftTable = "left_" + logId;
String rightTable = "right_" + logId;
Path tempDirectory = Files.createTempDirectory("duckdb-vp-crash-1279455-");
// Start from a fresh, named DuckDB database file so the developer only
// needs to compile and run this JDBC file.
Files.deleteIfExists(databaseFile);
Files.deleteIfExists(Path.of(databaseFile + ".wal"));
try (Connection connection = DriverManager.getConnection("jdbc:duckdb:" + databaseFile);
Statement statement = connection.createStatement()) {
statement.execute("SET threads=1");
statement.execute("SET temp_directory='"
+ tempDirectory.toAbsolutePath().toString().replace("'", "''") + "'");
statement.execute("""
CREATE TABLE %s AS
SELECT i AS vp_rowid,
TIMESTAMP '2000-01-01' + CAST(i AS INTEGER) * INTERVAL '1 second' AS c7
FROM range(100) t(i)
""".formatted(sourceTable));
statement.execute("CREATE TABLE " + leftTable + " AS SELECT vp_rowid FROM " + sourceTable);
statement.execute("CREATE TABLE " + rightTable + " AS SELECT vp_rowid, c7 FROM " + sourceTable);
statement.execute("SET disabled_optimizers='filter_pushdown,join_order'");
String splitQuery = splitQuery(leftTable, rightTable);
String query = sourceOnly ? sourceQuery(sourceTable) : splitQuery;
for (int i = 1; i <= repetitions; i++) {
try (ResultSet resultSet = statement.executeQuery(query)) {
if (resultSet.next()) {
throw new AssertionError("LIMIT 0 query unexpectedly returned a row");
}
}
if (i == 1 || i % 10 == 0) {
System.out.println(mode + " repetitions=" + i);
}
}
System.out.println("completed without native crash");
}
}
private static String sanitize(String value) {
String sanitized = value.replaceAll("[^A-Za-z0-9_]", "_");
return sanitized.isEmpty() ? "1279455" : sanitized;
}
}
```
### Compile
```bash
mkdir -p /tmp/duckdb-vp-repro-classes
javac \
-cp target/lib/duckdb_jdbc-1.5.5.1.jar \
-d /tmp/duckdb-vp-repro-classes \
repro/DuckDBVpCrash1279455Stable.java
```
### Run in `source` mode
```bash
timeout 45s java \
-cp '/tmp/duckdb-vp-repro-classes:target/lib/duckdb_jdbc-1.5.5.1.jar' \
DuckDBVpCrash1279455Stable 200 1279455 source
```
### Run in `split` mode
```bash
timeout 45s java \
-cp '/tmp/duckdb-vp-repro-classes:target/lib/duckdb_jdbc-1.5.5.1.jar' \
DuckDBVpCrash1279455Stable 200 1279455 split
```
Argument meanings:
```text
200 repeat the query 200 times
1279455 log / case id, used to generate database and table names
source run the source query
split run the VP split query
```
The reproducer automatically:
- creates the database file;
- creates the test tables;
- inserts 100 rows of deterministic data;
- sets `threads=1`;
- sets `SET disabled_optimizers='filter_pushdown,join_order'`;
- repeatedly executes the query.
### Actual result
Both `source` and `split` modes cause the JVM to crash inside DuckDB native code:
```text
SIGSEGV (0xb)
Problematic frame:
C [libc.so.6+...]
```
Typical Java stack:
```text
org.duckdb.DuckDBNative.duckdb_jdbc_execute_pending
org.duckdb.DuckDBPreparedStatement.execute
org.duckdb.DuckDBPreparedStatement.executeQuery
DuckDBVpCrash1279455Stable.main
```
Process exit code is typically:
```text
134
```
### Expected result
Because the queries use `LIMIT 0`, they should:
- return an empty result set normally;
- let the Java program exit cleanly;
and should **not** cause:
```text
SIGSEGV
Aborted (core dumped)
JVM native crash
```
### OS:
Ubuntu 20.04.6 LTS, x86_64
### DuckDB Version:
v1.5.5
### DuckDB Client:
Java JDBC
### Hardware:
Intel Xeon Gold 5218R, 80 cores, 1486G RAM
### Full Name:
Annie liu
### Affiliation:
ECNU
### Did you include all relevant configuration (e.g., CPU architecture, Linux distribution) to reproduce the issue?
- [x] Yes, I have
### Did you include all code required to reproduce the issue?
- [x] Yes, I have
### Did you include all relevant data sets for reproducing the issue?
Yes
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by compiling repro/DuckDBVpCrash1279455Stable.java with the provided JDBC jar and run it in both source and split modes. Confirm the repeated LIMIT 0 queries crash in duckdb_jdbc_execute_pending rather than returning an empty result set, then trace the JDBC/native execution path to identify the failure and verify clean completion in both modes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, java, sql
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100