Skip to content

RWORK(1) = REAL(LROPT) in z* routines truncates workspace size to float32, causing segfault for N > 2896 #1194

@jberg5

Description

@jberg5

Description

Twelve double-complex (z*) routines store the optimal RWORK size via RWORK(1) = REAL(LROPT). The Fortran REAL() intrinsic returns a float32, but RWORK is declared DOUBLE PRECISION. The f32 intermediate silently truncates integers above 2^24 = 16,777,216 to the nearest representable value, so callers that trust the workspace query allocate too little memory, leading to out-of-bounds writes and segfaults.

Looks like this issue was introduced by ee213a3ed.

Repro:

import ctypes, numpy as np

# Against LAPACK built from current HEAD
lapack = ctypes.CDLL("liblapack.so")

N = 3000
n = ctypes.c_int(N)
jobz = ctypes.c_char(b'V')
uplo = ctypes.c_char(b'U')
lda = ctypes.c_int(N)
info = ctypes.c_int(0)

a = np.zeros((N, N), dtype=np.complex128, order='F')
w = np.zeros(N, dtype=np.float64)
work = np.zeros(1, dtype=np.complex128)
rwork = np.zeros(1, dtype=np.float64)
iwork = np.zeros(1, dtype=np.int32)
lwork = ctypes.c_int(-1)
lrwork = ctypes.c_int(-1)
liwork = ctypes.c_int(-1)

lapack.zheevd_(ctypes.byref(jobz), ctypes.byref(uplo), ctypes.byref(n),
               a.ctypes.data_as(ctypes.c_void_p), ctypes.byref(lda),
               w.ctypes.data_as(ctypes.c_void_p),
               work.ctypes.data_as(ctypes.c_void_p), ctypes.byref(lwork),
               rwork.ctypes.data_as(ctypes.c_void_p), ctypes.byref(lrwork),
               iwork.ctypes.data_as(ctypes.c_void_p), ctypes.byref(liwork),
               ctypes.byref(info))

expected = 1 + 5*N + 2*N**2  # 18,015,001
got = int(rwork[0])           # 18,015,000 (off by 1)

Results at various N:

N=1000: expected=2005001,  got=2005001,  diff=0  ✓
N=2896: expected=16791393, got=16791392, diff=1  ✗
N=3000: expected=18015001, got=18015000, diff=1  ✗
N=5000: expected=50025001, got=50024998, diff=3  ✗

Allocating RWORK with the reported (too-small) size and calling ZHEEVD on actual data produces a segfault due to out-of-bounds writes.
Checklist

  • [ x] I've included a minimal example to reproduce the issue
  • [x ] I'd be willing to make a PR to solve this issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions