BOOL __cdecl __CRTDLL_INIT( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { BOOL term_all = FALSE; if ( dwReason == DLL_PROCESS_ATTACH ) { if ( !_heap_init() ) /* initialize heap */ /* * The heap cannot be initialized, return failure to the * loader. */ return FALSE; if(!_mtinit()) /* initialize multi-thread */ { /* * If the DLL load is going to fail, we must clean up * all resources that have already been allocated. */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail DLL load on failure */ } if (_ioinit() < 0) { _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail DLL load on failure */ } _wcmdln = GetCommandLineW(); #if !defined(_CRT_APP) || defined(_KERNELX) _aenvptr = (char *)__crtGetEnvironmentStringsA(); _acmdln = GetCommandLineA(); #else /* !defined(_CRT_APP) || defined(_KERNELX) */ // We cannot call GetCommandLineA in the App CRT: if (!__copy_to_char(_wcmdln, &_acmdln)) { _acmdln = NULL; } #endif /* !defined(_CRT_APP) || defined(_KERNELX) */ #if !defined(_CRT_APP) || defined(_KERNELX) #ifdef _MBCS /* * Initialize multibyte ctype table. Always done since it is * needed for processing the environment strings. */ __initmbctable(); #endif /* _MBCS */ if (_setenvp() < 0 || /* get environ info */ _cinit(FALSE) != 0) /* do C data initialize */ { term_all = TRUE; } #else /* !defined(_CRT_APP) || defined(_KERNELX) */ if (_cinit(FALSE) != 0) /* do C data initialize */ { term_all = TRUE; } #endif /* !defined(_CRT_APP) || defined(_KERNELX) */ if (term_all) { #if defined(_CRT_APP) && !defined(_KERNELX) _free_crt(_acmdln); _acmdln = NULL; #endif _ioterm(); /* shut down lowio */ _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail DLL load on failure */ } /* * Increment flag indicating process attach notification * has been received. */ proc_attached++; } else if ( dwReason == DLL_PROCESS_DETACH ) { /* * if a client process is detaching, make sure minimal * runtime termination is performed and clean up our * 'locks' (i.e., delete critical sections). */ if ( proc_attached > 0 ) { proc_attached--; __try { /* * Any basic clean-up done here may also need * to be done below if Process Attach is partly * processed and then a failure is encountered. */ if ( _C_Termination_Done == FALSE ) _cexit(); __crtdll_callstaticterminators(); /* Free all allocated CRT memory */ __freeCrtMemory(); #ifdef _DEBUG /* Dump all memory leaks */ if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF) { _CrtSetDumpClient(NULL); _CrtDumpMemoryLeaks(); } #endif /* _DEBUG */ /* * What remains is to clean up the system resources we have * used (handles, critical sections, memory,...,etc.). This * needs to be done if the whole process is NOT terminating. */ /* If dwReason is DLL_PROCESS_DETACH, lpreserved is NULL * if FreeLibrary has been called or the DLL load failed * and non-NULL if the process is terminating. */ if ( lpreserved == NULL ) { #if defined(_CRT_APP) && !defined(_KERNELX) _free_crt(_acmdln); _acmdln = NULL; #endif /* * The process is NOT terminating so we must clean up... */ _ioterm(); /* free TLS index, call _mtdeletelocks() */ _mtterm(); /* This should be the last thing the C run-time does */ _heap_term(); /* heap is now invalid! */ } } __finally { /* we shouldn't really have to care about this, because letting an exception escape from DllMain(DLL_PROCESS_DETACH) should result in process termination. Unfortunately, Windows up to Win7 as of now just silently swallows the exception. I have considered all kinds of tricks, but decided to leave it up to OS folks to fix this. For the time being just remove our FLS callback during phase 2 unwind that would otherwise be left pointing to unmapped address space. */ if ( lpreserved == NULL && __flsindex != FLS_OUT_OF_INDEXES ) _mtterm(); } } else /* no prior process attach, just return */ return FALSE;
/*** *int _cenvarg(argv, envp, argblk, envblk, name) - set up cmd line/environ * *Purpose: * Set up the block forms of the environment and the command line. * If "envp" is null, "_environ" is used instead. * *Entry: * _TSCHAR **argv - argument vector * _TSCHAR **envp - environment vector * _TSCHAR **argblk - pointer to pointer set to malloc'ed space for args * _TSCHAR **envblk - pointer to pointer set to malloc'ed space for env * _TSCHAR *name - name of program being invoked * *Exit: * returns 0 if ok, -1 if fails * stores through argblk and envblk * (calls malloc) * *Exceptions: * *******************************************************************************/ #ifdef WPRFLAG int __cdecl _wcenvarg ( #else /* WPRFLAG */ int __cdecl _cenvarg ( #endif /* WPRFLAG */ const _TSCHAR * const *argv, const _TSCHAR * const *envp, _TSCHAR **argblk, _TSCHAR **envblk, const _TSCHAR *name ) { REG1 const _TSCHAR * const *vp; REG2 unsigned tmp; REG3 _TSCHAR *cptr; unsigned arg_len; unsigned env_len; int cfi_len; /* counts the number of file handles in CFI */ int retval = 0; /* * Null environment pointer "envp" means use global variable, * "_environ" */ int cwd_start; int cwd_end; /* length of "cwd" strings in environment */ _TSCHAR envpfx[] = _T("SystemRoot"); _TSCHAR *envbuf = NULL; int envsize = 0; int defined = 0; /* * Allocate space for command line string * tmp counts the number of bytes in the command line string * including spaces between arguments * An empty string is special -- 2 bytes */ for (vp = argv, tmp = 2; *vp; tmp += (unsigned int)_tcslen(*vp++) + 1) ; arg_len = tmp; /* * Allocate space for the command line plus 2 null bytes */ if ( (*argblk = _calloc_crt(tmp, sizeof(_TSCHAR))) == NULL) { *envblk = NULL; errno = ENOMEM; _doserrno = E_nomem; return(-1); } if (_ERRCHECK_EINVAL(_tdupenv_s_crt(&envbuf, NULL, envpfx)) != 0) { retval = -1; goto error; } envsize = (int)_tcslen(envpfx) + 2; if (envbuf != NULL) { envsize += (int)_tcslen(envbuf); } /* * Allocate space for environment strings * tmp counts the number of bytes in the environment strings * including nulls between strings * Also add "_C_FILE_INFO=" string */ if (envp) for (vp = envp, tmp = 2; *vp; tmp += (unsigned int)_tcslen(*vp++) + 1) ; /* * The _osfile and _osfhnd arrays are passed as binary data in * dospawn.c */ cfi_len = 0; /* no _C_FILE_INFO */ if (!envp) *envblk = NULL; else { /* * Now that we've decided to pass our own environment block, * compute the size of the "current directory" strings to * propagate to the new environment. */ #ifdef WPRFLAG /* * Make sure wide environment exists. */ if (!_wenvptr) { if ((_wenvptr = (wchar_t *)__crtGetEnvironmentStringsW()) == NULL) { retval = -1; goto error; } } #else /* WPRFLAG */ if (!_aenvptr) { if ((_aenvptr = (char *)__crtGetEnvironmentStringsA()) == NULL) { retval = -1; goto error; } } #endif /* WPRFLAG */ /* * search for the first one */ for (cwd_start = 0; _tenvptr[cwd_start] != _T('\0') && _tenvptr[cwd_start] != _T('='); cwd_start += (int)_tcslen(&_tenvptr[cwd_start]) + 1) { } /* find the total size of all contiguous ones */ cwd_end = cwd_start; while (_tenvptr[cwd_end+0] == _T('=') && _tenvptr[cwd_end+1] != _T('\0') && _tenvptr[cwd_end+2] == _T(':') && _tenvptr[cwd_end+3] == _T('=')) { cwd_end += 4 + (int)_tcslen(&_tenvptr[cwd_end+4]) + 1; } tmp += cwd_end - cwd_start; /* * Allocate space for the environment strings plus extra null byte */ env_len = tmp; /* * Check if SystemRoot is already defined in environment provided */ for (vp = envp; *vp; vp++) { if (_tcsncicmp(*vp, envpfx, _tcslen(envpfx)) == 0) { defined = 1; break; } } if (!defined) tmp += envsize; if( !(*envblk = _calloc_crt(tmp, sizeof(_TSCHAR))) ) { _free_crt(*argblk); *argblk = NULL; errno = ENOMEM; _doserrno = E_nomem; retval = -1; goto done; } } /* * Build the command line by concatenating the argument strings * with spaces between, and two null bytes at the end. * NOTE: The argv[0] argument is followed by a null. */ cptr = *argblk; vp = argv; if (!*vp) /* Empty argument list ? */ ++cptr; /* just two null bytes */ else { /* argv[0] must be followed by a null */ _ERRCHECK(_tcscpy_s(cptr, arg_len - (cptr - *argblk), *vp)); cptr += (int)_tcslen(*vp++) + 1; } while( *vp ) { _ERRCHECK(_tcscpy_s(cptr, arg_len - (cptr - *argblk), *vp)); cptr += (int)_tcslen(*vp++); *cptr++ = ' '; } *cptr = cptr[ -1 ] = _T('\0'); /* remove extra blank, add double null */ /* * Build the environment block by concatenating the environment * strings with nulls between and two null bytes at the end */ cptr = *envblk; if (envp != NULL) { /* * Copy the "cwd" strings to the new environment. */ memcpy(cptr, &_tenvptr[cwd_start], (cwd_end - cwd_start) * sizeof(_TSCHAR)); cptr += cwd_end - cwd_start; /* * Copy the environment strings from "envp". */ vp = envp; while( *vp ) { _ERRCHECK(_tcscpy_s(cptr, env_len - (cptr - *envblk), *vp)); cptr += 1 + (int)_tcslen(*vp++); } if (!defined) { /* * Copy SystemRoot to the new environment. */ _ERRCHECK(_tcscpy_s(cptr, envsize, envpfx)); _ERRCHECK(_tcscat_s(cptr, envsize, _T("="))); if (envbuf != NULL) { _ERRCHECK(_tcscat_s(cptr, envsize, envbuf)); } cptr += envsize; } } if (cptr != NULL) { if (cptr == *envblk) { /* * Empty environment block ... this requires two * nulls. */ *cptr++ = _T('\0'); } /* * Extra null terminates the segment */ *cptr = _T('\0'); } goto done; error: _free_crt(*argblk); *argblk = NULL; *envblk = NULL; done: #ifdef WPRFLAG if (_wenvptr) _free_crt(_wenvptr); _wenvptr = NULL; #else /* WPRFLAG */ if (_aenvptr) _free_crt(_aenvptr); _aenvptr = NULL; #endif /* WPRFLAG */ if (envbuf) _free_crt(envbuf); return retval; }
BOOL WINAPI _CRT_INIT( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { unsigned int osplatform = 0; unsigned int winver = 0; unsigned int winmajor = 0; unsigned int winminor = 0; unsigned int osver = 0; /* * Start-up code only gets executed when the process is initialized */ if (dwReason == DLL_PROCESS_ATTACH) { /* * Dynamically allocate the OSVERSIONINFOA buffer, so we avoid * triggering the /GS buffer overrun detection. That can't be * used here, since the guard cookie isn't available until we * initialize it from here! */ OSVERSIONINFOA* posvi = (OSVERSIONINFOA*)HeapAlloc(GetProcessHeap(), 0, sizeof(OSVERSIONINFOA)); if (!posvi) { return FALSE; } /* * Get the full Win32 version */ posvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (!GetVersionExA(posvi)) { HeapFree(GetProcessHeap(), 0, posvi); return FALSE; } osplatform = posvi->dwPlatformId; winmajor = posvi->dwMajorVersion; winminor = posvi->dwMinorVersion; /* * The somewhat bizarre calculations of _osver and _winver are * required for backward compatibility (used to use GetVersion) */ osver = (posvi->dwBuildNumber) & 0x07fff; HeapFree(GetProcessHeap(), 0, posvi); if (osplatform != VER_PLATFORM_WIN32_NT) { osver |= 0x08000; } winver = (winmajor << 8) + winminor; _set_osplatform(osplatform); _set_winver(winver); _set_winmajor(winmajor); _set_winminor(winminor); _set_osver(osver); if (!_heap_init(1)) { /* initialize heap */ return FALSE; /* fail to load DLL */ } if (!_mtinit()) { /* initialize multi-thread */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } /* * Initialize the Runtime Checks stuff */ #ifdef _RTC _RTC_Initialize(); #endif /* _RTC */ _acmdln = (char*)GetCommandLineA(); _aenvptr = (char*)__crtGetEnvironmentStringsA(); if (_ioinit() < 0) { /* initialize lowio */ _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } if (_setargv() < 0 || /* get cmd line info */ _setenvp() < 0 || /* get environ info */ _cinit(FALSE) != 0) { /* do C data initialize, but don't init floating point */ _ioterm(); /* shut down lowio */ _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } /* Enable buffer count checking if linking against static lib */ _CrtSetCheckCount(TRUE); /* * increment flag to indicate process attach notification * has been received */ __proc_attached++; } else if (dwReason == DLL_PROCESS_DETACH) { if (__proc_attached > 0) { __proc_attached--; /* * Any basic clean-up code that goes here must be duplicated * below in _DllMainCRTStartup for the case where the user's * DllMain() routine fails on a Process Attach notification. * This does not include calling user C++ destructors, etc. */ if (_C_Termination_Done == FALSE) { _cexit(); } #ifdef _DEBUG /* Dump all memory leaks */ if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF) { _CrtDumpMemoryLeaks(); } #endif /* _DEBUG */ /* * What remains is to clean up the system resources we have * used (handles, critical sections, memory,...,etc.). This * needs to be done if the whole process is NOT terminating. */ #ifndef _DEBUG if (lpreserved == NULL) { #endif /* _DEBUG */ /* * The process is NOT terminating so we must clean up... */ /* Shut down lowio */ _ioterm(); _mtterm(); /* This should be the last thing the C run-time does */ _heap_term(); /* heap is now invalid! */ #ifndef _DEBUG } #endif /* _DEBUG */ } else /* no prior process attach, just return */ { return FALSE; } } else if (dwReason == DLL_THREAD_ATTACH) { _ptiddata ptd; /* Initialize FlsGetValue function pointer */ __set_flsgetvalue(); if (((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL)) { if (FLS_SETVALUE(__flsindex, (LPVOID)ptd)) { /* * Initialize of per-thread data */ _initptd(ptd, NULL); ptd->_tid = GetCurrentThreadId(); ptd->_thandle = (uintptr_t)(-1); } else { _free_crt(ptd); return FALSE; } } else { return FALSE; } } else if (dwReason == DLL_THREAD_DETACH) { _freeptd(NULL); /* free up per-thread CRT data */ } return TRUE ; }
/*** *int _cenvarg(argv, envp, argblk, envblk, name) - set up cmd line/environ * *Purpose: * Set up the block forms of the environment and the command line. * If "envp" is null, "_environ" is used instead. * File handle info is passed in the environment if _fileinfo is !0. * *Entry: * _TSCHAR **argv - argument vector * _TSCHAR **envp - environment vector * _TSCHAR **argblk - pointer to pointer set to malloc'ed space for args * _TSCHAR **envblk - pointer to pointer set to malloc'ed space for env * _TSCHAR *name - name of program being invoked * *Exit: * returns 0 if ok, -1 if fails * stores through argblk and envblk * (calls malloc) * *Exceptions: * *******************************************************************************/ #ifdef WPRFLAG int __cdecl _wcenvarg ( #else /* WPRFLAG */ int __cdecl _cenvarg ( #endif /* WPRFLAG */ const _TSCHAR * const *argv, const _TSCHAR * const *envp, _TSCHAR **argblk, _TSCHAR **envblk, const _TSCHAR *name ) { REG1 const _TSCHAR * const *vp; REG2 unsigned tmp; REG3 _TSCHAR *cptr; unsigned arg_len; int cfi_len; /* counts the number of file handles in CFI */ /* * Null environment pointer "envp" means use global variable, * "_environ" */ int cwd_start; int cwd_end; /* length of "cwd" strings in environment */ /* * Allocate space for command line string * tmp counts the number of bytes in the command line string * including spaces between arguments * An empty string is special -- 2 bytes */ for (vp = argv, tmp = 2; *vp; tmp += _tcslen(*vp++) + 1) ; arg_len = tmp; /* * Allocate space for the command line plus 2 null bytes */ if ( (*argblk = _malloc_crt(tmp * sizeof(_TSCHAR))) == NULL) { *envblk = NULL; errno = ENOMEM; _doserrno = E_nomem; return(-1); } /* * Allocate space for environment strings * tmp counts the number of bytes in the environment strings * including nulls between strings * Also add "_C_FILE_INFO=" string */ if (envp) for (vp = envp, tmp = 2; *vp; tmp += _tcslen(*vp++) + 1) ; /* * The _osfile and _osfhnd arrays are passed as binary data in * dospawn.c */ cfi_len = 0; /* no _C_FILE_INFO */ if (!envp) *envblk = NULL; else { /* * Now that we've decided to pass our own environment block, * compute the size of the "current directory" strings to * propagate to the new environment. */ #ifdef WPRFLAG /* * Make sure wide environment exists. */ if (!_wenvptr) { if ((_wenvptr = (wchar_t *)__crtGetEnvironmentStringsW()) == NULL) return -1; } #else /* WPRFLAG */ if (!_aenvptr) { if ((_aenvptr = (char *)__crtGetEnvironmentStringsA()) == NULL) return -1; } #endif /* WPRFLAG */ /* * search for the first one */ for (cwd_start = 0; _tenvptr[cwd_start] != _T('\0') && _tenvptr[cwd_start] != _T('='); cwd_start += _tcslen(&_tenvptr[cwd_start]) + 1) { } /* find the total size of all contiguous ones */ cwd_end = cwd_start; while (_tenvptr[cwd_end+0] == _T('=') && _tenvptr[cwd_end+1] != _T('\0') && _tenvptr[cwd_end+2] == _T(':') && _tenvptr[cwd_end+3] == _T('=')) { cwd_end += 4 + _tcslen(&_tenvptr[cwd_end+4]) + 1; } tmp += cwd_end - cwd_start; /* * Allocate space for the environment strings plus extra null byte */ if( !(*envblk = _malloc_crt(tmp * sizeof(_TSCHAR))) ) { _free_crt(*argblk); *argblk = NULL; errno = ENOMEM; _doserrno = E_nomem; return(-1); } } /* * Build the command line by concatenating the argument strings * with spaces between, and two null bytes at the end. * NOTE: The argv[0] argument is followed by a null. */ cptr = *argblk; vp = argv; if (!*vp) /* Empty argument list ? */ ++cptr; /* just two null bytes */ else { /* argv[0] must be followed by a null */ _tcscpy(cptr, *vp); cptr += _tcslen(*vp++) + 1; } while( *vp ) { _tcscpy(cptr, *vp); cptr += _tcslen(*vp++); *cptr++ = ' '; } *cptr = cptr[ -1 ] = _T('\0'); /* remove extra blank, add double null */ /* * Build the environment block by concatenating the environment * strings with nulls between and two null bytes at the end */ cptr = *envblk; if (envp != NULL) { /* * Copy the "cwd" strings to the new environment. */ memcpy(cptr, &_tenvptr[cwd_start], (cwd_end - cwd_start) * sizeof(_TSCHAR)); cptr += cwd_end - cwd_start; /* * Copy the environment strings from "envp". */ vp = envp; while( *vp ) { _tcscpy(cptr, *vp); cptr += 1 + _tcslen(*vp++); } } if (cptr != NULL) { if (cptr == *envblk) { /* * Empty environment block ... this requires two * nulls. */ *cptr++ = _T('\0'); } /* * Extra null terminates the segment */ *cptr = _T('\0'); } #ifdef WPRFLAG _free_crt(_wenvptr); _wenvptr = NULL; #else /* WPRFLAG */ _free_crt(_aenvptr); _aenvptr = NULL; #endif /* WPRFLAG */ return(0); }