Thursday, April 14, 2016

Fun experiences using Wine in Docker (part 2)

After the last post about running Wine in Docker, it was time to try and actually use the image to perform a build.

The first time I tried, the build crashed due to some sort of exception. It turns out the following sequence of events was to blame:

  • NMAKE, running under wine, loads msvcrt80.dll
  • During its DllMain, this DLL calls _wfindfirst64i32(), passing it the path to Microsoft.VC80.CRT.mainfest
  • Internally, _wfindfirst64i32 will:
    • Call FindFirstFileW which returns a WIN32_FIND_DATAW structure, which includes a FILETIME member for each of creation, last access, and last write times.
    • Pass each of those timestamps to a function that:
      • Calls FileTimeToLocalFileTime to convert it to local time
      • Calls FileTimeToSystemTime to convert it to a SYSTEMTIME structure
      • Passes each member of the SYSTEMTIME structure as arguments to another function, which raises an INVALID_PARAMETER exception (0xC000000D) if the Year argument is not between 1970 and 3000, inclusive

When Docker, using its union filesystem, starts the container, the file access times are zero, which is midnight, 1970-01-01. When this date is converted to local time (in EST timezone, which is UTC-5), the timestamp is five hours before midnight, 1970-01-01, which puts the year at 1969. This caused an exception to be raised whenever NMAKE would run.

The solution was quite simple: Removing /etc/localtime made the system use UTC time, which avoids the problem.

(When I find my notes, I will explain how I leveraged WINE's debugging facilities to track down this very elusive problem.