Skip to content

Reducing a regression between two D versions

Vladimir Panteleev edited this page Feb 8, 2019 · 6 revisions

Let's say you have a program that compiles and runs fine on one D version, but segfaults on another.

To start, you'll need to have both D versions installed at the same time. One easy and universal way to do it is to use dvm.

Install dvm and the two D versions. Note that if you have a system-wide install of D, it might conflict with your local ones (the linker may use libphobos2.a from /usr/lib/), so uninstall (or rename the library) if you run into any linking problems.

The test script should look something like this:

#!/bin/bash

# Enable the "errexit" mode, which will cause the shell interpreter to
# exit (with a non-zero status) as soon as any command fails (exits
# with non-zero status). Therefore, any command in this script which
# fails will cause DustMite to consider the reduction it's currently
# trying as not valid.

# This applies to building the D program (the compiler and build tool
# will exit with a non-zero status in case of failure), and running
# the built program (the D runtime will exit with a non-zero status in
# case of an uncaught exception, and the OS will show a non-zero
# status in case of termination by signal, such as a segmentation
# fault).

set -e

# Our test script will need to compile and run the program with both D
# versions. You can't use `dvm use` in a script (it won't affect the
# script's environment), so we'll source DVM's environment scripts
# instead.

source ~/.dvm/env/dmd-2.059

# Build the program with the old compiler version.
# Because -e is set, building is expected to succeed for DustMite to
# consider the current reduction successful.

rdmd --force --build-only program.d

# Run the built program. It is expected to succeed.

./program

# Now, activate the new compiler version.

source ~/.dvm/env/dmd-2.060

# Build the program again, this time with the new compiler version.

# Building and running is split up, to ensure the search is not
# side-tracked by a different segfault somewhere else (i.e. inside the
# compiler).

# As always, when using `rdmd`, don't forget to use `--force`,
# otherwise it may not detect that we're building the program with
# another compiler version.

rdmd --force --build-only program.d

# Run the program, and capture its exit code in a shell variable.

# Because in this example we are looking for specifically a
# segmentation fault, we want to check the exact exit code (rather
# than just checking that it's non-zero).

# Do so by first capturing it in a variable (the way it is done below
# is to make it compatible with the "errexit" mode set above).

status=0
./program || status=$?

# We can now check the captured exit code, and exit the test script
# the appropriate exit code, to tell Dustmite if we've seen the sought
# segfault in the second execution or not.

if [[ $status -eq 139 ]] ; then
    exit 0 # Program built with new compiler segfaulted - good reduction
else
    exit 1 # Program built with new compiler succeeded - bad reduction
fi