mpatrol tests: msw apps with user dlls
2003-05-09 Gregory W. Chicares <chicares@mindspring.com>

How should mpatrol be linked to a msw app that's linked to a dll?
That's a pretty common circumstance. For instance, I've got a small
app that uses the wxWindows GUI library. If I change one line of code
in my app, recompiling might take a second or two, but relinking takes
  40   seconds if I link the GUI library statically
   0.8 seconds if I link the GUI library dynamically
and that's a pretty good argument for linking the GUI library
dynamically. But how should the result be linked with mpatrol? Either
or both of the user app and the user dll can be linked with either or
neither a static or dynamic mpatrol library. This document explores
these options and their ramifications for mingw gcc-3.x, with
particular emphasis on a problem using mpatrol with the wxWindows
string class.

Guidance is hard to find, but a web search turned up:

http://www.cbmamiga.demon.co.uk/mpatrol/mpatrol_80.html

  There appears to be a problem when using the mpatrol DLL and the
  static version of the Microsoft C run-time library, and also a
  problem when using the static version of mpatrol and the Microsoft C
  run-time library DLL. Luckily, if you ensure that you use either
  both static libraries or both DLLs at the same time then the problem
  should go away. There doesn't seem to be an easier way around it at
  this time or, for that matter, an explanation for why it happens.

[mingw by its nature always uses the msvc C rtl dll--when building
mpatrol as well as any app that uses mpatrol.]

http://groups.yahoo.com/group/mpatrol/message/450

  > Is it necessary to link every dll
  that is required by an executable with
  > mpatrol.lib (or mpatrolmt.lib) ?

  No, you should only link mpatrol with
  the final executable or with only one
  DLL, otherwise you might get two or
  more sets of mpatrol library functions.

[but see followup comments in the next quoted message]

  You'll get errors if your DLL allocates memory that is freed outwith
  your DLL, and vice versa. mpatrol cannot be extended to detect heap
  errors in other versions of malloc() and free() if they coexist in
  the same process.

[that's the problem I found with the wxWindows string class]

http://groups.yahoo.com/group/mpatrol/message/452

  If you want to make the executable use the mpatrol functions then
  you must link the final executable with the mpatrol library and not
  just the DLL. But ignore what I said in my last email since I've
  found out that Windows DLL binding name resolutions are done at link
  time and not run-time. So it looks like you have to link your DLLs
  with mpatrol as well, but only with the DLL version of the mpatrol
  library and not the static version.

Since that advice has evolved over time, it seems best to consider it
in chronological order as presented above--or so, at least, it appears
in hindsight. But I didn't begin that research until I encountered a
problem. I started along this path:

http://www.cbmamiga.demon.co.uk/mpatrol/mpatrol_43.html

  ...the mpatrol library can usually be incorporated into a program
  using the following commands:
  [...]
  If the mpatrol library was built with support for the GNU BFD object
  file format access library:

    cc -I/usr/local/include <file> -L/usr/local/lib -lmpatrol -lbfd
          -liberty

because I'm using the mingw flavor of gcc (www.mingw.org). Those
directions are really for *nix, but the msvc-specific directions
clearly aren't suitable for this compiler.

Using mpatrol with a small app that uses a wxWindows dll, I got NOTALL
error reports whenever I created a wxString on the stack (wxWindows
uses its own string class, not std::string). It turns out that the
string object maintains internal data on the heap--data that is
allocated with malloc by the ctor (which, being defined out of line,
resides in the dll), but freed by the dtor (which, being defined
inline, resides in the app). Using this dll skeleton
  http://www.neuro.gatech.edu/users/cwilson/cygutils/dll-stuff/
and an enormously simplified variation on class wxString from here
  http://www.wxwindows.org/
I created the simplified test case in this archive.

* Prerequisites

A msw *nix environment specifically including gnu make, such as MSYS
  http://www.mingw.org/msys.shtml
  (don't use the nasty msw CMD.COM or COMMAND.EXE shells)
and gcc-3.x, e.g. from
  http://www.mingw.org

And of course you need static and dynamic mpatrol libraries. The
makefiles assume they're in the current directory. If yours are
elsewhere, change MPATROL_LIB_PATH and MPATROL_DLL_PATH in
GNUmakefile, or specify values on the make command line.

* How to use

GNUmakefile builds and runs the test suite: just type
  make
then look at file 'results', into which the makefile distills the log
file generated for each scenario. That distillation isn't perfect,
for instance because the sed scripts can't reliably parse corrupted
'mpatrol.log' files, so compare your 'results' to 'results-annotated',
which contains my gcc-3.2 results with commentary.

* What the code does

The user exe and the user dll each contain one deliberate error that
mpatrol should ideally catch.

The C++ code for 'usedll.exe' simulates the wxWindows problem noted
above, as described in the next paragraph. There's also a 'nodll.exe'
program that does the same thing, but puts all code in an exe instead
of a user dll. That can be useful for ascertaining whether a problem
might be caused by the presence of a user dll. For instance, one
problem noted below is that 'mpatrol.log' isn't completely written
(its summary is missing) when mpatrol is linked as a dll; this occurs
even with 'nodll.exe', showing that the presence of a user dll is not
the cause of this problem.

Classes sg and sg_base manage memory like wxString and wxStringData.
They serve only to illustrate a problem observed using mpatrol with
wxWindows: a wxString allocated on the stack in an application
linked with a wxWindows dll produces an mpatrol 'NOTALL' error when
the wxString goes out of scope, meaning that mpatrol doesn't know that
memory freed by the application (the inline dtor) was allocated
properly (it was, in the wxWindows dll, but mpatrol doesn't see that
in most scenarios).

* Observations

GNUmakefile runs eight scenarios, creating eight log files and
distilling them into 'results'; here's a manual distillation of
'results', where '*' flags observed defects:

scenario               1   2   3   4   5   6   7   8
link mpatrol to app   --- --- dll dll dll lib lib lib
link mpatrol to dll   dll lib --- dll lib --- dll lib
overlook error in app  *   *           *       *
overlook error in dll          *           *       *
spurious dtor error            *       *   *   *   *
other spurious errors  *       *   *   *       *
mpatrol.log unfinished *   *   *   *   *
mpatrol.log corrupt                    *       *   *

Removing several scenarios that don't merit further consideration:
  discard 1: 2 is uniformly better
  discard 3 and 5: 4 is uniformly better
  discard 8: 6 is uniformly better
leaves:

scenario                   2       4       6   7
link mpatrol to app       ---     dll     lib lib
link mpatrol to dll       lib     dll     --- dll
overlook error in app      *                   *
overlook error in dll                      *
spurious dtor error                        *   *
other spurious errors              *           *
mpatrol.log unfinished     *       *
mpatrol.log corrupt                            *

Comments:

error in app reported if app linked to mpatrol,
  unless dll linked to mpatrol a different way (static vs. dynamic)

error in dll reported if dll linked to mpatrol,
  unless both dll and app linked to mpatrol statically

spurious dtor error avoided only if both app and dll linked to mpatrol
  dynamically (not linking the app to mpatrol at all avoids it, but
  that's only because mpatrol then has no chance to see it)

'other' spurious errors arise whenever mpatrol is linked dynamically
  by either the app or the user dll; they seem to report apparent
  problems with C++ ostreams, and vanish if USE_PRINTF is defined;
  oddly, they appear only with gcc-3.2x, not with gcc-3.1--perhaps
  suggesting that the gcc-3.2x ostream implementation may have a
  problem similar to that observed with the wxWindows string class

mpatrol.log written completely iff app linked to mpatrol statically
  but mpatrol.log corrupted if dll linked to mpatrol too

mpatrol.log corrupt if it's linked to both the app and its dll, unless
  both are linked to mpatrol dynamically

* manifest

README                this file
GNUmakefile           main makefile
Makefile              submakefile--don't use directly
dllclass.cpp          code for user dll
dllclass.hpp          header for user dll
nodll.cpp             code for exe that doesn't depend on user dll
results-annotated     output of GNUmakefile with comments
usedll.cpp            code for exe that depends on user dll

