Opened 10 months ago

Closed 10 months ago

Last modified 10 months ago

#7059 closed defect (fixed)

Debug version of DLL links against wrong runtime library

Reported by: roelv Owned by: warmerdam
Priority: normal Milestone:
Component: ConfigBuild Version: svn-trunk
Severity: normal Keywords:


There is a bug in nmake.opt. The OPTFLAGS for the debug build (i.e., line 135 of trunk on 2017-09-27) has /MD, meaning "link with the release runtime libraries". This causes the class layout of debug builds of the GDAL dll to be different from those when the GDAL header files are included in a project that _uses_ GDAL, and links with /MDd ("link with debug build of runtime libraries").

In particular, std::string is 28 bytes in debug builds, but only 24 in release builds. This in turns causes anything that has a CPLString member (like GDALDataset) to be (subtly) binary incompatible (because CPLString is derived from std::string). More in particular, when you derive a custom class from GDALDataset in your own code (in msvc debug builds), and then cast a pointer to an instance of that class to a GDALDataset*, and *then* pass that pointer into the GDAL dll (like to GDALDataset::SetBand?()), the compiler won't complain because everything seems to work, but the binary layout is interpreted in a different way inside the DLL, causing (almost) unexplainable failures (like, nBlockXSize being interpreted as -1 and hence dataset writes failing, in my case).

This can be demonstrated trivially. Add /d1reportSingleClassLayoutGDALDataset to CXX_ANALYZE_FLAGS in nmake.opt for a GDAL build, and do the same in the "Command line" settings under "C/C++" in the Visual Studio properties of a project using GDAL. Build GDAL and look at the object layout (the offsets in particular), build your own project (which needs to include the GDAL headers obviously) and compare.

The nmake.opt file has been like this for many years, at least 10+ which is when I started using GDAL, probably since the earliest versions. I think this never shows up as a problem because it requires very particular circumstances to manifest itself. The insidious thing is though that it will misbehave silently, potentially causing data corruption - but only in debug builds. But I suspect this is also a change in recent versions of MSVC, otherwise I would've noticed earlier - but I haven't tested versions other than VS2015.

The fix is to change /MD in the debug OPTFLAGS to /MDd.

Change History (3)

comment:1 Changed 10 months ago by Even Rouault

Resolution: duplicate
Status: newclosed

Duplicate of #6384

comment:2 Changed 10 months ago by Even Rouault

I've raised a discussion about that on the mailing list:

comment:3 Changed 10 months ago by Even Rouault

Resolution: duplicatefixed

In 40242:

nmake.opt: use /MDd for OPTFLAGS for DEBUG=1 builds (fixes #7059, fixes #6384, fixes #4291, fixes #3346, fixes #1647, fixes #540)

Note: See TracTickets for help on using tickets.