Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

609 lines
17 KiB

/*++
Copyright (c) Microsoft Corporation
Module Name:
sxsmain.cpp
Abstract:
Author:
Revision History:
--*/
#include "stdinc.h"
#include <windows.h>
#include "sxsp.h"
#include "fusioneventlog.h"
#include "fusiontrace.h"
#include "fusionsha1.h"
extern CRITICAL_SECTION g_csHashFile;
//
// This typedef of a function represents a dll-main startup function. These are
// called during a DLL_PROCESS_ATTACH call to SxsDllMain in the order they're listed.
//
typedef BOOL (WINAPI *PFNStartupPointer)(
HINSTANCE hDllInstnace,
DWORD dwReason,
PVOID pvReason
);
BOOL WINAPI DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI FusionpEventLogMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI FusionpCryptoContext_DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI DllStartup_AlternateAssemblyStoreRoot(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved);
BOOL WINAPI DllStartup_SetupLog(HINSTANCE Module, DWORD Reason, PVOID Reserved);
BOOL WINAPI DllStartup_FileHashCriticalSectionInitialization(HINSTANCE Module, DWORD Reason, PVOID Reserved);
BOOL WINAPI FusionpAreWeInOSSetupModeMain(HINSTANCE Module, DWORD Reason, PVOID Reserved);
#define MAKE_STARTUP_RECORD(f) { &f, L#f }
#define SXSP_DLLMAIN_ATTACHED 0x01
const struct StartupFunctionRecord {
PFNStartupPointer Handler;
PCWSTR Name;
} g_SxspDllMainStartupPointers[] = {
MAKE_STARTUP_RECORD(DllStartup_CrtInit),
MAKE_STARTUP_RECORD(DllStartup_HeapSetup),
MAKE_STARTUP_RECORD(FusionpEventLogMain),
MAKE_STARTUP_RECORD(DllStartup_AtExitList),
MAKE_STARTUP_RECORD(DllStartup_AlternateAssemblyStoreRoot),
MAKE_STARTUP_RECORD(DllStartup_ActCtxContributors),
MAKE_STARTUP_RECORD(FusionpCryptoContext_DllMain),
MAKE_STARTUP_RECORD(DllStartup_SetupLog),
MAKE_STARTUP_RECORD(DllStartup_FileHashCriticalSectionInitialization),
MAKE_STARTUP_RECORD(FusionpAreWeInOSSetupModeMain)
};
BYTE g_SxspDllMainStartupStatus[NUMBER_OF(g_SxspDllMainStartupPointers)];
HINSTANCE g_hInstance;
/*
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
Replace all SLists with criticalsection and CDeque.
*/
SLIST_HEADER sxspAtExitList;
PCWSTR g_AlternateAssemblyStoreRoot;
BOOL g_WriteRegistryAnyway;
#if DBG
PCSTR
FusionpDllMainReasonToString(DWORD Reason)
{
PCSTR String;
String =
(Reason == DLL_THREAD_ATTACH) ? "DLL_THREAD_ATTACH" :
(Reason == DLL_THREAD_DETACH) ? "DLL_THREAD_DETACH" :
(Reason == DLL_PROCESS_ATTACH) ? "DLL_PROCESS_ATTACH" :
(Reason == DLL_PROCESS_DETACH) ? "DLL_PROCESS_DETACH" :
"";
return String;
}
#endif
extern "C"
BOOL
WINAPI
SxsDllMain(
HINSTANCE hInst,
DWORD dwReason,
PVOID pvReserved
)
//
// We do not call DisableThreadLibraryCalls
// because some/all versions of the CRT do work in the thread calls,
// allocation and free of the per thread data.
//
{
//
// Several "oca" (online crash analysis) bugs show
// Sxs.dll in various places in DllMain(process_detach) in hung apps.
// We load in many processes for oleaut/typelibrary support.
//
// When ExitProcess is called, it is impossible to leak memory and kernel handles,
// so it is sufficient and preferrable to do nothing quickly than to go through
// and free each individual resource.
//
// The pvReserved parameter is actually documented as having a meaning.
// Its NULLness indicates if we are in FreeLibrary or ExitProcess.
//
if (dwReason == DLL_PROCESS_DETACH && pvReserved != NULL)
{
// For ExitProcess, do nothing quickly.
return TRUE;
}
BOOL fResult = FALSE;
SIZE_T nCounter = 0;
#if DBG
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_VERBOSE,
"SXS: 0x%lx.0x%lx, %s() %s\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
__FUNCTION__,
FusionpDllMainReasonToString(dwReason));
#endif
switch (dwReason)
{
case DLL_THREAD_ATTACH:
if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
{
const DWORD dwLastError = ::FusionpGetLastWin32Error();
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
__FUNCTION__,
g_SxspDllMainStartupPointers[0].Name,
dwLastError,
dwLastError);
::SxsDllMain(hInst, DLL_THREAD_DETACH, pvReserved);
::FusionpSetLastWin32Error(dwLastError);
goto Exit;
}
break;
case DLL_THREAD_DETACH:
if (!g_SxspDllMainStartupPointers[0].Handler(hInst, dwReason, pvReserved))
{
const DWORD dwLastError = ::FusionpGetLastWin32Error();
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS: %s - %ls(DLL_THREAD_ATTACH) failed. Last WinError 0x%08x (%d).\n",
__FUNCTION__,
g_SxspDllMainStartupPointers[0].Name,
dwLastError,
dwLastError);
// Eat the error, the loader ignores it.
}
break;
case DLL_PROCESS_ATTACH:
ASSERT_NTC(hInst);
g_hInstance = hInst;
for (nCounter = 0; nCounter != NUMBER_OF(g_SxspDllMainStartupPointers) ; ++nCounter)
{
const SIZE_T nIndex = nCounter;
if (g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
{
g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
}
else
{
const DWORD dwLastError = ::FusionpGetLastWin32Error();
//
// It's a little iffy to set the bit even upon failure, but
// we do this because we assume individual functions do not handle
// rollback internally upon attach failure.
//
g_SxspDllMainStartupStatus[nIndex] |= SXSP_DLLMAIN_ATTACHED;
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS: %s - %ls(DLL_PROCESS_ATTACH) failed. Last WinError 0x%08x (%d).\n",
__FUNCTION__,
g_SxspDllMainStartupPointers[nIndex].Name,
dwLastError,
dwLastError);
// pvReserved has approximately the same defined meaning for attach and detach
::SxsDllMain(hInst, DLL_PROCESS_DETACH, pvReserved);
::FusionpSetLastWin32Error(dwLastError);
goto Exit;
}
}
break;
case DLL_PROCESS_DETACH:
//
// We always succeed DLL_PROCESS_DETACH, and we do not
// short circuit it upon failure. The loader in fact
// ignores what we return.
//
for (nCounter = NUMBER_OF(g_SxspDllMainStartupPointers) ; nCounter != 0 ; --nCounter)
{
const SIZE_T nIndex = nCounter - 1;
if ((g_SxspDllMainStartupStatus[nIndex] & SXSP_DLLMAIN_ATTACHED) != 0)
{
g_SxspDllMainStartupStatus[nIndex] &= ~SXSP_DLLMAIN_ATTACHED;
if (!g_SxspDllMainStartupPointers[nIndex].Handler(hInst, dwReason, pvReserved))
{
const DWORD dwLastError = ::FusionpGetLastWin32Error();
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS: %s - %ls(DLL_PROCESS_DETACH) failed. Last WinError 0x%08x (%d).\n",
__FUNCTION__,
g_SxspDllMainStartupPointers[nIndex].Name,
dwLastError,
dwLastError);
}
}
}
break;
}
fResult = TRUE;
Exit:
return fResult;
}
/*
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
Replace all SLists with criticalsection and CDeque.
*/
BOOL
SxspAtExit(
CCleanupBase* pCleanup
)
{
if (!pCleanup->m_fInAtExitList)
{
SxspInterlockedPushEntrySList(&sxspAtExitList, pCleanup);
pCleanup->m_fInAtExitList = true;
}
return TRUE;
}
/*
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
Replace all SLists with criticalsection and CDeque.
*/
BOOL
SxspTryCancelAtExit(
CCleanupBase* pCleanup
)
{
if (!pCleanup->m_fInAtExitList)
return FALSE;
if (::SxspIsSListEmpty(&sxspAtExitList))
{
pCleanup->m_fInAtExitList = false;
return FALSE;
}
PSLIST_ENTRY pTop = ::SxspInterlockedPopEntrySList(&sxspAtExitList);
if (pTop == pCleanup)
{
pCleanup->m_fInAtExitList = false;
return TRUE;
}
if (pTop != NULL)
::SxspInterlockedPushEntrySList(&sxspAtExitList, pTop);
return FALSE;
}
#define COMMON_HANDLER_PROLOG(dwReason) \
{ \
ASSERT_NTC(\
(dwReason == DLL_PROCESS_ATTACH) || \
(dwReason == DLL_PROCESS_DETACH) \
); \
if (!(\
(dwReason == DLL_PROCESS_ATTACH) || \
(dwReason == DLL_PROCESS_DETACH) \
)) goto Exit; \
}
BOOL WINAPI
DllStartup_AtExitList(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
{
BOOL fSuccess = FALSE;
COMMON_HANDLER_PROLOG(dwReason);
switch (dwReason)
{
case DLL_PROCESS_DETACH:
{
CCleanupBase *pCleanup = NULL;
while (pCleanup = UNCHECKED_DOWNCAST<CCleanupBase*>(SxspPopEntrySList(&sxspAtExitList)))
{
pCleanup->m_fInAtExitList = false;
pCleanup->DeleteYourself();
}
fSuccess = TRUE;
}
break;
case DLL_PROCESS_ATTACH:
::SxspInitializeSListHead(&sxspAtExitList);
fSuccess = TRUE;
break;
}
Exit:
return fSuccess;
}
extern "C"
{
BOOL g_fInCrtInit;
//
// This is the internal CRT routine that does the bulk of
// the initialization and uninitialization.
//
BOOL
WINAPI
_CRT_INIT(
HINSTANCE hDllInstnace,
DWORD dwReason,
PVOID pvReason
);
void
SxspCrtRaiseExit(
PCSTR pszCaller,
int crtError
)
//
// all the various CRT functions that end up calling ExitProcess end up here
// see crt0dat.c
//
{
const static struct
{
NTSTATUS ntstatus;
PCSTR psz;
} rgErrors[] =
{
{ STATUS_FATAL_APP_EXIT, "STATUS_FATAL_APP_EXIT" },
{ STATUS_DLL_INIT_FAILED, "STATUS_DLL_INIT_FAILED" },
};
const ULONG nInCrtInit = g_fInCrtInit ? 1 : 0;
//
// if (!g_fInCrtInit), then throwing STATUS_DLL_INIT_FAILED is dubious,
// but there no clearly good answer, maybe STATUS_NO_MEMORY, maybe introduce
// an NTSTATUS facility to wrap the values in.
//
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS: [0x%lx.0x%lx] %s(crtError:%d, g_fInCrtInit:%s) calling RaiseException(%08lx %s)\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
pszCaller,
crtError,
nInCrtInit ? "true" : "false",
rgErrors[nInCrtInit].ntstatus,
rgErrors[nInCrtInit].psz
);
::RaiseException(
static_cast<DWORD>(rgErrors[nInCrtInit].ntstatus),
0, // flags
0, // number of extra parameters
NULL); // extra parameters
//
// RaiseException returns void, and generally doesn't return, though it
// can if you intervene in a debugger.
//
}
extern void (__cdecl * _aexit_rtn)(int);
void
__cdecl
SxsCrtAExitRoutine(
int crtError
)
//
// This is our replacement for an internal CRT routine that otherwise
// calls ExitProcess.
//
{
SxspCrtRaiseExit(__FUNCTION__, crtError);
}
}
/*
NTRAID#NTBUG9-591174-2002/03/31-JayKrell
It'd be nice if we could just use msvcrt.dll without this hacking..
*/
BOOL WINAPI
DllStartup_CrtInit(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
/*
This mess is because
we need destructors to run, even if there is an exception
the startup code in msvcrt.dll and libcmt.lib is not very good
it tends to call MessageBox and/or ExitProcess upon out of memory
we need it to simply propagate an error
*/
{
#if !FUSION_WIN
//
// having this do-nothing function makes our DLL_THREAD_ATTACH handling simpler.
//
return TRUE;
#else
BOOL fSuccess = FALSE;
DWORD dwExceptionCode = 0;
__try
{
__try
{
g_fInCrtInit = TRUE;
if (dwReason == DLL_PROCESS_ATTACH)
{
_aexit_rtn = SxsCrtAExitRoutine;
//
// __app_type and __error_mode determine if
// _CRT_INIT calls MessageBox or WriteFile(GetStdHandle()) upon errors.
// MessageBox is a big nono in csrss.
// WriteFile we expect to fail, but that's ok, and they don't check
// the return value.
//
// It should be sufficient to set __error_mode.
//
_set_error_mode(_OUT_TO_STDERR);
}
fSuccess = _CRT_INIT(hInstance, dwReason, pvReserved);
}
__finally
{
g_fInCrtInit = FALSE;
}
}
__except(
( (dwExceptionCode = GetExceptionCode()) == STATUS_DLL_INIT_FAILED
|| dwExceptionCode == STATUS_FATAL_APP_EXIT
)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH)
{
}
return fSuccess;
#endif // FUSION_WIN
}
BOOL WINAPI
DllStartup_HeapSetup(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
{
BOOL fSuccess = FALSE;
COMMON_HANDLER_PROLOG(dwReason);
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
fSuccess = FusionpInitializeHeap(hInstance);
break;
case DLL_PROCESS_DETACH:
#if defined(FUSION_DEBUG_HEAP)
::FusionpDumpHeap(L"");
#endif
::FusionpUninitializeHeap();
fSuccess = TRUE;
break;
}
Exit:
return fSuccess;
}
BOOL WINAPI
DllStartup_ActCtxContributors(HINSTANCE hInstance, DWORD dwReason, PVOID pvReserved)
{
BOOL fSuccess = FALSE;
COMMON_HANDLER_PROLOG(dwReason);
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
fSuccess = SxspInitActCtxContributors();
break;
case DLL_PROCESS_DETACH:
SxspUninitActCtxContributors();
fSuccess = TRUE;
break;
}
Exit:
return fSuccess;
}
BOOL
WINAPI
DllStartup_AlternateAssemblyStoreRoot(HINSTANCE, DWORD dwReason, PVOID pvReserved)
{
BOOL fSuccess = FALSE;
COMMON_HANDLER_PROLOG(dwReason);
switch (dwReason)
{
case DLL_PROCESS_DETACH:
if (g_AlternateAssemblyStoreRoot != NULL)
{
CSxsPreserveLastError ple;
delete[] const_cast<PWSTR>(g_AlternateAssemblyStoreRoot);
g_AlternateAssemblyStoreRoot = NULL;
ple.Restore();
}
fSuccess = TRUE;
break;
case DLL_PROCESS_ATTACH:
g_AlternateAssemblyStoreRoot = NULL;
fSuccess = TRUE;
break;
}
Exit:
return fSuccess;
}
BOOL
WINAPI
DllStartup_FileHashCriticalSectionInitialization(
HINSTANCE hInstance,
DWORD dwReason,
PVOID pvReserved
)
{
BOOL fSuccess = FALSE;
//
// We're always called back on disconnect, which isn't really a bug,
// but a different contract that this can't uphold. Instead, we'll
// keep rollback information here about whether or not the csec was
// initialized.
//
static BOOL s_fCritSecCreated;
COMMON_HANDLER_PROLOG(dwReason);
switch (dwReason)
{
case DLL_PROCESS_DETACH:
if (s_fCritSecCreated)
{
::DeleteCriticalSection(&g_csHashFile);
s_fCritSecCreated = FALSE;
}
fSuccess = TRUE;
break;
case DLL_PROCESS_ATTACH:
if (!s_fCritSecCreated)
{
if (!::FusionpInitializeCriticalSection(&g_csHashFile))
goto Exit;
s_fCritSecCreated = TRUE;
}
fSuccess = TRUE;
break;
}
Exit:
return fSuccess;
}