3

For some time now I've been happily using dlmalloc for a cross-platform project (Windows, Mac OS X, Ubuntu). Recently, however, it seems that using dlmalloc leads to a crash-on-exit on Windows 7.

To make sure that it wasn't something goofy in my project, I created a super-minimal test program-- it doesn't do anything but return from main. One version ("malloctest") links to dlmalloc and the other ("regulartest") doesn't. On WinXP, both run fine. On Windows 7, malloctest crashes. You can see screencasts of the tests here.

My question is: why is this happening? Is it a bug in dlmalloc? Or has the loader in Windows 7 changed? Is there a workaround?

fyi, here is the test code (test.cpp):

#include <stdio.h>

int main() {
    return 0;
}

and here is the nmake makefile:

all: regulartest.exe malloctest.exe

malloctest.exe: malloc.obj test.obj
 link /out:$@ $**

regulartest.exe: test.obj
 link /out:$@ $**

clean:
 del *.exe *.obj

For brevity, I won't include the dlmalloc source in this post, but you can get it (v2.8.4) here.

Edit: See these other relavent SO posts:

Community
  • 1
  • 1
paleozogt
  • 6,393
  • 11
  • 51
  • 94

2 Answers2

2

Looks like a bug in the C runtime. Using Visual Studio 2008 on Windows 7, I reproduced the same problem. After some quick debugging by putting breakpoints in dlmalloc and dlfree, I saw that dlfree was getting called with an address that it never returned earlier from dlmalloc, and then it was hitting an access violation shortly thereafter.

Thankfully, the C runtime's source code is distributed along with VS, so I could see that this call to free was coming from the __endstdio function in _file.c. The corresponding allocation was in __initstdio, and it was calling _calloc_crt to allocate its memory. _calloc_crt calls _calloc_impl, which calls HeapAlloc to get memory. _malloc_crt (used elsewhere in the C runtime, such as to allocate memory for the environment and for argv), on the other hand, calls straight to malloc, and _free_crt calls straight to free.

So, for the memory that gets allocated with _malloc_crt and freed with _free_crt, everything is fine and dandy. But for the memory that gets allocated with _calloc_crt and freed with _free_crt, bad things happen.

I don't know if replacing malloc like this is supported -- if it is, then this is a bug with the CRT. If not, I'd suggest looking into a different C runtime (e.g. MinGW or Cygwin GCC).

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

Using dlmalloc in cross-platform code is an oxymoron. Replacing any standard C functions (especially malloc and family) results in undefined behavior. The closest thing to a portable way to replace malloc is using search-and-replace (not #define; that's also UB) on the source files to call (for example) my_malloc instead of malloc. Note that internal C library functions will still use their standard malloc, so if the two conflict, things will still blow up. Basically, trying to replace malloc is just really misguided. If your system really has a broken malloc implementation (too slow, too much fragmentation, etc.) then you need to do your replacement in an implementation-specific way, and disable the replacement on all systems except ones where you've carefully checked that your implementation-specific replacement works correctly.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    You make it sound like anyone wanting to override malloc is ridiculous. Lots of projects override malloc (see the new SO links in my question). Our project saw some significant speed gains by using dlmalloc. It may be that I've been doing it subtly wrong (as its more difficult to override malloc for msvc than gcc), but its a perfectly valid thing to want to do. – paleozogt Nov 05 '10 at 17:41
  • What's reasonable to say is: "I've tested such-and-such platform and its `malloc` sucks. I've also researched how to replace `malloc` on this platform, and I'm doing it the right way. I've ensured in my build scripts that the `malloc` replacement will not be attempted on any system except the exact configuration I tested it on." What's unreasonable is: "I'm going to assume the system `malloc` always sucks and that my replacement usually works, and only disable my replacement on systems I know have a "good" `malloc`. The latter behavior has a name: it's called **non-portable**. – R.. GitHub STOP HELPING ICE Nov 05 '10 at 18:02
  • 1
    We tested it on Windows XP and its malloc sucks. I researched how to replace malloc on that platform, and I did it the right way. Now we're looking into how to make it work on Windows 7, as the Window XP malloc-overriding technique clearly doesn't work. Do you have an actual answer to my question (how to make it work on Windows 7) or are you just going continue being argumentative? – paleozogt Nov 05 '10 at 18:07
  • I don't have experience with Windows, so no. What I do have experience with is software that simply assumes the standard library is broken and goes about trying to hack in replacements here and there, and then fails to compile or randomly segfaults when I build it on a system that's anything but vanilla GNU/Linux/BSD/Windows. I'm sorry if my answer is unhelpful to you, but I think it's sound advice to others who might be reading your question. – R.. GitHub STOP HELPING ICE Nov 05 '10 at 20:32