Skip to content

Windows

Tavis Ormandy edited this page Jul 16, 2019 · 6 revisions

halfempty can be used to minimize testcases of Windows software from within the Windows Subsystem for Linux. You can invoke windows software from within your script, monitor the result and return a status to halfempty.

Follow the standard Linux installation instructions from within the WSL environment.

Example

Detecting crashes with cdb.

First, make sure that cdb.exe is in your path, it's part of the Debugging Tools For Windows, which comes with the Windows SDK.

$ which cdb.exe
/mnt/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/cdb.exe

Now you can write a simple script to call cdb, here is an example:

#!/bin/sh
tmpinput=`mktemp` && cat > ${tmpinput}
wininput=`wslpath -am ${tmpinput}`

tmpoutput=`mktemp`
winoutput=`wslpath -am ${tmpoutput}`

trap 'rm -f ${tmpinput} ${tmpoutput}; exit ${result:=1}' EXIT

# Run your test case, this example exits after the first exception.
cdb.exe -sxd wob -logo "${winoutput}" -c 'g;q' test.exe "${wininput}"

# Search the log for a crash.
if grep -q 'Access violation - code c0000005' ${tmpoutput}; then
    result=0 # Keep this file.
else
    result=1 # No crash.
fi

Let's see this work with a simple test program, this simple c program might crash if the input contains the character 'X'.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char line[1024] = {0};
    FILE *input;

    if (argc != 2)
        return 1;

    input = fopen(argv[1], "r");

    if (input == NULL)
        return 1;

    while (fread(line, 1, sizeof(line) - 1, input) > 0) {
        if (strchr(line, 'X'))
            *(char *)(0) = 'C';
    }

    fclose(input);
    return 0;
}

I just compiled it like this:

cl /nologo test.c

Now run halfempty with the example script above and some sample text.

$ cp /usr/share/dict/words input
$ chmod +x cdbdemo.sh 
$ halfempty cdbdemo.sh input
╭│   │ ── halfempty ───────────────────────────────────────────────── v0.30 ──
╰│  8│ A fast, parallel testcase minimization tool
 ╰───╯ ───────────────────────────────────────────────────────── by @taviso ──

Input file "input" is now 971578 bytes, starting strategy "bisect"...
Verifying the original input executes successfully... (skip with --noverify)
The original input file succeeded after 1.2 seconds.
New finalized size: 971578 (depth=2) real=0.0s, user=0.0s, speedup=~-0.0s
New finalized size: 485789 (depth=5) real=1.4s, user=3.5s, speedup=~2.1s
New finalized size: 242895 (depth=7) real=2.6s, user=6.3s, speedup=~3.7s
New finalized size: 121448 (depth=8) real=3.8s, user=7.5s, speedup=~3.8s
New finalized size: 60725 (depth=11) real=5.2s, user=11.4s, speedup=~6.2s
New finalized size: 30364 (depth=12) real=6.5s, user=12.9s, speedup=~6.4s
New finalized size: 15184 (depth=15) real=7.6s, user=15.8s, speedup=~8.2s
New finalized size: 7594 (depth=16) real=8.1s, user=16.4s, speedup=~8.3s
New finalized size: 3799 (depth=18) real=9.0s, user=18.1s, speedup=~9.1s
New finalized size: 1902 (depth=20) real=9.9s, user=19.8s, speedup=~9.9s
New finalized size: 954 (depth=23) real=10.6s, user=22.2s, speedup=~11.5s
New finalized size: 480 (depth=25) real=11.5s, user=23.8s, speedup=~12.3s
New finalized size: 243 (depth=26) real=12.3s, user=24.6s, speedup=~12.3s
New finalized size: 125 (depth=29) real=13.1s, user=27.0s, speedup=~13.8s
New finalized size: 66 (depth=31) real=13.9s, user=28.7s, speedup=~14.8s
New finalized size: 37 (depth=32) real=14.9s, user=29.7s, speedup=~14.8s
New finalized size: 23 (depth=35) real=15.6s, user=31.8s, speedup=~16.1s
New finalized size: 16 (depth=36) real=16.3s, user=32.6s, speedup=~16.3s
New finalized size: 9 (depth=38) real=17.2s, user=34.2s, speedup=~17.0s
New finalized size: 6 (depth=40) real=18.1s, user=35.9s, speedup=~17.8s
New finalized size: 3 (depth=41) real=18.7s, user=36.7s, speedup=~18.0s
New finalized size: 2 (depth=42) real=19.5s, user=37.4s, speedup=~17.9s
New finalized size: 1 (depth=43) real=20.2s, user=38.0s, speedup=~17.8s
Reached the end of our path through tree, all nodes were finalized
262 nodes failed, 60 worked, 12 discarded, 1 collapsed
168.974 seconds of compute was required for final path

Strategy "bisect" complete, output 1 bytes
Input file "input" is now 1 bytes, starting strategy "zero"...
Verifying the original input executes successfully... (skip with --noverify)
The original input file succeeded after 0.7 seconds.
New finalized size: 1 (depth=2) real=0.0s, user=0.0s, speedup=~-0.0s
Reached the end of our path through tree, all nodes were finalized
0 nodes failed, 1 worked, 0 discarded, 1 collapsed
0.715 seconds of compute was required for final path

Strategy "zero" complete, output 1 bytes
All work complete, generating output halfempty.out (size: 1)
$ uname -r
4.4.0-18362-Microsoft
$ xxd halfempty.out  
00000000: 58                                       X

halfempty correctly found that just the letter 'X' was enough to cause the crash!

Clone this wiki locally