Skip to content

Commit

Permalink
Fix bugzilla issue 24517: druntime tests crash on FreeBSD 14
Browse files Browse the repository at this point in the history
FreeBSD 14 changed the signature of qsort_r to be POSIX-compliant with
POSIX, making it so that our binding for it no longer matches, resulting
in a crash when it's used.

This implements a fix similar to what the FreeBSD headers do to avoid
breaking code (they provide a static inline extern(C++) overload for the
old signature). This provides a deprecated extern(D) overload for the
old signature. The extern(C) overload now matches the new signature. The
changes have been versioned so that they only affect FreeBSD 14 and
newer.

Technically, if someone used Cmp when declaring their function for
qsort_r, this would still break them (though with a compilation error
that should be easy to fix rather than silent breakage or a crash), but
I don't really see a way around that, and Cmp is not part of the POSIX
API, so no one would have a clue that it was a thing without digging
through the bindings. Arguably, we should make it private, since it's
not part of POSIX, but I haven't done anything with that in this commit.
My guess is that in reality, no D programs are both written to use
qsort_r and run on FreeBSD (outside of the druntime tests), but this
way, they won't break unless they use Cmp to declare their comparator
function. They'll just get a deprecation message that they should update
their code.

Regardless, we have to change the signature for FreeBSD 14 for it to
work, and this does that.
  • Loading branch information
jmdavis committed Apr 22, 2024
1 parent c09adbb commit df9a56d
Showing 1 changed file with 39 additions and 7 deletions.
46 changes: 39 additions & 7 deletions druntime/src/core/internal/qsort.d
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,49 @@ static if (Glibc_Qsort_R)
}
else version (FreeBSD)
{
alias extern (C) int function(scope void *, scope const void *, scope const void *) Cmp;
extern (C) void qsort_r(scope void *base, size_t nmemb, size_t size, scope void *thunk, Cmp cmp);
import core.sys.freebsd.config : __FreeBSD_version;

extern (C) void[] _adSort(return scope void[] a, TypeInfo ti)
static if (__FreeBSD_version >= 1400000)
{
extern (C) int cmp(scope void* ti, scope const void* p1, scope const void* p2)
alias extern (C) int function(scope const void*, scope const void*, scope void*) Cmp;
extern (C) void qsort_r(scope void* base, size_t nmemb, size_t size, Cmp cmp, scope void* thunk);

// https://cgit.freebsd.org/src/tree/include/stdlib.h?h=stable/14#n350
pragma(mangle, "qsort_r@FBSD_1.0")
private extern (C) void __qsort_r_compat(scope void* base, size_t nmemb, size_t size, scope void* thunk, OldCmp cmp);
alias extern (C) int function(scope void*, scope const void*, scope const void*) OldCmp;

deprecated("In FreeBSD 14, qsort_r's signature was fixed to match POSIX. This extern(D) overload has been " ~
"provided to avoid breaking code, but code should be updated to use the POSIX version.")
extern (D) void qsort_r(scope void* base, size_t nmemb, size_t size, scope void* thunk, OldCmp cmp)
{
return (cast(TypeInfo)ti).compare(p1, p2);
__qsort_r_compat(base, nmemb, size, thunk, cmp);
}

extern (C) void[] _adSort(return scope void[] a, TypeInfo ti)
{
extern (C) int cmp(scope const void* p1, scope const void* p2, scope void* ti)
{
return (cast(TypeInfo)ti).compare(p1, p2);
}
qsort_r(a.ptr, a.length, ti.tsize, &cmp, cast(void*)ti);
return a;
}
}
else
{
alias extern (C) int function(scope void *, scope const void *, scope const void *) Cmp;
extern (C) void qsort_r(scope void* base, size_t nmemb, size_t size, scope void* thunk, Cmp cmp);

extern (C) void[] _adSort(return scope void[] a, TypeInfo ti)
{
extern (C) int cmp(scope void* ti, scope const void* p1, scope const void* p2)
{
return (cast(TypeInfo)ti).compare(p1, p2);
}
qsort_r(a.ptr, a.length, ti.tsize, cast(void*)ti, &cmp);
return a;
}
qsort_r(a.ptr, a.length, ti.tsize, cast(void*)ti, &cmp);
return a;
}
}
else version (DragonFlyBSD)
Expand Down

0 comments on commit df9a56d

Please sign in to comment.