You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] Unified backend: af_get_last_error calls unresolved symbol without null check #3713
af_get_last_error in the unified backend calls a function pointer obtained from LOAD_SYMBOL() without checking it for null. When no backend library is loaded — or the symbol cannot be resolved — this is an indirect call through a null pointer.
This is the only use of LOAD_SYMBOL() in the unified backend, and it is unguarded.
} else {
// If false, the error is coming from active backend.typedefvoid (*af_func)(char **, dim_t *);
void *vfn = LOAD_SYMBOL();
af_func func = nullptr;
memcpy(&func, &vfn, sizeof(void *));
func(str, len); // no null check
}
LOAD_SYMBOL() expands to getFunctionPointer(getActiveHandle(), __FUNCTION__), which is GetProcAddress on Windows / dlsym elsewhere. Both return NULL rather than faulting when the handle is NULL or the symbol is absent, so func is NULL and func(str, len) jumps to address 0.
How the else branch is reached
The branch is taken when the unified layer's own error string is empty. That string is thread_local (src/backend/common/err_common.cpp):
and af_get_last_errorclears it after a successful read. So there are several ordinary ways to land in the else branch with no backend loaded:
Calling af_get_last_error twice in a row — the first read consumes and clears the string, the second finds it empty.
Calling it from a different thread than the one that produced the error, since both the string and getActiveHandle() are thread-local.
Calling it defensively before any failing call.
Impact
STATUS_ACCESS_VIOLATION (0xC0000005) with faulting address 0x0000000000000000.
This crash occurs inside the error-reporting path. When backend loading fails, the attempt to retrieve the explanatory message is itself what crashes, so the user never sees "ArrayFire couldn't locate any backends." That is very likely why this class of failure has gone undiagnosed for years in the Rust bindings, whose default error handler calls af_get_last_error on every error:
Activity