Choosing a C runtime library
Yesterday a developer in my group came by asking about a failure he saw when running the application verifier on his component. The app verifier was reporting that he was using a HEAP_NO_SERIALIZE heap from a thread other than the one that created the heap.
I looked a bit deeper and realized that he was running with the single threaded statically linked C runtime library. An honest mistake, given that it’s the default version of the C runtime library.
You see, there are 3 different versions of the C runtime library shipped (and 3 different versions of the ATL and MFC libraries too).
The first is the statically linked single-threaded library. This one can be used only on single threaded applications, and all the object code for the C runtime library functions used is included in the application binary. You get this with the /ML compiler switch.
The second is the statically linked, multi-threaded library. This one’s the same as the first, but you can use it in a multithreaded application. You get this one with the /MT compiler switch.
The third is the dynamically linked library. This one keeps all the C runtime library code in a separate DLL (MSVCRTxx.DLL). Since the runtime library code’s in a DLL, it also handles multi-threaded issues. The DLL library is enabled with the /MD switch.
But I’ve been wondering. Why on earth would anyone ever choose any option OTHER than multi-threaded DLL version of the runtime library?
There are LOTS of reasons for always using the multithreaded DLL:
1) Your application is smaller because it doesn’t have the C runtime library loaded into it.
2) Because of #1, your application will load faster. The C runtime library is almost certainly in memory, so the pages containing the library don’t have to be read from disk.
3) Using the multithreaded DLL future-proofs your application. If you ever add a second thread to your application (or call into an API that creates multiple threads), you don’t have to remember to change your C runtime library. And unless you’re running the app verifier regularly, the only way you’ll find out about the problem is if you get a heap corruption (if you’re lucky).
4) If your application has multiple DLL’s, then you need to be VERY careful about allocation – each DLL will have its own C runtime library heap, as will the application. If you allocate a block in one DLL, you must free it in the same DLL.
5) If a security bug is ever found in the C runtime library, you don’t have to release an update to your app.
The last one’s probably the most important IMHO. Just to be clear - There haven’t been any security holes found in the C runtime library. But it could happen. And when it happens, it’s pretty ugly. A really good example of this can be seen with the security vulnerability that was found in the zlib compression library. This library was shipped in dozens of products, and every single one of them had to be updated. If you do a google search for “zlib library security vulnerability” you can see some of the chaos that resulted from this disclosure. If your app used the DLL C runtime library, then you’d get the security fix for free from windows update when Microsoft posted the update.
The only arguments I’ve been able to come up with for using the static C runtime libraries are:
1) I don’t have to distribute two binaries with my application – If I use the DLL, I need to redistribute the DLL. This makes my application setup more complicated.
Yes, but not significantly (IMHO). This page lists the redistribution info for the C runtime library and other components.
2) If I statically link to the C runtime library, I avoid DLL hell.
This is a red herring IMHO. Ever since VC6, the C runtime library has been tightly versioned, as long as your installer follows the rules for version checking of redistributable files (found here) you should be ok.
3) My code is faster since the C runtime library doesn’t have to do all that heap synchronization stuff.
Is it really? How much checking is involved in the multithreaded library? Let’s see. The multithreaded library puts some stuff that was kept in global variable in thread local storage. So there’s an extra memory indirection involved on routines like strtok etc. Also, the single threaded library creates it’s heap with HEAP_NO_SERIALIZE (that’s what led to this entire post J). But that just wraps the heap access with an EnterCriticalSection/ExitCriticalSection. Which is very very fast if there’s no contention. And since this is a single threaded application, by definition there’s no contention for the critical section.
Using the multithreaded DLL C runtime library is especially important for systems programmers. First off, if your system component is a DLL, it’s pretty safe to assume that you’ll be called from multiple threads, so at an absolute minimum, you’re going to want to use the multithreaded static C runtime library. And if you’re using the multithreaded static C runtime library, why NOT use the DLL version?
If you’re not writing a DLL, then it’s highly likely that your app does (or will) use multiple threads. Which brings me back to the previous comment – why NOT use the DLL version?
You’re app will be smaller, more secure, future-proof, and no slower than if you don’t.
Comments
Anonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
Um. I've been around long enough. That's why I mentioned "ever since VC6" in my comment. We learned our lesson the hard way.Anonymous
April 29, 2004
msvcrt.dll has come in many versions, and shipped with many products. The DLL Help Database (http://support.microsoft.com/default.aspx?scid=/servicedesks/fileversion/dllinfo.asp) lists 23 versions, and I know that's not complete. Couple that with Visual Basic 6's Package and Deployment Wizard's habit of redistributing whatever's in the Windows directory, and you have something of a nightmare. Thankfully on Windows 2000 and XP this is a protected file (protected with Windows File Protection).
Security Bulletin MS01-060 (http://www.microsoft.com/technet/security/bulletin/ms01-060.mspx) included a patch for format string vulnerabilities in the C runtime.
You're a bit safer with msvcr70.dll or msvcr71.dll. Version 7.0 has only been shipped in two versions, with FoxPro 7.0 and Visual Studio .NET 2002 (and .NET 1.0 SP1), while 7.1 also appears in two versions: with Business Contact Manager and with VS.NET 2003, Windows Server 2003 and .NET 1.1.
These pre-release DLLs (FoxPro 7.0 and Business Contact Manager) are bad practice, IMO. Windows Installer is pretty good at DLL installation issues, anyway, and people should now be using the VC_User_CRT71_RTL_X86_---.msm merge module for shipping the runtime.Anonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
Typically, once Microsoft learns its lessons, it tends to remember them. Check out Michael Grier's weblog (http://weblogs.asp.net/mgrier) for more info on some of the forthcoming technologies to help with versioning.
As to the last thing: When you get right down to it, the nice thing about a 'blog is that I get to say what I feel in it. And I honestly believe that the reasons for not using the DLL version of the C runtime library aren't strong enough to justify not using it.
The two Mikes (Dunn and Dimmick) brought up a couple of VERY valid points - sometimes customers machines are broken, and sometimes apps like foxpro toss trash into the system.
But, as Mike Dimmick points out: If you're using VC6 and the static runtime library, then your app is vulnerable to the bug if it passes user input into the vulnerable function. If you've got the DLL version, then when the fix for MS01-060 is downloaded to your machine, you're likely to be safe.Anonymous
April 29, 2004
"When you get right down to it, the nice thing about a 'blog is that I get to say what I feel in it. "
Absolutely. And the nice thing about it having a comments field at the bottom, is that I can disagree with you in public.
Actually, I don't really disagree with you that there are lots of reasons why dynamically linking the library is better, it's just that there are some good reasons why it can be worse.
I'm afraid 'trust me, we don't repeat our mistakes' might not be enough for me. I like MS a lot (why else would I read your blog?), but some bits of it endlessly re-invent the wheel, often regressing horribly when they do. (Tried MFC programming in a recent version of VS?)
It could be that the calm on the VCRT DLL was largely because it became owned by the OS rather than VS. I know that the VC team are very keen that this doesn't happen again (they've said so on the newsgroups) and it will be interesting to see if they can be trusted to look after it on their own again.
As one of the Mike's said, the 7x.dll's are safer, but building version numbers into filenames hardly seems to be the solution to the world's problems. At one point there was a service pack promised for 7.0, though I don't suppose this is actually going to appear now - would there have been a new DLL name for that?Anonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
The comment has been removedAnonymous
April 29, 2004
I have to agree with a lot of the commenters here -- shipping dynamically linked to the CRT is undesirable from a support standpoint. You say that it has the advantage of automatically getting security fixes, but that also means the program inherits vulnerabilities if the DLL gets rolled back due to a broken installer. I cause enough bugs by myself; I don't need third party programs introducing more.
There is one major advantage to MSVCRT that hasn't been noted here, though: it avoids allocating a thread local storage (TLS) selector per module. I've had cases where third parties wrote a bunch of plugins that were statically linked, and when my program tried to load them, all of the individual CRT instances consumed all the TLS entries on 98 and modules started failing to load. Global hooks and plugins should generally be dynamically linked for that reason.Anonymous
April 30, 2004
I had totally forgotten about the TLS issues Phaeron. In your case, you'd be better off with the DLL CRT anyway (I really am a one-note song, aren't I), just for working set issues - which can especially be significant on W98.Anonymous
April 30, 2004
There are several interesting reasons to use the shared msvcr*.dll:
1. Page sharing across processes
2. Fewer heaps in each process
3. You need to do this is you pass malloc()d or new-d memory across DLL boundaries
4. The TLS issue
The perf team in MS is who pushes us to use the common C runtime mostly because of 2 - the actual code size issue tends to not be as big an issue as having a bunch of lurking heaps out there. (Also, if you use the process heap, there's hope that someday you'll be able to allocate memory in DLL_PROCESS_ATTACH but if you're using a private heap, you're forever subject to the deadlocks that happen today.)Anonymous
May 03, 2004
The comment has been removedAnonymous
May 06, 2004
The only problem right now is that the merge modules for the C++ runtime for VC2003 is broken[1], which forces me to link statically.
Nothing you can do about perhaps, but very unfortunate.
[1] (first posting in thread) http://groups.google.ca/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=023501c30f1b%249baa9fd0%243001280a%40phx.gblAnonymous
May 07, 2004
The comment has been removedAnonymous
July 10, 2004
If you're using the free VC++ Toolkit you don't have the option of using MSVCR71.DLL, because the .lib isn't included and it needs more than just imports.Anonymous
August 07, 2008
PingBack from http://www.lugovskoy.net/?p=59Anonymous
May 31, 2009
PingBack from http://woodtvstand.info/story.php?id=2656Anonymous
June 09, 2009
PingBack from http://weakbladder.info/story.php?id=337Anonymous
June 13, 2009
PingBack from http://thestoragebench.info/story.php?id=4107Anonymous
June 15, 2009
PingBack from http://unemploymentofficeresource.info/story.php?id=258Anonymous
June 19, 2009
PingBack from http://mydebtconsolidator.info/story.php?id=15476