Every path resolution reaches the app0.zar state, which was a
function-local static: it is destroyed during exit before the handlers
registered ahead of its first use run, so a path resolved in such a
handler locked a destroyed mutex. glibc lets that pass; macOS fails it
with EINVAL, and guest_path_lifetime failed there. The state is now
allocated once and never destroyed, as the working directory state
beside it already is.
A ZArchive named app0.zar beside app0/ is a read-only layer under it. libc opens it at the first path resolution, looks paths missing from app0/ up case-insensitively, reads files across compressed blocks and keeps the archived descriptor table with shared positions.
Resolving an archive-only path through a call that does not read the archive throws instead of failing with ENOENT, as do opendir of a directory present in both places, fdopen of an archived descriptor and chdir into the archive. A path through .. in an archive-only directory resolves.