Couldn't we fix the lackey catastrophe by using #pragma init_seg(user)?


The lackey catastrophe is the nickname I gave to a problem where the lackey hired by the C runtime to destruct global objects runs too late. Specifically, it may run after other DLLs have already shut down, which means that you will have a problem if there is an object whose destructor relies on one of those already-shut-down DLLs.

Commenter ZLB remarked, "One way to fix this would be to use #pragma init_seg(user) to force the object to be constucted last and destructed first."

The init_seg pragma helps control the order in which objects within a module are constructed and destructed. But note the phrase "within a module".

The global variables in a module are constructed in three phases. The "compiler" phase is reserved for the compiler, and its objects construct first. The "lib" phase is intended for libraries (and clearly, in this context, we mean static libraries), and its objects construct next. The "user" phase is intended for application variables, and its objects construct last. (Destruction is in reverse order of construction.)

But all of these phases are internal to the C runtime. They control the order in which the C runtime constructs and destructs objects as part of standard module initialization and termination. But they don't have any effect on when the module as a whole is initialized or terminated.

Suppose you have Super Elite status at an airline, eligible for priority boarding for any flight. You get to the airport for the 4pm flight to San Francisco, and the moment they announce that they are commencing boarding, you saunter up to the gate, flash your Super Elite status badge, and stroll right onto the airplane ahead of everybody else.

That's great and all, but remember: You're all on the same airplane.

Getting Super Elite priority boarding on the 4pm flight to San Francisco won't get you to San Francisco ahead of the 1pm flight. That flight left three hours ago, and in fact it already landed even before you set foot on the airplane.

Using the init_seg pragma lets you tweak the order in which objects are constructed and destructed, relative to other objects in the module. But the issue here is that the module itself is being terminated too late. You're all on the same airplane flight, and that flight takes off too late. Nothing you do with your flight is going to get you there ahead of that other module, because that other module already landed.

A more mundane explanation as to why the init_seg(user) pragma won't help is that init_seg(user) is the default initialization segment. If you don't specify an initialization segment, then you get user. Explicitly asking for user doesn't change anything. That option is provided for completeness.

Comments (9)
  1. Darran Rowe says:

    The one thing that I wonder is in Windows 10, does explorer use the universal crt?
    If I remember correctly, that problem was caused by everything using msvcrt.dll, including kernel32.dll, that caused the crt unload stuff to happen after just about everything.
    If explorer uses the universal crt for its runtime instead of msvcrt, wouldn't this problem be non existent again because ucrtbase.dll would unload much earlier. (Unless of course if kernel32.dll also uses the universal crt.)

    1. Harry Johnston says:

      I don't think that can have been the problem, because unless you're using a dodgy third-party product or a VERY old version of Visual Studio, you don't get linked with msvcrt.dll, you get linked with msvcrtNNN.dll.

        1. Joshua says:

          Link tag on "link to" is corrupted. I only knew it was there because my mobile device highlighted it even though tapping it went nowhere. Link goes to: https://en.wikipedia.org/wiki/MinGW#Programming_language_support

      1. Darran Rowe says:

        Can you say this is true for the internal Windows components and the build process for Windows?
        The thing to remember here is that Windows never shipped with any version of the CRT pre-installed. So on a freshly installed system, there were no files named msvcrNNN.dll available. So that would mean that explorer couldn't run, right? But it is the default shell, so it had to somehow run.
        Anyway, since the gcc compiler that comes with mingw normally linked against msvcrt.dll, are you calling gcc a dodgy third party product?
        Finally, your last sentence is no longer true. Visual Studio 2015 and newer no longer link to a library named msvcrNNN.dll. Probably as an effort to stop so many people from linking against msvcrt.dll, they introduced the universal crt, so new versions of Visual Studio link against ucrtbase.dll.

        1. Harry Johnston says:

          Ah, I misunderstood what you were saying, you're talking about the case where Explorer itself is experiencing the lackey problem. I thought you were talking about third-party applications. Careless reading on my part, sorry.

          MinGW was indeed the dodgy third-party product I was alluding to. Although I should note that the only reason I consider it dodgy is precisely because it links against msvcrt.dll, so I suppose this could be considered a "no true Scotsman" argument. :-)

          And yes, I'm aware that the newer versions of Visual Studio use the uCRT. I thought that could go without saying. The important part of the sentence was "don't get linked with msvcrt.dll".

          1. Ben Voigt (Visual Studio and Development Technologies MVP with C++ focus) says:

            No circular reasoning flaw here.
            It's true that MinGW is dodgy because it uses the dodgy practice of linking to MSVCRT.DLL.
            But circular reasoning only kicks in if the argument that linking to MSVCRT.DLL is dodgy is made because only dodgy software does it. And that's not the argument, because there's a better one. Namely, that Microsoft rather officially said something along the lines of "MSVCRT is for Microsoft and not for thee", but then MinGW went and linked to it anyway. It's the ignoring of the API contract that makes it dodgy.

            (See Raymond's earlier post for links to and explanation of the official statement, which I have only paraphrased https://blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273/)

  2. 640k says:

    Where is the famous time machine? Raymond/ms "official statement" was issued long after applications started to link against msvcrt.dll.

    1. There was no "official statement" because none was needed. msvcrt was never part of the Windows SDK. Anybody who was using it was doing so without any documentation. Do you need to make an official statement that you shouldn't do undocumented things?

Comments are closed.

Skip to main content