[Issue 17596] dmd d 2.073.2 and 2.074.1 interim generated dmd segfaults on FreeBSD 12-CURRENT

d-bugmail at puremagic.com d-bugmail at puremagic.com
Wed Aug 15 02:31:35 UTC 2018


https://issues.dlang.org/show_bug.cgi?id=17596

Jonathan M Davis <issues.dlang at jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |issues.dlang at jmdavisProg.co
                   |                            |m

--- Comment #20 from Jonathan M Davis <issues.dlang at jmdavisProg.com> ---
(In reply to Vladimir Panteleev from comment #9)
> Alright, so how about:
> 
> - We add getosreldate and INO64_FIRST to druntime
> - We add both the old and new struct definitions
> - We add a stat wrapper which,when getosreldate() < INO64_FIRST, translates
> the old struct to the new struct and returns it.

I tried that with the functions from sys/mount.h that use statfs_t, and it
doesn't work. The problem is that from what I can tell, if you build a program
on FreeBSD 11, it runs just fine on FreeBSD 12 - at least it did with the
functions in sys/mount.h. e.g. When running a program built on FreeBSD 11 on
FreeBSD 12, fstatfs reports the same version with its f_version member that it
does on FreeBSD 11, and it clearly calls the FreeBSD 11 version of fstafs.
objdump confirms this. If you compile a C/C++ program which uses fstatfs on
FreeBSD 12 and use objdump -t on it and grep for fstatfs, it has

00000000002013e0       F *UND*  0000000000000000              fstatfs

whereas if you compile it on FreeBSD 11, you get

0000000000000000       F *UND*  0000000000000011              fstatfs@@FBSD_1.0

Building a D program that does the same thing on FreeBSD 11 also results in

0000000000000000       F *UND*  0000000000000011              fstatfs@@FBSD_1.0

and it still says

0000000000000000       F *UND*  0000000000000011              fstatfs@@FBSD_1.0

if you run objdump on it in FreeBSD 12. And it runs just fine on FreeBSD 12.

If I create a wrapper in druntime so that it uses the FreeBSD 11 version of
stat_t if getosreldate() < INO64_FIRST, then it works just fine on FreeBSD 11
but fails miserably when running that binary on FreeBSD 12, because the binary
has the FreeBSD 11 version of the function in it, and it's the FreeBSD 11
version of stat_t that it's using even though it's running on FreeBSD 12.

So, from what testing I've done thus far, running D binaries built on FreeBSD
11 on FreeBSD 12 works just fine. What fails is when you try to build a program
on FreeBSD 12 (including the compiler). The resulting binary doesn't work
properly if it uses any of the structs that changed, because the definition in
D does not match the definition in C.

It may be that taking a program built on FreeBSD 11 which uses a function like
fstatfs and running it on FreeBSD 12 only works because the OS itself detects
which version of the function your program is built with and therefore calls
the old version of the syscall internally (I don't know), but building a D
program on FreeBSD 11 and running it on 12 seems to work just fine right now,
whereas if you build anything with dmd on FreeBSD 12 where the definition in
druntime does not match the actual FreeBSD 12 definition, then it doesn't work.

So, my conclusion is that the only way to fully fix this is for the struct
definitions to be versioned based on the version of FreeBSD the program is
built on (which would then allow us to do the same thing that C/C++ does and
have versioned headers). And arguably, assuming that there's only one version
of the OS when creating bindings for the OS headers is a terrible idea to begin
with. We only really get away with it like we do because of the fact that most
of them don't change very often.

In any case, all of the extra stuff with detecting the version of FreeBSD at
runtime in D and changing which version of a struct you use based on what
getosreldate() says might make it possible to run a binary built on FreeBSD 12
(with the FreeBSD 12 versions of the structs) on FreeBSD 11 (I don't know), but
it breaks running a FreeBSD 11 binary on FreeBSD 12.

As far as I can tell, we really only have two options:

1. Make it so that dmd actually provides a version identifier for different
versions of FreeBSD (e.g. FreeBSD11 and FreeBSD12) so that we can version the
definitions in druntime just like they would be in the actual C headers (since
FreeBSD 11 gets different headers than FreeBSD 12). That way, we could version
most stuff with FreeBSD like we always have but cleanly cope when definitions
change between versions of FreeBSD by versioning those few symbols with
identifiers such as FreeBSD11 or FreeBSD12.

2. Have a PR where we change all of the struct definitions that differ between
FreeBSD 11 and FreeBSD 12, use a dmd binary built on FreeBSD 11 with the old
code to build it, and then immediately require that everything built with that
version of dmd and newer use FreeBSD 12. That's theoreticaly feasible, but it
could be difficult to make work well with the auto-tester, and it would be
fairly disruptive. This isn't like with Windows where we say that we support
version X, but older versions work well enough for folks to get by during the
transition. It's a distinct point where dmd either works with FreeBSD 11 or
FreeBSD 12 but not both. Without versioning the definitions themselves, we
can't provide a release of dmd that's going to work on both FreeBSD 11 and
FreeBSD 12 even temporarily.

As such, I am strongly inclined to argue that we add version identifiers to D
for FreeBSD11 and FreeBSD12 - either that or some function that provides the
version that the code is being built on which can then be used with static if
instead of version, but that can't be done without compiler support, because
CTFE can't call stuff like getosreldate() or uname().

--


More information about the Digitalmars-d-bugs mailing list