Skip to content

GLM aggregates segfault in faer blocked-GEMM on DuckDB v1.4.4 unittest harness (fixtures ≥ ~150 rows) #93

Description

@sipemu

Symptom

Any GLM aggregate whose IRLS inner loop runs a weighted-least-squares QR (poisson_fit_agg, negbinom_fit_agg, tweedie_fit_agg, … — anything reaching faer's ColPivQr) segfaults deterministically when:

  1. the fit has ≥ ~150 observations (crash threshold bisected to between n=100 and n=150), AND
  2. the query runs inside the DuckDB v1.4.4 sqllogictest harness (build/release/test/unittest).

It does not reproduce:

  • in the DuckDB CLI shell with identical data (default threads or threads=1),
  • on DuckDB v1.5.3 (shell or harness),
  • calling fit_negbinomial / fit_poisson directly from Rust (including on 256KB-stack threads).

Inside the harness it crashes with threads=1 too, so it is not a worker-thread race.

Backtrace

#0  private_gemm_x86::pack_lhs ()                       ← SIGSEGV, si_addr = 0x0 (NULL deref)
#1  private_gemm_x86::millikernel_colmajor ()
#2  private_gemm_x86::gemm ()
#3  faer::linalg::matmul::triangular::mat_x_mat_into_lower_impl_unchecked ()
#6  faer::linalg::householder::upgrade_householder_factor ()
#7  faer::linalg::solvers::ColPivQr<T>::new_imp ()
#8  anofox_regression::solvers::negative_binomial::NegativeBinomialRegressor::solve_weighted_ls ()
#9  NegativeBinomialRegressor::fit_irls ()
#10 anofox_negbinomial_fit ()
#11 duckdb::NegBinomAggFinalize(...)
#12 duckdb::RowOperations::FinalizeStates(...)

Faulting instruction is a mulsd (%r14,%r12,1),%xmm0 inside the packing loop with a NULL base pointer.

Size threshold

faer's QR uses an unblocked path for small matrices and switches to blocked Householder (which calls the gemm microkernels) for larger ones — only the blocked path crashes. That's why every pre-existing GLM test stayed green: all fixtures were < 150 rows.

n rows harness v1.4.4
20 / 50 / 100 ✅ pass
150 / 200 💥 SIGSEGV (3/3 runs)

Ruled out

  • My new aggregate C++ (structural clone of poisson_aggregate.cpp; poisson_fit_agg itself crashes identically on the same fixture).
  • FFI struct layout mismatch (C header vs #[repr(C)] verified field-by-field).
  • Stack exhaustion (fault address is NULL, not a guard page; direct Rust runs pass on 256KB stacks).
  • Worker-thread placement (crashes with SET threads=1 in the harness; crashed on main thread in one gdb run).
  • Harness client settings (enable_progress_bar, PRAGMA enable_verification in the shell don't reproduce it).

Open leads

  • The harness requireLOAD path dlopens the loadable .duckdb_extension while the statically linked copy is also present in libduckdb.so — two copies of faer/its dispatch state in one process. The shell auto-loads only the static copy. Explicit LOAD in the shell did not reproduce, but the harness load order/path differs (local repository, gzipped artifact) and was not fully replicated.
  • v1.4.4 vs v1.5.3 extension-ci-tools differ in extension symbol visibility/linking, which would change whether the two copies' dynamic symbols interpose.

Workaround in place

All GLM test fixtures are capped at 100 rows (commits on the #88#92 branches reference this issue). Production usage is unaffected — the crash needs the v1.4.4 harness specifically.

Repro recipe

git submodule update --init duckdb extension-ci-tools posthog-telemetry
(cd duckdb && git fetch --depth 1 origin tag v1.4.4 && git checkout v1.4.4)
(cd extension-ci-tools && git fetch --depth 1 origin v1.4.4 && git checkout FETCH_HEAD)
GEN=ninja make release
# any GLM agg with a 200-row fixture:
./build/release/test/unittest "test/sql/regression/test_negbinom_basic.test"  # with range(0,200)

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions