The process dies with SIGABRT on the first SQL error, and it is the manager
What you see
Connect works. SELECT works. The first statement that fails on the server — a DROP of a
missing table, a typo — kills the process. On macOS it is a bare SIGABRT with nothing on
stderr and no crash report; unixODBC's own isql dies the same way. On Linux the same class
of failure prints:
*** stack smashing detected ***: terminated
Successful statements are unaffected, which is what makes it look like a server problem. It is not. It is the driver manager.
What is actually happening
SQLWCHAR is not one width. unixODBC defines it as two bytes (UTF-16); iODBC defines it as
the platform wchar_t, four bytes, one code point per unit. A driver built to the second
convention and loaded through the first exchanges wide text in the wrong unit size.
The abort is in the diagnostic path. On the first call that returns SQL_ERROR — SQLExecDirect,
SQLPrepare, SQLExecDirectW alike — unixODBC reads the driver's wide diagnostic into a fixed
12-byte stack array, SQLWCHAR sqlstate[6] in extract_diag_error_w (DriverManager/__info.c).
A four-byte driver writes 24 bytes into it, and the stack protector aborts:
frame #0: libsystem_c.dylib`__stack_chk_fail
frame #1: libodbc.2.dylib`extract_diag_error_w(...) at __info.c
frame #2: libodbc.2.dylib`function_return_ex(level=3, ..., ret_code=-1, ...) at __info.c:5215
frame #3: libodbc.2.dylib`SQLExecDirect(...) at SQLExecDirect.c:527
The same program linked against iODBC 3.52.16 gets the proper diagnostics from the same
drivers ([42S02] … SQ074: Line 1: No table no_such_table_xyz) and survives.
How to tell a driver's SQLWCHAR width
Two ways, neither needing the driver's source.
Check what it links. MySQL Connector/ODBC 26.7.1 for macOS arm64 links
@rpath/libiodbcinst.dylib; OpenSearch's macOS package links /usr/lib/libiodbc. A driver
that links an iODBC library is an iODBC-width driver. Relinking it to unixODBC is not a valid
recipe — the widths do not change with the link line.
Or ask it directly. dlopen the driver, run a statement that fails, and call its
SQLGetDiagRecW with a buffer pre-filled with 0xAA. A four-byte driver writes UCS-4 —
5b 00 00 00 4f 00 00 00 … for "[Ope", 5b 00 00 00 41 00 00 00 … for "[Apa" — and
fills BufferLength × 4 bytes.
Related: Vendor macOS drivers are built for iODBC's four-byte SQLWCHAR
Which drivers do this
Three in the compatibility matrix. Virtuoso's macOS driver virtodbcu_r.so (Homebrew 7.2.17,
whose formula has no unixODBC dependency); the Arrow Flight SQL ODBC driver 0.9.7 armv8 build,
which fronts sqlflite, InfluxDB 3 and Dremio; and Actian Ingres 10.1's libiiodbcdriver.1.so
on Linux, whose wide entry points take the platform wchar_t and which joined the matrix
with the seven entries added on 2026-09-03. Neither of the first two documents the width
anywhere.
The Ingres case shows the other half of the same mismatch. unixODBC picks a driver's Unicode
path purely by finding SQLConnectW in it, so with Ingres the connection string arrives as
its first character and the connect fails before any diagnostic is reached:
08004 786744 E_GC0138_GCN_NO_SERVER User provided a server class as part of the
database name (dbname/class), but no servers of that class ... are running in
the target installation
Virtuoso's Linux Unicode build virtodbcu.so is four-byte too: reached through unixODBC's
ANSI entry points, the first failing statement aborts inside libodbc.so.2 with the stack
smashing message above, in a 40-line probe with nothing else in the picture.
What to do
Build your client against iODBC and use those drivers through it. Through an iODBC-built bridge, Flight SQL, InfluxDB 3, Dremio and Virtuoso all pass the compatibility workload on macOS. One client build per driver manager: a unixODBC-built one for unixODBC drivers (psqlodbc, sqliteodbc, the MariaDB connector), an iODBC-built one for these. For Ingres, whose narrow entry points are correct and complete, the matrix loads the driver behind a generated ANSI-only forwarding library of 72 one-jump stubs, so unixODBC does the UCS-2 conversion itself and the driver only ever sees narrow calls.
Keeping unixODBC and never letting a statement fail is not a workaround anyone should ship.
Upstream
Found on 2026-08-25 and reported as
lurcher/unixODBC#239, with a
driver-independent reproduction: a 40-line fake driver compiled with SQL_WCHART_CONVERT
triggers it on Linux, its two-byte twin does not, on 2.3.12 and on 2.3.14 built from the
release tarball; plus lldb frames from two real macOS drivers and a fix suggestion. It is the
same crash as the earlier #227 (Informix), which had been closed without a reproduction.
The issue was closed as not planned on 2026-08-25; the maintainer committed a mismatch check
the same day (a2acae7: doubled buffers, a sentinel test, a message before the abort), so
the crash is now caught rather than silent. A follow-up with a test table and a patch —
report the mismatch as a diagnostic instead of aborting, and prime the sentinel on the ODBC 2
path — was posted on the closed issue. The two drivers' undocumented widths were reported
separately: openlink/virtuoso-opensource#1469
and dremio/warpdrive#16, both open.
Where this comes from: the adbcBridge compatibility matrix runs one workload through every database's ODBC driver on Linux, macOS and Windows and records each failure with its first error; the row for this database is at https://adbcbridge.org/matrix/#virtuoso, and the finding is on file with its reproduction in docs/UPSTREAM.md of the repository.