diff options
116 files changed, 2188 insertions, 799 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 543e4ffb23..610e929d33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -573,9 +573,7 @@ add_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) endif(WIN32) add_definitions(-DFEATURE_NORM_IDNA_ONLY) add_definitions(-DFEATURE_PREJIT) -if(WIN32) - add_definitions(-DFEATURE_RANDOMIZED_STRING_HASHING) -endif(WIN32) +add_definitions(-DFEATURE_RANDOMIZED_STRING_HASHING) add_definitions(-DFEATURE_READYTORUN) add_definitions(-DFEATURE_STANDALONE_SN) add_definitions(-DFEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED) diff --git a/clr.coreclr.props b/clr.coreclr.props index b47de7b48f..819fd6f829 100644 --- a/clr.coreclr.props +++ b/clr.coreclr.props @@ -101,9 +101,6 @@ <ProfilingSupportedBuild>false</ProfilingSupportedBuild> - <!-- UNIXTODO Enable randomized string hashing --> - <FeatureRandomizedStringHashing>false</FeatureRandomizedStringHashing> - <!-- Windows specific features --> <FeatureWin32Registry>false</FeatureWin32Registry> <FeatureAppX>false</FeatureAppX> @@ -125,4 +122,4 @@ <FeatureCoreFxGlobalization>true</FeatureCoreFxGlobalization> </PropertyGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/cross/arm/tryrun.cmake b/cross/arm/tryrun.cmake index bd84ad75b0..0a6d34d44d 100644 --- a/cross/arm/tryrun.cmake +++ b/cross/arm/tryrun.cmake @@ -90,10 +90,6 @@ SET( UNGETC_NOT_RETURN_EOF_EXITCODE 0 CACHE STRING "Result from TRY_RUN" FORCE) -SET( MALLOC_ZERO_RETURNS_NULL_EXITCODE - 1 - CACHE STRING "Result from TRY_RUN" FORCE) - SET( HAS_POSIX_SEMAPHORES_EXITCODE 0 CACHE STRING "Result from TRY_RUN" FORCE) diff --git a/cross/arm64/tryrun.cmake b/cross/arm64/tryrun.cmake index bd84ad75b0..0a6d34d44d 100644 --- a/cross/arm64/tryrun.cmake +++ b/cross/arm64/tryrun.cmake @@ -90,10 +90,6 @@ SET( UNGETC_NOT_RETURN_EOF_EXITCODE 0 CACHE STRING "Result from TRY_RUN" FORCE) -SET( MALLOC_ZERO_RETURNS_NULL_EXITCODE - 1 - CACHE STRING "Result from TRY_RUN" FORCE) - SET( HAS_POSIX_SEMAPHORES_EXITCODE 0 CACHE STRING "Result from TRY_RUN" FORCE) diff --git a/src/binder/assemblybinder.cpp b/src/binder/assemblybinder.cpp index 3dc1d73e96..ecd34499af 100644 --- a/src/binder/assemblybinder.cpp +++ b/src/binder/assemblybinder.cpp @@ -164,7 +164,7 @@ namespace BINDER_SPACE } else { - PathString fullAssemblyPath; + SString fullAssemblyPath; WCHAR *pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(MAX_LONGPATH); DWORD dwCCFullAssemblyPath = MAX_LONGPATH + 1; // SString allocates extra byte for null. @@ -184,9 +184,6 @@ namespace BINDER_SPACE { assemblyPath.Set(fullAssemblyPath); } - - // Now turn this path into our canonical representation - CanonicalizePath(assemblyPath); } return hr; @@ -1228,17 +1225,9 @@ namespace BINDER_SPACE #ifdef FEATURE_LEGACYNETCF fWindowsPhone7 = RuntimeIsLegacyNetCF(pApplicationContext->GetAppDomainId()) == TRUE; #endif - // - // Windows Phone 7 Quirk: - // - // NetCF allows partial binds to platform assemblies. If we are running a - // Mango application, skip the PKT check if no Ref version is provided, - // since there are apps in the Marketplace that do Assembly.Load("System") - // + if (!tpaListAssembly || (fWindowsPhone7 && tpaListAssembly)) { - dwIncludeFlags |= AssemblyName::EXCLUDE_PUBLIC_KEY_TOKEN_IF_MISSING; - // // On Windows Phone 7, exclude culture comparisons when requesting an uncultured // assembly for app compat reasons (there are main app assemblies with spurious cultures) diff --git a/src/binder/assemblyname.cpp b/src/binder/assemblyname.cpp index f65363de63..a1897e409d 100644 --- a/src/binder/assemblyname.cpp +++ b/src/binder/assemblyname.cpp @@ -568,10 +568,10 @@ Exit: { fEquals = EqualsCaseInsensitive(GetNormalizedCulture(), pAssemblyName->GetNormalizedCulture()); } - if (fEquals && ((dwIncludeFlags & EXCLUDE_PUBLIC_KEY_TOKEN_IF_MISSING) == 0 || - (pAssemblyName->Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN)))) + + if (fEquals && (dwIncludeFlags & INCLUDE_PUBLIC_KEY_TOKEN) != 0) { - fEquals = (GetPublicKeyTokenBLOB().Equals(pAssemblyName->GetPublicKeyTokenBLOB())); + fEquals = (GetPublicKeyTokenBLOB().Equals(pAssemblyName->GetPublicKeyTokenBLOB())); } if (fEquals && ((dwIncludeFlags & INCLUDE_ARCHITECTURE) != 0)) diff --git a/src/binder/cdebuglog.cpp b/src/binder/cdebuglog.cpp index 717fbd2ef9..329d54fcae 100644 --- a/src/binder/cdebuglog.cpp +++ b/src/binder/cdebuglog.cpp @@ -56,7 +56,7 @@ namespace BINDER_SPACE { HRESULT hr=S_OK; LPTSTR pszFileName; - TCHAR szPath[MAX_LONGPATH]; + PathString szPathString; DWORD dw = 0; // _ASSERTE (pszPath ) ; @@ -65,8 +65,12 @@ namespace BINDER_SPACE IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW)); } - IF_FAIL_GO(StringCbCopy(szPath, sizeof(szPath), pszName)); - + size_t pszNameLen = wcslen(pszName); + WCHAR * szPath = szPathString.OpenUnicodeBuffer(static_cast<COUNT_T>(pszNameLen)); + size_t cbSzPath = (sizeof(WCHAR)) * (pszNameLen + 1); // SString allocates extra byte for null + IF_FAIL_GO(StringCbCopy(szPath, cbSzPath, pszName)); + szPathString.CloseBuffer(static_cast<COUNT_T>(pszNameLen)); + pszFileName = PathFindFileName(szPath); if (pszFileName <= szPath) @@ -330,7 +334,6 @@ namespace BINDER_SPACE CombinePath(g_BinderVariables->logPath, sCategory, logFilePath); CombinePath(logFilePath, m_applicationName, logFilePath); CombinePath(logFilePath, m_logFileName, logFilePath); - CanonicalizePath(logFilePath); BINDER_LOG_STRING(L"logFilePath", logFilePath); diff --git a/src/binder/debuglog.cpp b/src/binder/debuglog.cpp index 4f82b7bed9..2c4fd41bfd 100644 --- a/src/binder/debuglog.cpp +++ b/src/binder/debuglog.cpp @@ -90,7 +90,6 @@ namespace BINDER_SPACE kCount2.u.HighPart); PlatformPath(logFilePath); - CanonicalizePath(logFilePath); } fFileExists = (FileOrDirectoryExists(logFilePath) == S_OK); diff --git a/src/binder/inc/assemblyname.hpp b/src/binder/inc/assemblyname.hpp index ac648586e3..474500bc75 100644 --- a/src/binder/inc/assemblyname.hpp +++ b/src/binder/inc/assemblyname.hpp @@ -31,7 +31,7 @@ namespace BINDER_SPACE INCLUDE_ARCHITECTURE = 0x02, INCLUDE_RETARGETABLE = 0x04, INCLUDE_CONTENT_TYPE = 0x08, - EXCLUDE_PUBLIC_KEY_TOKEN_IF_MISSING = 0x10, + INCLUDE_PUBLIC_KEY_TOKEN = 0x10, EXCLUDE_CULTURE = 0x20 } INCLUDE_FLAGS; diff --git a/src/binder/inc/bindertypes.hpp b/src/binder/inc/bindertypes.hpp index 3c4bed4514..6fc4574e0f 100644 --- a/src/binder/inc/bindertypes.hpp +++ b/src/binder/inc/bindertypes.hpp @@ -32,8 +32,6 @@ class PEAssembly; namespace BINDER_SPACE { - typedef InlineSString<MAX_LONGPATH + 1> PathString; - class AssemblyVersion; class AssemblyName; class Assembly; diff --git a/src/binder/utils.cpp b/src/binder/utils.cpp index 5befa8d629..a6a506d937 100644 --- a/src/binder/utils.cpp +++ b/src/binder/utils.cpp @@ -260,37 +260,6 @@ namespace BINDER_SPACE BINDER_LOG_LEAVE(W("Utils::PlatformPath")); } - void CanonicalizePath(SString &path, BOOL fAppendPathSeparator) - { - BINDER_LOG_ENTER(W("Utils::CanonicalizePath")); - BINDER_LOG_STRING(W("input path"), path); - - if (!path.IsEmpty()) - { - WCHAR wszCanonicalPath[MAX_LONGPATH]; - PlatformPath(path); - - // This is also defined in rotor pal - if (PathCanonicalizeW(wszCanonicalPath, path)) - { - path.Set(wszCanonicalPath); - } - - if (fAppendPathSeparator) - { - SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator()); - - if (!path.EndsWith(platformPathSeparator)) - { - path.Append(platformPathSeparator); - } - } - } - - BINDER_LOG_STRING(W("canonicalized path"), path); - BINDER_LOG_LEAVE(W("Utils::CanonicalizePath")); - } - void CombinePath(SString &pathA, SString &pathB, SString &combinedPath) @@ -300,17 +269,16 @@ namespace BINDER_SPACE BINDER_LOG_STRING(W("path A"), pathA); BINDER_LOG_STRING(W("path B"), pathB); - WCHAR tempResultPath[MAX_LONGPATH]; - if (PathCombineW(tempResultPath, pathA, pathB)) - { - combinedPath.Set(tempResultPath); - BINDER_LOG_STRING(W("combined path"), tempResultPath); - } - else + SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator()); + combinedPath.Set(pathA); + + if (!combinedPath.EndsWith(platformPathSeparator)) { - combinedPath.Clear(); + combinedPath.Append(platformPathSeparator); } + combinedPath.Append(pathB); + BINDER_LOG_LEAVE(W("Utils::CombinePath")); } diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp index d5772b2ef5..3f27e07bd7 100644 --- a/src/classlibnative/bcltype/system.cpp +++ b/src/classlibnative/bcltype/system.cpp @@ -24,6 +24,7 @@ #include "classnames.h" #include "system.h" #include "string.h" +#include "sstring.h" #include "eeconfig.h" #include "assemblynative.hpp" #include "generics.h" @@ -288,34 +289,29 @@ FCIMPL0(StringObject*, SystemNative::_GetModuleFileName) { FCALL_CONTRACT; - WCHAR wszFile[MAX_LONGPATH]; - STRINGREF refRetVal = NULL; - LPCWSTR pFileName = NULL; - DWORD lgth = 0; + STRINGREF refRetVal = NULL; + HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); if (g_pCachedModuleFileName) { - pFileName = g_pCachedModuleFileName; - lgth = (DWORD)wcslen(pFileName); + refRetVal = StringObject::NewString(g_pCachedModuleFileName); } else { - HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); - lgth = WszGetModuleFileName(NULL, wszFile, MAX_LONGPATH); + SString wszFilePathString; + + WCHAR * wszFile = wszFilePathString.OpenUnicodeBuffer(MAX_LONGPATH); + DWORD lgth = WszGetModuleFileName(NULL, wszFile, MAX_LONGPATH); if (!lgth) { COMPlusThrowWin32(); } - HELPER_METHOD_FRAME_END(); - pFileName = wszFile; - } + wszFilePathString.CloseBuffer(lgth); - if(lgth) - { - HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); - refRetVal = StringObject::NewString(pFileName, lgth); - HELPER_METHOD_FRAME_END(); + refRetVal = StringObject::NewString(wszFilePathString.GetUnicode()); } + HELPER_METHOD_FRAME_END(); + return (StringObject*)OBJECTREFToObject(refRetVal); } FCIMPLEND @@ -347,14 +343,16 @@ FCIMPL0(StringObject*, SystemNative::GetRuntimeDirectory) { FCALL_CONTRACT; - wchar_t wszFile[MAX_LONGPATH+1]; STRINGREF refRetVal = NULL; DWORD dwFile = MAX_LONGPATH+1; HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal); + SString wszFilePathString; + WCHAR * wszFile = wszFilePathString.OpenUnicodeBuffer(dwFile); HRESULT hr = GetInternalSystemDirectory(wszFile, &dwFile); - + wszFilePathString.CloseBuffer(dwFile); + if(FAILED(hr)) COMPlusThrowHR(hr); diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index 2660e34045..ecf65f2925 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -32,6 +32,7 @@ add_compile_options(-fPIC) set(NATIVEGLOBALIZATION_SOURCES calendarData.cpp casing.cpp + collation.cpp idna.cpp locale.cpp localeNumberData.cpp diff --git a/src/corefx/System.Globalization.Native/collation.cpp b/src/corefx/System.Globalization.Native/collation.cpp new file mode 100644 index 0000000000..ab670264e8 --- /dev/null +++ b/src/corefx/System.Globalization.Native/collation.cpp @@ -0,0 +1,269 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include <assert.h> +#include <stdint.h> +#include <unicode/uchar.h> +#include <unicode/ucol.h> +#include <unicode/usearch.h> +#include <unicode/utf16.h> + +const int32_t CompareOptionsIgnoreCase = 1; +// const int32_t CompareOptionsIgnoreNonSpace = 2; +// const int32_t CompareOptionsIgnoreSymbols = 4; +// const int32_t CompareOptionsIgnoreKanaType = 8; +// const int32_t CompareOptionsIgnoreWidth = 0x10; +// const int32_t CompareOptionsStringSort = 0x20000000; + +/* + * To collator returned by this function is owned by the callee and must be closed when this method returns + * with a U_SUCCESS UErrorCode. + * + * On error, the return value is undefined. + */ +UCollator* GetCollatorForLocaleAndOptions(const char* lpLocaleName, int32_t options, UErrorCode* pErr) +{ + UCollator* pColl = nullptr; + + pColl = ucol_open(lpLocaleName, pErr); + + if ((options & CompareOptionsIgnoreCase) == CompareOptionsIgnoreCase) + { + ucol_setAttribute(pColl, UCOL_STRENGTH, UCOL_SECONDARY, pErr); + } + + return pColl; +} + + +/* +Function: +CompareString +*/ +extern "C" int32_t CompareString(const char* lpLocaleName, const UChar* lpStr1, int32_t cwStr1Length, const UChar* lpStr2, int32_t cwStr2Length, int32_t options) +{ + static_assert(UCOL_EQUAL == 0, "managed side requires 0 for equal strings"); + static_assert(UCOL_LESS < 0, "managed side requires less than zero for a < b"); + static_assert(UCOL_GREATER > 0, "managed side requires greater than zero for a > b"); + + UCollationResult result = UCOL_EQUAL; + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + + if (U_SUCCESS(err)) + { + result = ucol_strcoll(pColl, lpStr1, cwStr1Length, lpStr2, cwStr2Length); + ucol_close(pColl); + } + + return result; +} + +/* +Function: +IndexOf +*/ +extern "C" int32_t IndexOf(const char* lpLocaleName, const UChar* lpTarget, const UChar* lpSource, int32_t cwSourceLength, int32_t options) +{ + static_assert(USEARCH_DONE == -1, "managed side requires -1 for not found"); + + int32_t result = USEARCH_DONE; + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + + if (U_SUCCESS(err)) + { + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, -1, lpSource, cwSourceLength, pColl, nullptr, &err); + + if (U_SUCCESS(err)) + { + result = usearch_first(pSearch, &err); + usearch_close(pSearch); + } + + ucol_close(pColl); + } + + return result; +} + +/* +Function: +LastIndexOf +*/ +extern "C" int32_t LastIndexOf(const char* lpLocaleName, const UChar* lpTarget, const UChar* lpSource, int32_t cwSourceLength, int32_t options) +{ + static_assert(USEARCH_DONE == -1, "managed side requires -1 for not found"); + + int32_t result = USEARCH_DONE; + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + + if (U_SUCCESS(err)) + { + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, -1, lpSource, cwSourceLength, pColl, nullptr, &err); + + if (U_SUCCESS(err)) + { + result = usearch_last(pSearch, &err); + usearch_close(pSearch); + } + + ucol_close(pColl); + } + + return result; +} + +/* + Return value is a "Win32 BOOL" (1 = true, 0 = false) + */ +extern "C" int32_t StartsWith(const char* lpLocaleName, const UChar* lpTarget, const UChar* lpSource, int32_t cwSourceLength, int32_t options) +{ + int32_t result = FALSE; + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + + if (U_SUCCESS(err)) + { + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, -1, lpSource, cwSourceLength, pColl, nullptr, &err); + int32_t idx = USEARCH_DONE; + + if (U_SUCCESS(err)) + { + idx = usearch_first(pSearch, &err); + + if (idx == 0) + { + result = TRUE; + } + else + { + UCollationElements* pCollElem = ucol_openElements(pColl, lpSource, idx, &err); + + if (U_SUCCESS(err)) + { + int32_t curCollElem = UCOL_NULLORDER; + + result = TRUE; + + while((curCollElem = ucol_next(pCollElem, &err)) != UCOL_NULLORDER) + { + if (curCollElem != 0) + { + // Non ignorable collation element found between start of the string and the first match for lpTarget. + result = FALSE; + break; + } + } + + if (U_FAILURE(err)) + { + result = FALSE; + } + + ucol_closeElements(pCollElem); + } + } + + usearch_close(pSearch); + } + + ucol_close(pColl); + } + + return result; +} + +/* + Return value is a "Win32 BOOL" (1 = true, 0 = false) + */ +extern "C" int32_t EndsWith(const char* lpLocaleName, const UChar* lpTarget, const UChar* lpSource, int32_t cwSourceLength, int32_t options) +{ + int32_t result = FALSE; + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + + if (U_SUCCESS(err)) + { + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, -1, lpSource, cwSourceLength, pColl, nullptr, &err); + int32_t idx = USEARCH_DONE; + + if (U_SUCCESS(err)) + { + idx = usearch_last(pSearch, &err); + + if (idx != USEARCH_DONE) + { + if ((idx + usearch_getMatchedLength(pSearch)) == cwSourceLength) + { + result = TRUE; + } + + // TODO (dotnet/corefx#3467): We should do something similar to what StartsWith does where we can ignore + // some collation elements at the end of te string if they are zero. + } + + usearch_close(pSearch); + } + + ucol_close(pColl); + } + + return result; +} + +extern "C" int32_t GetSortKey(const char* lpLocaleName, const UChar* lpStr, int32_t cwStrLength, uint8_t* sortKey, int32_t cbSortKeyLength, int32_t options) +{ + UErrorCode err = U_ZERO_ERROR; + UCollator* pColl = GetCollatorForLocaleAndOptions(lpLocaleName, options, &err); + int32_t result = 0; + + if (U_SUCCESS(err)) + { + result = ucol_getSortKey(pColl, lpStr, cwStrLength, sortKey, cbSortKeyLength); + + ucol_close(pColl); + } + + return result; +} + +extern "C" int32_t CompareStringOrdinalIgnoreCase(const UChar* lpStr1, int32_t cwStr1Length, const UChar* lpStr2, int32_t cwStr2Length) +{ + assert(lpStr1 != nullptr); + assert(cwStr1Length >= 0); + assert(lpStr2 != nullptr); + assert(cwStr2Length >= 0); + + int32_t str1Idx = 0; + int32_t str2Idx = 0; + + while (str1Idx < cwStr1Length && str2Idx < cwStr2Length) + { + UChar32 str1Codepoint; + UChar32 str2Codepoint; + + U16_NEXT(lpStr1, str1Idx, cwStr1Length, str1Codepoint); + U16_NEXT(lpStr2, str2Idx, cwStr2Length, str2Codepoint); + + if (str1Codepoint != str2Codepoint && u_toupper(str1Codepoint) != u_toupper(str2Codepoint)) + { + return str1Codepoint < str2Codepoint ? -1 : 1; + } + } + + if (cwStr1Length < cwStr2Length) + { + return -1; + } + + if (cwStr2Length < cwStr1Length) + { + return 1; + } + + return 0; +} diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 029c62aabe..270615bc1e 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -15136,7 +15136,8 @@ HRESULT Debugger::InitAppDomainIPC(void) } hEnsureCleanup(this); DWORD dwStrLen = 0; - WCHAR szExeName[MAX_LONGPATH]; + SString szExeNamePathString; + WCHAR * szExeName = szExeNamePathString.OpenUnicodeBuffer(MAX_LONGPATH); int i; // all fields in the object can be zero initialized. @@ -15188,6 +15189,7 @@ HRESULT Debugger::InitAppDomainIPC(void) szExeName, MAX_LONGPATH); + szExeNamePathString.CloseBuffer(dwStrLen); // If we couldn't get the name, then use a nice default. if (dwStrLen == 0) { diff --git a/src/debug/shim/debugshim.cpp b/src/debug/shim/debugshim.cpp index 2d4e63cad5..55b0b36e24 100644 --- a/src/debug/shim/debugshim.cpp +++ b/src/debug/shim/debugshim.cpp @@ -84,10 +84,10 @@ STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess( HMODULE hDac = NULL; DWORD dbiTimestamp; DWORD dbiSizeOfImage; - WCHAR dbiName[MAX_PATH_FNAME]; + WCHAR dbiName[MAX_PATH_FNAME] = {0}; DWORD dacTimestamp; DWORD dacSizeOfImage; - WCHAR dacName[MAX_PATH_FNAME]; + WCHAR dacName[MAX_PATH_FNAME] = {0}; CLR_DEBUGGING_VERSION version; BOOL versionSupportedByCaller = FALSE; diff --git a/src/dlls/mscoree/mscoree.cpp b/src/dlls/mscoree/mscoree.cpp index 0be663e9dc..6a1af6d985 100644 --- a/src/dlls/mscoree/mscoree.cpp +++ b/src/dlls/mscoree/mscoree.cpp @@ -792,7 +792,12 @@ BOOL PAL_GetPALDirectory(__out_ecount(cchBuffer) LPWSTR pbuffer, HRESULT hr = S_OK; - WCHAR pPath[MAX_LONGPATH]; + WCHAR * pPath = new (nothrow) WCHAR[MAX_LONGPATH]; + if (pPath == NULL) + { + return FALSE; + } + DWORD dwPath = MAX_LONGPATH; #ifndef CROSSGEN_COMPILE @@ -800,6 +805,7 @@ BOOL PAL_GetPALDirectory(__out_ecount(cchBuffer) LPWSTR pbuffer, #endif dwPath = WszGetModuleFileName(g_pMSCorEE, pPath, dwPath); + if(dwPath == 0) { hr = HRESULT_FROM_GetLastErrorNA(); @@ -809,7 +815,9 @@ BOOL PAL_GetPALDirectory(__out_ecount(cchBuffer) LPWSTR pbuffer, DWORD dwLength; hr = CopySystemDirectory(pPath, pbuffer, cchBuffer, &dwLength); } - + + delete [] pPath; + return (hr == S_OK); } @@ -1002,7 +1010,6 @@ ErrExit: // S_OK - Output buffer contains the version string. // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in // characters. -// STDAPI GetCORVersionInternal( __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, @@ -1115,44 +1122,10 @@ __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, } - #ifndef CROSSGEN_COMPILE +#ifndef FEATURE_CORECLR STDAPI LoadLibraryShimInternal(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll) { -#ifdef FEATURE_CORECLR - - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - PRECONDITION(CheckPointer(szDllName, NULL_OK)); - PRECONDITION(CheckPointer(szVersion, NULL_OK)); - PRECONDITION(CheckPointer(pvReserved, NULL_OK)); - PRECONDITION(CheckPointer(phModDll)); - } CONTRACTL_END; - - if (szDllName == NULL) - return E_POINTER; - - HRESULT hr = S_OK; - - BEGIN_ENTRYPOINT_NOTHROW; - - WCHAR szDllPath[MAX_LONGPATH+1]; - - if (!PAL_GetPALDirectoryW(szDllPath, MAX_LONGPATH)) { - IfFailGo(HRESULT_FROM_GetLastError()); - } - wcsncat_s(szDllPath, MAX_LONGPATH+1, szDllName, MAX_LONGPATH - wcslen(szDllPath)); - - if ((*phModDll = WszLoadLibrary(szDllPath)) == NULL) - IfFailGo(HRESULT_FROM_GetLastError()); - -ErrExit: - END_ENTRYPOINT_NOTHROW; - return hr; - -#else // FEATURE_CORECLR - // Simply forward the call to the ICLRRuntimeInfo implementation. STATIC_CONTRACT_WRAPPER; if (g_pCLRRuntime) @@ -1163,7 +1136,7 @@ ErrExit: { // no runtime info, probably loaded directly (e.g. from Fusion) // just look next to ourselves. - WCHAR wszPath[MAX_LONGPATH]; + WCHAR wszPath[MAX_PATH]; DWORD dwLength = WszGetModuleFileName(g_hThisInst, wszPath,NumItems(wszPath)); @@ -1188,15 +1161,12 @@ ErrExit: } return S_OK; } - -#endif // FEATURE_CORECLR - } - -#endif // CROSSGEN_COMPILE +#endif +#endif static DWORD g_dwSystemDirectory = 0; -static WCHAR g_pSystemDirectory[MAX_LONGPATH + 1]; +static WCHAR * g_pSystemDirectory = NULL; HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength) { @@ -1263,17 +1233,30 @@ HRESULT SetInternalSystemDirectory() DWORD len; // use local buffer for thread safety - WCHAR wzSystemDirectory[COUNTOF(g_pSystemDirectory)]; + NewArrayHolder<WCHAR> wzSystemDirectory(new (nothrow) WCHAR[MAX_LONGPATH+1]); + if (wzSystemDirectory == NULL) + { + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + } - hr = GetCORSystemDirectoryInternal(wzSystemDirectory, COUNTOF(wzSystemDirectory), &len); + hr = GetCORSystemDirectoryInternal(wzSystemDirectory, MAX_LONGPATH+1, &len); if(FAILED(hr)) { - wzSystemDirectory[0] = W('\0'); + *wzSystemDirectory = W('\0'); len = 1; } - + + WCHAR * pSystemDirectory = new (nothrow) WCHAR[len]; + if (pSystemDirectory == NULL) + { + return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + } + + wcscpy_s(pSystemDirectory, len, wzSystemDirectory); + // publish results idempotently with correct memory ordering - memcpy(g_pSystemDirectory, wzSystemDirectory, len * sizeof(WCHAR)); + g_pSystemDirectory = pSystemDirectory; + (void)InterlockedExchange((LONG *)&g_dwSystemDirectory, len); } @@ -1283,10 +1266,21 @@ HRESULT SetInternalSystemDirectory() #if defined(CROSSGEN_COMPILE) && defined(FEATURE_CORECLR) void SetMscorlibPath(LPCWSTR wzSystemDirectory) { - wcscpy_s(g_pSystemDirectory, COUNTOF(g_pSystemDirectory), wzSystemDirectory); - - DWORD len = (DWORD)wcslen(g_pSystemDirectory); - + DWORD len = (DWORD)wcslen(wzSystemDirectory); + if (g_dwSystemDirectory < len+1) + { + delete [] g_pSystemDirectory; + g_pSystemDirectory = new (nothrow) WCHAR[len+1]; + + if (g_pSystemDirectory == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return; + } + } + + wcscpy_s(g_pSystemDirectory, len+1, wzSystemDirectory); + if(g_pSystemDirectory[len-1] != '\\') { g_pSystemDirectory[len] = W('\\'); @@ -1294,6 +1288,8 @@ void SetMscorlibPath(LPCWSTR wzSystemDirectory) g_dwSystemDirectory = len + 1; } else + { g_dwSystemDirectory = len; + } } #endif diff --git a/src/dlls/mscoree/mscorwks_unixexports.src b/src/dlls/mscoree/mscorwks_unixexports.src index fd450304c8..69c140320b 100644 --- a/src/dlls/mscoree/mscorwks_unixexports.src +++ b/src/dlls/mscoree/mscorwks_unixexports.src @@ -61,11 +61,13 @@ LockFile lstrlenA lstrlenW MapViewOfFile +MetaDataGetDispenser MoveFileExW MultiByteToWideChar OpenEventW OpenMutexW OpenSemaphoreW +OutputDebugStringW PAL_Random QueryPerformanceCounter QueryPerformanceFrequency diff --git a/src/inc/bbsweep.h b/src/inc/bbsweep.h index 7cebe2000c..f99c36c995 100644 --- a/src/inc/bbsweep.h +++ b/src/inc/bbsweep.h @@ -277,8 +277,8 @@ private: } #endif // !FEATURE_CORESYSTEM - WCHAR objectName[MAX_LONGPATH]; - WCHAR objectNamePrefix[MAX_LONGPATH]; + WCHAR objectName[MAX_LONGPATH] = {0}; + WCHAR objectNamePrefix[MAX_LONGPATH] = {0}; GetObjectNamePrefix(processID, fromRuntime, objectNamePrefix); // if there is a non-empty name prefix, append a '\' if (objectNamePrefix[0] != '\0') diff --git a/src/inc/clr/fs/path.h b/src/inc/clr/fs/path.h index 29a70f7260..e90b3188ed 100644 --- a/src/inc/clr/fs/path.h +++ b/src/inc/clr/fs/path.h @@ -92,7 +92,7 @@ namespace clr // result is placed in wzBuffer and the number of chars written is placed in pcchBuffer on // success; otherwise an error HRESULT is returned. static HRESULT - Combine(LPCWSTR wzPathLeft, LPCWSTR wzPathRight, __out DWORD *pcchBuffer, __out_ecount(*pcchBuffer) LPWSTR wzBuffer) + Combine(LPCWSTR wzPathLeft, LPCWSTR wzPathRight, __in DWORD *pcchBuffer, __out_ecount(*pcchBuffer) LPWSTR wzBuffer) { STATIC_CONTRACT_NOTHROW; diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h index 391f127ed4..221334d7b7 100644 --- a/src/inc/clrconfigvalues.h +++ b/src/inc/clrconfigvalues.h @@ -293,6 +293,7 @@ CONFIG_STRING_INFO(INTERNAL_TestHooks, W("TestHooks"), "Used by tests to get tes CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AssertOnFailFast, W("AssertOnFailFast"), "") RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("legacyCorruptedStateExceptionsPolicy"), 0, "Enabled Pre-V4 CSE behaviour", CLRConfig::FavorConfigFile) CONFIG_DWORD_INFO_EX(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_FailFastOnCorruptedStateException, W("FailFastOnCorruptedStateException"), 0, "Failfast if a CSE is encountered", CLRConfig::FavorConfigFile) // // Garbage collector diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index 043595dbc3..e0004a5948 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -3421,7 +3421,7 @@ public: // to return the string values to the runtime for deletion. // this avoid leaking the memory in the JIT. virtual void freeStringConfigValue( - wchar_t *value + __in_z wchar_t *value ) = 0; #endif // !RYUJIT_CTPBUILD }; diff --git a/src/inc/dlwrap.h b/src/inc/dlwrap.h index 9129bcf2bf..d30e01462a 100644 --- a/src/inc/dlwrap.h +++ b/src/inc/dlwrap.h @@ -42,6 +42,7 @@ VerQueryValueW_NoThrow( #endif #if defined(_WININET_) && !defined (CreateUrlCacheEntryW_NoThrow) +__success(return) BOOL CreateUrlCacheEntryW_NoThrow( IN LPCWSTR lpszUrlName, diff --git a/src/inc/downlevel.h b/src/inc/downlevel.h index 12aeb42cf7..d33a0abb5b 100644 --- a/src/inc/downlevel.h +++ b/src/inc/downlevel.h @@ -143,13 +143,14 @@ namespace DownLevel // User /system defaults // TODO: I don't think we need all of these. int GetSystemDefaultLocaleName(__out_ecount(cchLocaleName) LPWSTR lpLocaleName, __in int cchLocaleName); - DWORD GetUserPreferredUILanguages (__in DWORD dwFlags, __out PULONG pulNumLanguages, __out_ecount_opt(*pcchLanguagesBuffer) PWSTR pwszLanguagesBuffer, __in PULONG pcchLanguagesBuffer); + __success(return == 1) DWORD GetUserPreferredUILanguages (__in DWORD dwFlags, __out PULONG pulNumLanguages, __out_ecount_opt(*pcchLanguagesBuffer) PWSTR pwszLanguagesBuffer, __in PULONG pcchLanguagesBuffer); int GetUserDefaultLocaleName(__out_ecount(cchLocaleName) LPWSTR lpLocaleName, __in int cchLocaleName); // Locale and calendar information int GetLocaleInfoEx (__in LPCWSTR lpLocaleName, __in LCTYPE LCType, __out_ecount_opt(cchData) LPWSTR lpLCData, __in int cchData); int GetDateFormatEx(__in LPCWSTR lpLocaleName, __in DWORD dwFlags, __in_opt CONST SYSTEMTIME* lpDate, __in_opt LPCWSTR lpFormat, __out_ecount(cchDate) LPWSTR lpDateStr, __in int cchDate, __in_opt LPCWSTR lpCalendar); + __success(return != 0) int GetCalendarInfoEx(__in LPCWSTR lpLocaleName, __in CALID Calendar, __in_opt LPCWSTR pReserved, @@ -160,12 +161,13 @@ namespace DownLevel // Compareinfo type information int TurkishCompareStringIgnoreCase(LCID lcid, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2); - - int CompareStringEx(LPCWSTR lpLocaleName, DWORD dwCmpFlags, LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, - int cchCount2, LPNLSVERSIONINFO lpVersionInformation, LPVOID lpReserved, LPARAM lParam ); - int CompareStringOrdinal(LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2, BOOL bIgnoreCase); + int CompareStringEx(__in LPCWSTR lpLocaleName, __in DWORD dwCmpFlags, __in_ecount(cchCount1) LPCWSTR lpString1, __in int cchCount1, __in_ecount(cchCount2) LPCWSTR lpString2, + __in int cchCount2, __in_opt LPNLSVERSIONINFO lpVersionInformation, __in_opt LPVOID lpReserved, __in_opt LPARAM lParam ); + + int CompareStringOrdinal(__in_ecount(cchCount1) LPCWSTR string1, __in int cchCount1, __in_ecount(cchCount2) LPCWSTR string2, __in int cchCount2, __in BOOL bIgnoreCase); + __success(return != 0) int LCMapStringEx(__in LPCWSTR lpLocaleName, __in DWORD dwMapFlags, __in_ecount(cchSrc) LPCWSTR lpSrcStr, @@ -176,6 +178,7 @@ namespace DownLevel __in_opt LPVOID lpReserved, __in_opt LPARAM lParam); + __success(return != -1) int FindNLSStringEx(__in LPCWSTR lpLocaleName, __in DWORD dwFindNLSStringFlags, __in_ecount(cchSource) LPCWSTR lpStringSource, @@ -200,6 +203,7 @@ namespace DownLevel // This is where we fudge data the OS doesn't know (even on Vista) namespace UplevelFallback { + __success(return != 0) int LCMapStringEx(__in LPCWSTR lpLocaleName, __in DWORD dwMapFlags, __in_ecount(cchSrc) LPCWSTR lpSrcStr, @@ -225,6 +229,7 @@ namespace DownLevel int ResolveLocaleName(__in LPCWSTR lpNameToResolve, __in_ecount_opt(cchLocaleName) LPWSTR lpLocaleName, __in int cchLocaleName); + __success(return) BOOL GetThreadPreferredUILanguages( __in DWORD dwFlags, __out PULONG pulNumLanguages, __out_ecount_opt(*pcchLanguagesBuffer) PWSTR pwszLanguagesBuffer, diff --git a/src/inc/eventtracebase.h b/src/inc/eventtracebase.h index eac127e732..9a6b218d3f 100644 --- a/src/inc/eventtracebase.h +++ b/src/inc/eventtracebase.h @@ -385,7 +385,7 @@ namespace ETW friend class ETW::EnumerationLog; #ifdef FEATURE_EVENT_TRACE static VOID SendModuleEvent(Module *pModule, DWORD dwEventOptions, BOOL bFireDomainModuleEvents=FALSE); - static ULONG SendModuleRange(Module *pModule, DWORD dwEventOptions); + static ULONG SendModuleRange(__in Module *pModule, __in DWORD dwEventOptions); static VOID SendAssemblyEvent(Assembly *pAssembly, DWORD dwEventOptions); static VOID SendDomainEvent(BaseDomain *pBaseDomain, DWORD dwEventOptions, LPCWSTR wszFriendlyName=NULL); public: diff --git a/src/inc/formattype.cpp b/src/inc/formattype.cpp index 05b4c86247..923ff3e9a1 100644 --- a/src/inc/formattype.cpp +++ b/src/inc/formattype.cpp @@ -93,7 +93,7 @@ const PCCOR_SIGNATURE PrettyPrintSignature( const char* name, // can be "", the name of the method for this sig 0 means local var sig CQuickBytes *out, // where to put the pretty printed string IMDInternalImport *pIMDI, // ptr to IMDInternalImport class with ComSig - __in_opt const char* inlabel, // prefix for names (NULL if no names required) + _In_opt_z_ const char* inlabel, // prefix for names (NULL if no names required) BOOL printTyArity=FALSE); diff --git a/src/inc/newapis.h b/src/inc/newapis.h index 0ec87b5c70..57286e2051 100644 --- a/src/inc/newapis.h +++ b/src/inc/newapis.h @@ -326,7 +326,9 @@ namespace NewApis // Enumeration functions __success(return != 0) BOOL EnumDateFormatsExEx (DATEFMT_ENUMPROCEXEX lpDateFmtEnumProcExEx, LPCWSTR lpLocaleName, DWORD dwFlags, LPARAM lParam); + __success(return != 0) BOOL EnumTimeFormatsEx(TIMEFMT_ENUMPROCEX lpTimeFmtEnumProcEx, LPCWSTR lpLocaleName, DWORD dwFlags, LPARAM lParam); + __success(return != 0) BOOL EnumCalendarInfoExEx(CALINFO_ENUMPROCEXEX pCalInfoEnumProcExEx, LPCWSTR lpLocaleName, CALID Calendar, CALTYPE CalType, LPARAM lParam); int LCIDToLocaleName(__in LCID Locale, __out_ecount_opt(cchName) LPWSTR lpName, __in int cchName, __in DWORD dwFlags); diff --git a/src/inc/palclr.h b/src/inc/palclr.h index 9842bc4be6..26d882d08f 100644 --- a/src/inc/palclr.h +++ b/src/inc/palclr.h @@ -91,6 +91,7 @@ #define DIRECTORY_SEPARATOR_STR_W W("\\") #define PATH_SEPARATOR_CHAR_W W(';') +#define PATH_SEPARATOR_STR_W W(";") // PAL Macros // Not all compilers support fully anonymous aggregate types, so the diff --git a/src/inc/sbuffer.h b/src/inc/sbuffer.h index adcde9bab8..0c98fdb668 100644 --- a/src/inc/sbuffer.h +++ b/src/inc/sbuffer.h @@ -353,8 +353,8 @@ class SBuffer // Manipulates contents of the buffer via the plugins below, but // adds some debugging checks. Should always call through here rather // than directly calling the extensibility points. - void DebugMoveBuffer(BYTE *to, BYTE *from, COUNT_T size); - void DebugCopyConstructBuffer(BYTE *to, const BYTE *from, COUNT_T size); + void DebugMoveBuffer(__out_bcount(size) BYTE *to, BYTE *from, COUNT_T size); + void DebugCopyConstructBuffer(__out_bcount(size) BYTE *to, const BYTE *from, COUNT_T size); void DebugConstructBuffer(BYTE *buffer, COUNT_T size); void DebugDestructBuffer(BYTE *buffer, COUNT_T size); diff --git a/src/inc/sstring.h b/src/inc/sstring.h index a42d71155e..f4ae412f18 100644 --- a/src/inc/sstring.h +++ b/src/inc/sstring.h @@ -1006,6 +1006,15 @@ typedef InlineSString<512> StackSString; // be needed is small and it's preferable not to take up the stack space. typedef InlineSString<32> SmallStackSString; +// To be used specifically for path strings. +#ifdef _DEBUG +// This is a smaller version for debug builds to exercise the buffer allocation path +typedef InlineSString<32> PathString; +#else +// Set it to the current MAX_PATH +typedef InlineSString<260> PathString; +#endif + // ================================================================================ // Quick macro to create an SString around a literal string. // usage: diff --git a/src/inc/stgpool.h b/src/inc/stgpool.h index 5932a51464..9170125b37 100644 --- a/src/inc/stgpool.h +++ b/src/inc/stgpool.h @@ -333,7 +333,7 @@ protected: // helper for extension segments. //***************************************************************************** __checkReturn - FORCEINLINE HRESULT GetDataReadOnly(UINT32 nOffset, __in MetaData::DataBlob *pData) + FORCEINLINE HRESULT GetDataReadOnly(UINT32 nOffset, __inout MetaData::DataBlob *pData) { LIMITED_METHOD_CONTRACT; _ASSERTE(IsReadOnly()); @@ -375,7 +375,7 @@ protected: // helper for extension segments. //***************************************************************************** __checkReturn - virtual HRESULT GetData(UINT32 nOffset, __in MetaData::DataBlob *pData) + virtual HRESULT GetData(UINT32 nOffset, __inout MetaData::DataBlob *pData) { WRAPPER_NO_CONTRACT; return GetDataReadOnly(nOffset, pData); diff --git a/src/inc/sxshelpers.h b/src/inc/sxshelpers.h index 3fa450d5b9..3ecf5cc9a2 100644 --- a/src/inc/sxshelpers.h +++ b/src/inc/sxshelpers.h @@ -103,7 +103,7 @@ class AssemblyVersion inline AssemblyVersion(AssemblyVersion& version); // Init - HRESULT Init(LPCWSTR pwzVersion, BOOL bStartsWithV); + HRESULT Init(__in_z LPCWSTR pwzVersion, BOOL bStartsWithV); inline HRESULT Init(WORD major, WORD minor, WORD build, WORD revision); // Mofifiers. diff --git a/src/inc/utilcode.h b/src/inc/utilcode.h index 7d380e24de..e832441454 100644 --- a/src/inc/utilcode.h +++ b/src/inc/utilcode.h @@ -5600,6 +5600,7 @@ namespace Clr { namespace Util namespace Reg { HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, SString & ssValue); + __success(return == S_OK) HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, __deref_out __deref_out_z LPWSTR* pwszValue); } @@ -5625,6 +5626,7 @@ namespace Win32 SString & ssFileName, bool fAllowLongFileNames = false); + __success(return == S_OK) HRESULT GetModuleFileName( HMODULE hModule, __deref_out_z LPWSTR * pwszFileName, diff --git a/src/inc/winrt/windowsstring.h b/src/inc/winrt/windowsstring.h index ff5fcfe811..fe99e69478 100644 --- a/src/inc/winrt/windowsstring.h +++ b/src/inc/winrt/windowsstring.h @@ -324,7 +324,7 @@ namespace clr // // if the HRESULT indicates failure, does nothing // - static HRESULT FreeAndAssignOnSuccess(HRESULT hr, HSTRING newValue, __out HSTRING *target) + static HRESULT FreeAndAssignOnSuccess(HRESULT hr, HSTRING newValue, __inout HSTRING *target) { STATIC_CONTRACT_LIMITED_METHOD; if (SUCCEEDED(hr)) diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp index 1f590abe02..076ba7c262 100644 --- a/src/jit/codegenxarch.cpp +++ b/src/jit/codegenxarch.cpp @@ -5094,13 +5094,16 @@ void CodeGen::genCallInstruction(GenTreePtr node) genConsumeReg(target)); } } -#if defined(_TARGET_AMD64_) && defined(FEATURE_READYTORUN_COMPILER) +#ifdef FEATURE_READYTORUN_COMPILER else if (call->gtEntryPoint.addr != nullptr) { - genEmitCall(emitter::EC_FUNC_TOKEN_INDIR, + genEmitCall((call->gtEntryPoint.accessType == IAT_VALUE) ? emitter::EC_FUNC_TOKEN : emitter::EC_FUNC_TOKEN_INDIR, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) (void*) call->gtEntryPoint.addr, +#ifdef _TARGET_X86_ + stackArgBytes, +#endif // _TARGET_X86_ retSize, ilOffset); } diff --git a/src/md/compressedinteger.h b/src/md/compressedinteger.h index 54a86cb626..2dcae9b60c 100644 --- a/src/md/compressedinteger.h +++ b/src/md/compressedinteger.h @@ -67,6 +67,7 @@ public: // Returns FALSE if the value cannot be encoded as compressed integer, doesn't fill *pcbEncodingSize // then. __checkReturn + __success(return) static inline BOOL GetEncodingSize( UINT32 nValue, __out UINT32 *pcbEncodingSize); @@ -74,6 +75,7 @@ public: // *pcbEncodingSize with 1, 2 or 4 and *pnEncodedValue with the encoded value. // Returns FALSE if the value cannot be encoded as compressed integer, doesn't fill *pcbEncodingSize // nor *pnEncodedValue then. + __success(return) static inline BOOL Encode( UINT32 nValue, __out UINT32 *pnEncodedValue, diff --git a/src/md/datablob.h b/src/md/datablob.h index 891e41eff0..8e00b29cfe 100644 --- a/src/md/datablob.h +++ b/src/md/datablob.h @@ -67,19 +67,19 @@ public: // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. // Returns TRUE otherwise, fills *pnValue, but doesn't move the memory block (doesn't skip the read // data). - __checkReturn inline BOOL PeekU1(__out BYTE *pnValue) const; - __checkReturn inline BOOL PeekU2(__out UINT16 *pnValue) const; - __checkReturn inline BOOL PeekU4(__out UINT32 *pnValue) const; - __checkReturn inline BOOL PeekU8(__out UINT64 *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU1(__out BYTE *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU2(__out UINT16 *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU4(__out UINT32 *pnValue) const; + __checkReturn __success(return) inline BOOL PeekU8(__out UINT64 *pnValue) const; //#GetUx_Functions // Reads the U1/U2/U4/U8 from the data blob and skips the read data. // Returns FALSE if there's not enough data in the blob, doesn't initialize the value '*pnValue' then. // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. - __checkReturn inline BOOL GetU1(__out BYTE *pnValue); - __checkReturn inline BOOL GetU2(__out UINT16 *pnValue); - __checkReturn inline BOOL GetU4(__out UINT32 *pnValue); - __checkReturn inline BOOL GetU8(__out UINT64 *pnValue); + __checkReturn __success(return) inline BOOL GetU1(__out BYTE *pnValue); + __checkReturn __success(return) inline BOOL GetU2(__out UINT16 *pnValue); + __checkReturn __success(return) inline BOOL GetU4(__out UINT32 *pnValue); + __checkReturn __success(return) inline BOOL GetU8(__out UINT64 *pnValue); // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size // in *pcbCompressedValueSize) from the data blob without skipping the read data. @@ -89,6 +89,7 @@ public: // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4), but // doesn't move the memory block (doesn't skip the read data). __checkReturn + __success(return) inline BOOL PeekCompressedU( __out UINT32 *pnValue, __out UINT32 *pcbCompressedValueSize); @@ -97,7 +98,8 @@ public: // Returns FALSE if there's not enough data in the blob or the compression is invalid (starts with byte // 111? ????), doesn't initialize the value *pnValue then. // Returns TRUE otherwise, fills *pnValue and moves the memory block behind the read data. - __checkReturn + __checkReturn + __success(return) inline BOOL GetCompressedU(__out UINT32 *pnValue); // Reads compressed integer (1, 2 or 4 bytes of format code:CompressedInteger#Format - returns the size // in *pcbCompressedValueSize) from the data blob and skips the read data. @@ -107,6 +109,7 @@ public: // Returns TRUE otherwise, fills *pnValue and *pcbCompressedValueSize (with number 1,2 or 4) and moves // the memory block behind the read data. __checkReturn + __success(return) inline BOOL GetCompressedU( __out UINT32 *pnValue, __out UINT32 *pcbCompressedValueSize); @@ -117,6 +120,7 @@ public: // Returns TRUE otherwise, fills *pData with the "read" data and moves the memory block behind the // "read" data. __checkReturn + __success(return) inline BOOL GetDataOfSize( UINT32 cbDataSize, __out DataBlob *pData); @@ -174,11 +178,13 @@ public: // Returns FALSE if there's less than cbSize data represented. // Returns TRUE otherwise and truncates the represented data size to cbSize. __checkReturn + __success(return) inline BOOL TruncateToExactSize(UINT32 cbSize); // Truncates the buffer by size (cbSize). // Returns FALSE if there's less than cbSize data represented. // Returns TRUE otherwise and truncates the represented data size by cbSize. __checkReturn + __success(return) inline BOOL TruncateBySize(UINT32 cbSize); #ifdef _DEBUG @@ -198,12 +204,14 @@ public: // integer (bigger than code:CompressedInteger::const_Max). // Returns TRUE on success and moves the memory block behind the written data. __checkReturn + __success(return) inline BOOL StoreCompressedU(UINT32 nValue); // Writes data from *pSource to the data blob and skips the written data. // Returns FALSE if there's not enough data in the blob. // Returns TRUE on success and moves memory block behind the written data. __checkReturn + __success(return) inline BOOL StoreData(__in const DataBlob *pSource); private: diff --git a/src/md/datablob.inl b/src/md/datablob.inl index d7ce361013..40c92c2131 100644 --- a/src/md/datablob.inl +++ b/src/md/datablob.inl @@ -106,6 +106,7 @@ DataBlob::Init( // See code:#PeekUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::PeekU1(__out BYTE *pnValue) const @@ -123,6 +124,7 @@ DataBlob::PeekU1(__out BYTE *pnValue) const // See code:#PeekUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::PeekU2(__out UINT16 *pnValue) const @@ -140,6 +142,7 @@ DataBlob::PeekU2(__out UINT16 *pnValue) const // See code:#PeekUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::PeekU4(__out UINT32 *pnValue) const @@ -157,6 +160,7 @@ DataBlob::PeekU4(__out UINT32 *pnValue) const // See code:#PeekUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::PeekU8(__out UINT64 *pnValue) const @@ -183,6 +187,7 @@ DataBlob::PeekU8(__out UINT64 *pnValue) const // See code:#GetUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::GetU1(__out BYTE *pnValue) @@ -201,6 +206,7 @@ DataBlob::GetU1(__out BYTE *pnValue) // See code:#GetUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::GetU2(__out UINT16 *pnValue) @@ -219,6 +225,7 @@ DataBlob::GetU2(__out UINT16 *pnValue) // See code:#GetUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::GetU4(__out UINT32 *pnValue) @@ -237,6 +244,7 @@ DataBlob::GetU4(__out UINT32 *pnValue) // See code:#GetUx_Functions above. // __checkReturn +_Success_(return) inline BOOL DataBlob::GetU8(__out UINT64 *pnValue) @@ -278,6 +286,7 @@ DataBlob::GetCompressedU(__out UINT32 *pnValue) // doesn't move the memory block (doesn't skip the read data). // __checkReturn +_Success_(return) inline BOOL DataBlob::PeekCompressedU( diff --git a/src/md/heaps/blobheap.h b/src/md/heaps/blobheap.h index 91d5430368..d3fb1e324c 100644 --- a/src/md/heaps/blobheap.h +++ b/src/md/heaps/blobheap.h @@ -83,7 +83,7 @@ public: __checkReturn inline HRESULT GetAllData( - __out DataBlob *pData) + __inout DataBlob *pData) { return m_BlobPool.GetDataReadOnly(0, pData); } diff --git a/src/md/hotdata/hotheap.h b/src/md/hotdata/hotheap.h index cc59c8a175..e9e42c4330 100644 --- a/src/md/hotdata/hotheap.h +++ b/src/md/hotdata/hotheap.h @@ -52,7 +52,7 @@ public: __checkReturn HRESULT GetData( UINT32 nDataIndex, - __in DataBlob *pData); + __out DataBlob *pData); inline BOOL IsEmpty() const { return m_pHotHeapHeader == NULL; } diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs new file mode 100644 index 0000000000..b600fa59ef --- /dev/null +++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class GlobalizationInterop + { + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + internal unsafe static extern int CompareString(byte[] localeName, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + internal unsafe static extern int IndexOf(byte[] localeName, string target, char* pSource, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + internal unsafe static extern int LastIndexOf(byte[] localeName, string target, char* pSource, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal unsafe static extern bool StartsWith(byte[] localeName, string target, string source, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal unsafe static extern bool EndsWith(byte[] localeName, string target, string source, int cwSourceLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + internal unsafe static extern int GetSortKey(byte[] localeName, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options); + + [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)] + internal unsafe static extern int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len); + } +} diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs index 46fb25b6c3..ba658d0f5e 100644 --- a/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs +++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs @@ -2,14 +2,22 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; namespace System.Globalization { public partial class CompareInfo - { + { + // ICU uses a char* (UTF-8) to represent a locale name. + private readonly byte[] m_sortNameAsUtf8; + internal unsafe CompareInfo(CultureInfo culture) { - // TODO: Implement This Fully. + m_name = culture.m_name; + m_sortName = culture.SortName; + m_sortNameAsUtf8 = System.Text.Encoding.UTF8.GetBytes(m_sortName); } internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) @@ -17,13 +25,13 @@ namespace System.Globalization Contract.Assert(source != null); Contract.Assert(value != null); - // TODO: Implement This Fully. - if (value.Length == 0) { return startIndex; } + // TODO (dotnet/corefx#3468): Move this into the shim so we don't have to do the ToUpper or call substring. + if (ignoreCase) { source = source.ToUpper(CultureInfo.InvariantCulture); @@ -53,13 +61,13 @@ namespace System.Globalization Contract.Assert(source != null); Contract.Assert(value != null); - // TODO: Implement This Fully. - if (value.Length == 0) { return startIndex; } + // TODO (dotnet/corefx#3468): Move this into the shim so we don't have to do the ToUpper or call substring. + if (ignoreCase) { source = source.ToUpper(CultureInfo.InvariantCulture); @@ -76,8 +84,8 @@ namespace System.Globalization last = cur; } - return last >= 0 ? - last + startIndex - count + 1 : + return last >= 0 ? + last + startIndex - count + 1 : -1; } @@ -86,25 +94,13 @@ namespace System.Globalization Contract.Assert(source != null); Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - // TODO: Implement This Fully. - int hash = 5381; - - unchecked - { - for (int i = 0; i < source.Length; i++) - { - hash = ((hash << 5) + hash) + ChangeCaseAscii(source[i]); - } - } - - return hash; + return GetHashCodeOfStringCore(source, options, forceRandomizedHashing: false, additionalEntropy: 0); } [System.Security.SecuritySafeCritical] private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2) { - // TODO: Implement This Fully. - return CompareStringOrdinalAscii(string1, count1, string2, count2, ignoreCase: true); + return Interop.GlobalizationInterop.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2); } [System.Security.SecuritySafeCritical] @@ -114,37 +110,66 @@ namespace System.Globalization Contract.Assert(string2 != null); Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - // TODO: Implement This Fully. - string s1 = string1.Substring(offset1, length1); - string s2 = string2.Substring(offset2, length2); - - fixed (char* c1 = s1) + fixed (char* pString1 = string1) { - fixed (char* c2 = s2) + fixed (char* pString2 = string2) { - return CompareStringOrdinalAscii(c1, s1.Length, c2, s2.Length, IgnoreCase(options)); + return Interop.GlobalizationInterop.CompareString(m_sortNameAsUtf8, pString1 + offset1, length1, pString2 + offset2, length2, options); } } } - private int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) + [System.Security.SecuritySafeCritical] + private unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) { Contract.Assert(!string.IsNullOrEmpty(source)); Contract.Assert(target != null); Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - // TODO: Implement This Fully. - return IndexOfOrdinal(source, target, startIndex, count, IgnoreCase(options)); + if (target.Length == 0) + { + return startIndex; + } + + if (options == CompareOptions.Ordinal) + { + return IndexOfOrdinal(source, target, startIndex, count, ignoreCase: false); + } + + fixed (char* pSource = source) + { + int lastIndex = Interop.GlobalizationInterop.IndexOf(m_sortNameAsUtf8, target, pSource + startIndex, count, options); + + return lastIndex != -1 ? lastIndex + startIndex : -1; + } } - private int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) + private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) { Contract.Assert(!string.IsNullOrEmpty(source)); Contract.Assert(target != null); Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - // TODO: Implement This Fully. - return LastIndexOfOrdinal(source, target, startIndex, count, IgnoreCase(options)); + if (target.Length == 0) + { + return startIndex; + } + + if (options == CompareOptions.Ordinal) + { + return LastIndexOfOrdinal(source, target, startIndex, count, ignoreCase: false); + } + + // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source + // of the start of the string that is count characters away from startIndex. + int leftStartIndex = (startIndex - count + 1); + + fixed (char* pSource = source) + { + int lastIndex = Interop.GlobalizationInterop.LastIndexOf(m_sortNameAsUtf8, target, pSource + (startIndex - count + 1), count, options); + + return lastIndex != -1 ? lastIndex + leftStartIndex : -1; + } } private bool StartsWith(string source, string prefix, CompareOptions options) @@ -153,10 +178,7 @@ namespace System.Globalization Contract.Assert(!string.IsNullOrEmpty(prefix)); Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - // TODO: Implement This Fully. - if(prefix.Length > source.Length) return false; - - return StringEqualsAscii(source.Substring(0, prefix.Length), prefix, IgnoreCase(options)); + return Interop.GlobalizationInterop.StartsWith(m_sortNameAsUtf8, prefix, source, source.Length, options); } private bool EndsWith(string source, string suffix, CompareOptions options) @@ -165,75 +187,40 @@ namespace System.Globalization Contract.Assert(!string.IsNullOrEmpty(suffix)); Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - // TODO: Implement This Fully. - if(suffix.Length > source.Length) return false; - - return StringEqualsAscii(source.Substring(source.Length - suffix.Length), suffix, IgnoreCase(options)); + return Interop.GlobalizationInterop.EndsWith(m_sortNameAsUtf8, suffix, source, source.Length, options); } // ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- - private static char ChangeCaseAscii(char c, bool toUpper = true) + internal unsafe int GetHashCodeOfStringCore(string source, CompareOptions options, bool forceRandomizedHashing, long additionalEntropy) { - if (toUpper && c >= 'a' && c <= 'z') - { - return (char)('A' + (c - 'a')); - } - else if (!toUpper && c >= 'A' && c <= 'Z') - { - return (char)('a' + (c - 'A')); - } - - return c; - } + Contract.Assert(source != null); + Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - private static bool StringEqualsAscii(string s1, string s2, bool ignoreCase = true) - { - if (s1.Length != s2.Length) return false; + int sortKeyLength = Interop.GlobalizationInterop.GetSortKey(m_sortNameAsUtf8, source, source.Length, null, 0, options); - for (int i = 0; i < s1.Length; i++) + // As an optimization, for small sort keys we allocate the buffer on the stack. + if (sortKeyLength <= 256) { - char c1 = ignoreCase ? ChangeCaseAscii(s1[i]) : s1[i]; - char c2 = ignoreCase ? ChangeCaseAscii(s2[i]) : s2[i]; - - if (c1 != c2) return false; + byte* pSortKey = stackalloc byte[sortKeyLength]; + Interop.GlobalizationInterop.GetSortKey(m_sortNameAsUtf8, source, source.Length, pSortKey, sortKeyLength, options); + return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy); } - return true; - } + byte[] sortKey = new byte[sortKeyLength]; - [System.Security.SecuritySafeCritical] - private static unsafe int CompareStringOrdinalAscii(char* s1, int count1, char* s2, int count2, bool ignoreCase) - { - int countMin = Math.Min(count1, count2); + fixed(byte* pSortKey = sortKey) { - for (int i = 0; i < countMin; i++) - { - char c1 = ignoreCase ? ChangeCaseAscii(s1[i]) : s1[i]; - char c2 = ignoreCase ? ChangeCaseAscii(s2[i]) : s2[i]; - - if (c1 < c2) - { - return -1; - } - else if (c1 > c2) - { - return 1; - } - } + Interop.GlobalizationInterop.GetSortKey(m_sortNameAsUtf8, source, source.Length, pSortKey, sortKeyLength, options); + return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy); } - - if (count1 == count2) return 0; - if (count1 > count2) return 1; - - return -1; } - private static bool IgnoreCase(CompareOptions options) - { - return ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase); - } + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall)] + [SuppressUnmanagedCodeSecurity] + private static unsafe extern int InternalHashSortKey(byte* sortKey, int sortKeyLength, [MarshalAs(UnmanagedType.Bool)] bool forceRandomizedHashing, long additionalEntropy); } -}
\ No newline at end of file +} diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs index 9a18175a06..9a64917b66 100644 --- a/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs +++ b/src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs @@ -19,11 +19,10 @@ namespace System.Globalization ////////////////////////////////////////////////////////////////////////// internal unsafe TextInfo(CultureData cultureData) { - // TODO: Implement this fully. m_cultureData = cultureData; m_cultureName = m_cultureData.CultureName; m_textInfoName = m_cultureData.STEXTINFO; - m_needsTurkishCasing = NeedsTurkishCasing(this.m_textInfoName); + m_needsTurkishCasing = NeedsTurkishCasing(m_textInfoName); } [System.Security.SecuritySafeCritical] @@ -61,9 +60,7 @@ namespace System.Globalization private bool NeedsTurkishCasing(string localeName) { Contract.Assert(localeName != null); - - string lcName = CultureData.AnsiToLower(localeName); - return lcName.Length >= 2 && ((lcName[0] == 't' && lcName[1] == 'r') || (lcName[0] == 'a' && lcName[1] == 'z')); + return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("i", "I", CompareOptions.IgnoreCase) != 0; } } } diff --git a/src/mscorlib/corefx/System/Globalization/TextInfo.cs b/src/mscorlib/corefx/System/Globalization/TextInfo.cs index e99151dda8..7de2b67036 100644 --- a/src/mscorlib/corefx/System/Globalization/TextInfo.cs +++ b/src/mscorlib/corefx/System/Globalization/TextInfo.cs @@ -288,14 +288,6 @@ namespace System.Globalization { get { -#if PLATFORM_UNIX - // UNIXTODO: This hack can be removed once collation works and the code after this correctly returns "false". - if (m_needsTurkishCasing) - { - return false; - } -#endif - if (m_IsAsciiCasingSameAsInvariant == null) { m_IsAsciiCasingSameAsInvariant = CultureInfo.GetCultureInfo(m_textInfoName).CompareInfo.Compare("abcdefghijklmnopqrstuvwxyz", diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index 70b8e916b4..512c7a0ade 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -1017,6 +1017,7 @@ <Member Name="Resolve(System.IntPtr,System.Reflection.AssemblyName)" /> <Member Name="ResolveUnmanagedDll(System.String,System.IntPtr)" /> <Member Name="LoadUnmanagedDll(System.String)" /> + <Member Name="LoadUnmanagedDllFromPath(System.String)" /> <Member Name="get_Default" /> <Member Name="SetProfileOptimizationRoot(System.String)" /> <Member Name="StartProfileOptimization(System.String)" /> @@ -9900,6 +9901,7 @@ <Member Name="get_Name" /> <Member MemberType="Property" Name="ConstructionException" /> <Member MemberType="Property" Name="CurrentThreadActivityId" /> + <Member MemberType="Event" Name="EventCommandExecuted" /> <Member Name="Dispose" /> <Member Name="Dispose(System.Boolean)" /> <Member Name="GenerateManifest(System.Type,System.String)" /> diff --git a/src/mscorlib/mscorlib.shared.sources.props b/src/mscorlib/mscorlib.shared.sources.props index 81749f0569..13f58e2fc0 100644 --- a/src/mscorlib/mscorlib.shared.sources.props +++ b/src/mscorlib/mscorlib.shared.sources.props @@ -787,6 +787,7 @@ <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\Interop.Libraries.cs" /> <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Calendar.cs" /> <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Casing.cs" /> + <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Collation.cs" /> <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.Locale.cs" /> <GlobalizationSources Include="$(CoreFxSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs" /> <GlobalizationSources Include="$(CoreFxSourcesRoot)\System\Globalization\CalendarData.Unix.cs" /> diff --git a/src/mscorlib/src/System/Collections/Hashtable.cs b/src/mscorlib/src/System/Collections/Hashtable.cs index 4c30b72b5e..2c10ff0442 100644 --- a/src/mscorlib/src/System/Collections/Hashtable.cs +++ b/src/mscorlib/src/System/Collections/Hashtable.cs @@ -22,7 +22,7 @@ namespace System.Collections { using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Diagnostics.Contracts; -#if FEATURE_RANDOMIZED_STRING_HASHING +#if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_PAL using System.Security.Cryptography; #endif @@ -1802,9 +1802,11 @@ namespace System.Collections { return comparer; } - + private const int bufferSize = 1024; +#if !FEATURE_PAL private static RandomNumberGenerator rng; +#endif private static byte[] data; private static int currentIndex = bufferSize; private static readonly object lockObj = new Object(); @@ -1816,14 +1818,21 @@ namespace System.Collections { if(currentIndex == bufferSize) { - if(null == rng) + if(data == null) { - rng = RandomNumberGenerator.Create(); data = new byte[bufferSize]; Contract.Assert(bufferSize % 8 == 0, "We increment our current index by 8, so our buffer size must be a multiple of 8"); +#if !FEATURE_PAL + rng = RandomNumberGenerator.Create(); +#endif + } +#if FEATURE_PAL + Microsoft.Win32.Win32Native.Random(true, data, data.Length); +#else rng.GetBytes(data); +#endif currentIndex = 0; } diff --git a/src/mscorlib/src/System/Decimal.cs b/src/mscorlib/src/System/Decimal.cs index 894760043e..a9acef73b4 100644 --- a/src/mscorlib/src/System/Decimal.cs +++ b/src/mscorlib/src/System/Decimal.cs @@ -218,11 +218,7 @@ namespace System { // Constructs a Decimal from a Currency value. // internal Decimal(Currency value) { - Decimal temp = Currency.ToDecimal(value); - this.lo = temp.lo; - this.mid = temp.mid; - this.hi = temp.hi; - this.flags = temp.flags; + this = Currency.ToDecimal(value); } // Don't remove these 2 methods below. They are required by the fx when the are dealing with Currency in their diff --git a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 66a9b17ba7..f461a14e50 100644 --- a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -199,6 +199,30 @@ namespace System.Runtime.Loader return assembly; } + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + private static extern IntPtr InternalLoadUnmanagedDllFromPath(string unmanagedDllPath); + + // This method provides a way for overriders of LoadUnmanagedDll() to load an unmanaged DLL from a specific path in a + // platform-independent way. The DLL is loaded with default load flags. + protected IntPtr LoadUnmanagedDllFromPath(string unmanagedDllPath) + { + if (unmanagedDllPath == null) + { + throw new ArgumentNullException("unmanagedDllPath"); + } + if (unmanagedDllPath.Length == 0) + { + throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"), "unmanagedDllPath"); + } + if (Path.IsRelative(unmanagedDllPath)) + { + throw new ArgumentException(Environment.GetResourceString("Argument_AbsolutePathRequired"), "unmanagedDllPath"); + } + + return InternalLoadUnmanagedDllFromPath(unmanagedDllPath); + } // Custom AssemblyLoadContext implementations can override this // method to perform the load of unmanaged native dll diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs index 8acafd6d5f..eb8fdd88a2 100644 --- a/src/mscorlib/src/System/String.cs +++ b/src/mscorlib/src/System/String.cs @@ -2556,10 +2556,12 @@ namespace System { return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - if( this.Length < value.Length) { + if( this.Length < value.Length || m_firstChar != value.m_firstChar) { return false; } - return (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0); + return (value.Length == 1) ? + true : // First char is the same and thats all there is to compare + (nativeCompareOrdinalEx(this, 0, value, 0, value.Length) == 0); case StringComparison.OrdinalIgnoreCase: if( this.Length < value.Length) { diff --git a/src/mscorlib/src/System/StringComparer.cs b/src/mscorlib/src/System/StringComparer.cs index cc976504ab..9799a51942 100644 --- a/src/mscorlib/src/System/StringComparer.cs +++ b/src/mscorlib/src/System/StringComparer.cs @@ -239,8 +239,7 @@ namespace System { } #if FEATURE_COREFX_GLOBALIZATION - // TODO: Implement this fully. - throw new NotImplementedException(); + return _compareInfo.GetHashCodeOfStringCore(obj, options, true, _entropy); #else return _compareInfo.GetHashCodeOfString(obj, options, true, _entropy); #endif @@ -394,8 +393,7 @@ namespace System { if( _ignoreCase) { #if FEATURE_COREFX_GLOBALIZATION - // TODO: Implement this fully. - throw new NotImplementedException(); + return CultureInfo.InvariantCulture.CompareInfo.GetHashCodeOfStringCore(obj, CompareOptions.IgnoreCase, true, _entropy); #else return TextInfo.GetHashCodeOrdinalIgnoreCase(obj, true, _entropy); #endif diff --git a/src/mscorlib/src/System/Threading/ExecutionContext.cs b/src/mscorlib/src/System/Threading/ExecutionContext.cs index 3fc1e14908..94308118bc 100644 --- a/src/mscorlib/src/System/Threading/ExecutionContext.cs +++ b/src/mscorlib/src/System/Threading/ExecutionContext.cs @@ -59,18 +59,18 @@ namespace System.Threading static ExecutionContext t_currentMaybeNull; private readonly Dictionary<IAsyncLocal, object> m_localValues; - private readonly List<IAsyncLocal> m_localChangeNotifications; + private readonly IAsyncLocal[] m_localChangeNotifications; private ExecutionContext() { m_localValues = new Dictionary<IAsyncLocal, object>(); - m_localChangeNotifications = new List<IAsyncLocal>(); + m_localChangeNotifications = Array.Empty<IAsyncLocal>(); } - private ExecutionContext(ExecutionContext other) + private ExecutionContext(Dictionary<IAsyncLocal, object> localValues, IAsyncLocal[] localChangeNotifications) { - m_localValues = new Dictionary<IAsyncLocal, object>(other.m_localValues); - m_localChangeNotifications = new List<IAsyncLocal>(other.m_localChangeNotifications); + m_localValues = localValues; + m_localChangeNotifications = localChangeNotifications; } [SecuritySafeCritical] @@ -191,18 +191,39 @@ namespace System.Threading if (previousValue == newValue) return; - current = new ExecutionContext(current); - current.m_localValues[local] = newValue; + // + // Allocate a new Dictionary containing a copy of the old values, plus the new value. We have to do this manually to + // minimize allocations of IEnumerators, etc. + // + Dictionary<IAsyncLocal, object> newValues = new Dictionary<IAsyncLocal, object>(current.m_localValues.Count + (hadPreviousValue ? 0 : 1)); - t_currentMaybeNull = current; + foreach (KeyValuePair<IAsyncLocal, object> pair in current.m_localValues) + newValues.Add(pair.Key, pair.Value); + newValues[local] = newValue; + + // + // Either copy the change notification array, or create a new one, depending on whether we need to add a new item. + // + IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications; if (needChangeNotifications) { if (hadPreviousValue) - Contract.Assert(current.m_localChangeNotifications.Contains(local)); + { + Contract.Assert(Array.IndexOf(newChangeNotifications, local) >= 0); + } else - current.m_localChangeNotifications.Add(local); + { + int newNotificationIndex = newChangeNotifications.Length; + Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); + newChangeNotifications[newNotificationIndex] = local; + } + } + t_currentMaybeNull = new ExecutionContext(newValues, newChangeNotifications); + + if (needChangeNotifications) + { local.OnValueChanged(previousValue, newValue, false); } } diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 6f88513d29..080d07781d 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -3658,6 +3658,19 @@ LoadLibraryExW( IN /*Reserved*/ HANDLE hFile, IN DWORD dwFlags); +PALIMPORT +HMODULE +PALAPI +PAL_LoadLibraryDirect( + IN LPCWSTR lpLibFileName); + +PALIMPORT +HMODULE +PALAPI +PAL_RegisterLibraryDirect( + IN HMODULE dl_handle, + IN LPCWSTR lpLibFileName); + /*++ Function: PAL_LOADLoadPEFile @@ -3879,14 +3892,6 @@ HeapCreate( IN SIZE_T dwMaximumSize); PALIMPORT -SIZE_T -PALAPI -HeapSize( - HANDLE hHeap, - DWORD dwFlags, - LPCVOID lpMem); - -PALIMPORT LPVOID PALAPI HeapAlloc( diff --git a/src/pal/inc/rt/palrt.h b/src/pal/inc/rt/palrt.h index 92d9b3a219..b969047ce3 100644 --- a/src/pal/inc/rt/palrt.h +++ b/src/pal/inc/rt/palrt.h @@ -1364,11 +1364,13 @@ typedef VOID (__stdcall *WAITORTIMERCALLBACK)(PVOID, BOOLEAN); #define DIRECTORY_SEPARATOR_CHAR_W W('/') #define DIRECTORY_SEPARATOR_STR_W W("/") #define PATH_SEPARATOR_CHAR_W W(':') +#define PATH_SEPARATOR_STR_W W(":") #else // PLATFORM_UNIX #define DIRECTORY_SEPARATOR_CHAR_A '\\' #define DIRECTORY_SEPARATOR_CHAR_W W('\\') #define DIRECTORY_SEPARATOR_STR_W W("\\") #define PATH_SEPARATOR_CHAR_W W(';') +#define PATH_SEPARATOR_STR_W W(";") #endif // PLATFORM_UNIX #ifndef IMAGE_IMPORT_DESC_FIELD diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index 854655621f..20393cd17e 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -141,6 +141,7 @@ set(SOURCES misc/interlock.cpp misc/miscpalapi.cpp misc/msgbox.cpp + misc/stackstring.cpp misc/strutil.cpp misc/sysinfo.cpp misc/time.cpp @@ -223,7 +224,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux) rt dl unwind - unwind-ptrace unwind-generic ) endif(CMAKE_SYSTEM_NAME STREQUAL Linux) diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in index 5133374392..4c06de0eca 100644 --- a/src/pal/src/config.h.in +++ b/src/pal/src/config.h.in @@ -135,7 +135,6 @@ #define HAVE_LOWERCASE_ISO_NAME 0 #define HAVE_READ_REAL_TIME 0 #define HAVE_UNDERSCORE_ISO_NAME 0 -#define MALLOC_ZERO_RETURNS_NULL 0 #define MKSTEMP64_IS_USED_INSTEAD_OF_MKSTEMP 0 #define NEED_DLCOMPAT 0 #define OPEN64_IS_USED_INSTEAD_OF_OPEN 0 diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index 69d947adb3..77a0846762 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -763,22 +763,6 @@ int main(void) unlink(szFileName); exit(ret); }" UNGETC_NOT_RETURN_EOF) -check_cxx_source_runs(" -#include <stdlib.h> - -int main(void) -{ - void *p; - - p = malloc(0); - - if (p == NULL) - { - exit(0); - } - - exit(1); -}" MALLOC_ZERO_RETURNS_NULL) set(CMAKE_REQUIRED_LIBRARIES pthread) check_cxx_source_runs(" #include <stdlib.h> diff --git a/src/pal/src/cruntime/malloc.cpp b/src/pal/src/cruntime/malloc.cpp index 2628a47ad4..36587dbd81 100644 --- a/src/pal/src/cruntime/malloc.cpp +++ b/src/pal/src/cruntime/malloc.cpp @@ -112,12 +112,13 @@ CorUnix::InternalMalloc( { void *pvMem; pthrCurrent->suspensionInfo.EnterUnsafeRegion(); -#if MALLOC_ZERO_RETURNS_NULL + if (szSize == 0) { + // malloc may return null for a requested size of zero bytes. Force a nonzero size to get a valid pointer. szSize = 1; } -#endif + pvMem = (void*)malloc(szSize); pthrCurrent->suspensionInfo.LeaveUnsafeRegion(); return pvMem; diff --git a/src/pal/src/cruntime/wchar.cpp b/src/pal/src/cruntime/wchar.cpp index 0eb211cc7f..17442d3de8 100644 --- a/src/pal/src/cruntime/wchar.cpp +++ b/src/pal/src/cruntime/wchar.cpp @@ -1450,7 +1450,7 @@ PAL_wcsncat( wchar_16 * strDest, const wchar_16 *strSource, size_t count ) static BOOL MISC_CRT_WCSTOD_IsValidCharacter( WCHAR c ) { if ( c == '+' || c == '-' || c == '.' || ( c >= '0' && c <= '9' ) || - c == 'e' || c == 'E' || c == 'd' || c == 'd' ) + c == 'e' || c == 'E' || c == 'd' || c == 'D' ) { return TRUE; } diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp index 7a0a81fa3f..5a8c67160f 100644 --- a/src/pal/src/exception/seh-unwind.cpp +++ b/src/pal/src/exception/seh-unwind.cpp @@ -36,7 +36,9 @@ Abstract: #endif // !__LINUX__ #include <libunwind.h> #ifdef __LINUX__ +#ifdef HAVE_LIBUNWIND_PTRACE #include <libunwind-ptrace.h> +#endif // HAVE_LIBUNWIND_PTRACE #endif // __LINUX__ #endif // HAVE_LIBUNWIND_H @@ -327,7 +329,6 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP #ifdef _AMD64_ #ifdef __LINUX__ - static struct LibunwindCallbacksInfoType { CONTEXT *Context; @@ -435,10 +436,31 @@ static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, size_ return -UNW_EINVAL; } +int find_proc_info(unw_addr_space_t as, + unw_word_t ip, unw_proc_info_t *pip, + int need_unwind_info, void *arg) +{ +#ifdef HAVE_LIBUNWIND_PTRACE + // UNIXTODO: libunwind RPM package on Fedora/CentOS/RedHat doesn't have libunwind-ptrace.so + // and we can't use it from a shared library like libmscordaccore.so. + // That's why all calls to ptrace parts of libunwind ifdeffed out for now. + return _UPT_find_proc_info(as, ip, pip, need_unwind_info, arg); +#else + return -UNW_EINVAL; +#endif +} + +void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg) +{ +#ifdef HAVE_LIBUNWIND_PTRACE + return _UPT_put_unwind_info(as, pip, arg); +#endif +} + static unw_accessors_t unwind_accessors = { - .find_proc_info = _UPT_find_proc_info, - .put_unwind_info = _UPT_put_unwind_info, + .find_proc_info = find_proc_info, + .put_unwind_info = put_unwind_info, .get_dyn_info_list_addr = get_dyn_info_list_addr, .access_mem = access_mem, .access_reg = access_reg, @@ -494,7 +516,9 @@ BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context, LibunwindCallbacksInfo.readMemCallback = readMemCallback; WinContextToUnwindContext(context, &unwContext); addrSpace = unw_create_addr_space(&unwind_accessors, 0); +#ifdef HAVE_LIBUNWIND_PTRACE libunwindUptPtr = _UPT_create(pid); +#endif st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr); if (st < 0) { @@ -518,10 +542,12 @@ BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context, result = TRUE; Exit: - if (libunwindUptPtr != nullptr) +#ifdef HAVE_LIBUNWIND_PTRACE + if (libunwindUptPtr != NULL) { _UPT_destroy(libunwindUptPtr); } +#endif if (addrSpace != 0) { unw_destroy_addr_space(addrSpace); diff --git a/src/pal/src/include/pal/thread.hpp b/src/pal/src/include/pal/thread.hpp index f84ee6eada..15d4f43ca1 100644 --- a/src/pal/src/include/pal/thread.hpp +++ b/src/pal/src/include/pal/thread.hpp @@ -342,6 +342,11 @@ namespace CorUnix bool m_fStartStatus; bool m_fStartStatusSet; + // Base address of the stack of this thread + void* m_stackBase; + // Limit address of the stack of this thread + void* m_stackLimit; + // The default stack size of a newly created thread (currently 256KB) // when the dwStackSize paramter of PAL_CreateThread() // is zero. This value can be set by setting the @@ -408,7 +413,9 @@ namespace CorUnix m_eThreadType(UserCreatedThread), m_fStartItemsInitialized(FALSE), m_fStartStatus(FALSE), - m_fStartStatusSet(FALSE) + m_fStartStatusSet(FALSE), + m_stackBase(NULL), + m_stackLimit(NULL) #ifdef FEATURE_PAL_SXS , m_fInPal(TRUE) #endif // FEATURE_PAL_SXS @@ -646,6 +653,20 @@ namespace CorUnix ReleaseThreadReference( void ); + + // Get base address of this thread's stack + // Can be called only for the current thread. + void * + GetStackBase( + void + ); + + // Get limit address of this thread's stack + // Can be called only for the current thread. + void * + GetStackLimit( + void + ); #ifdef FEATURE_PAL_SXS // diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp index 22a3a009de..29d8d19d82 100644 --- a/src/pal/src/loader/module.cpp +++ b/src/pal/src/loader/module.cpp @@ -96,8 +96,16 @@ char g_szCoreCLRPath[MAX_LONGPATH] = { 0 }; /* static function declarations ***********************************************/ +template<class TChar> bool LOADVerifyLibraryPath(const TChar *libraryPath); +bool LOADConvertLibraryPathWideStringToMultibyteString( + LPCWSTR wideLibraryPath, + CHAR (&multibyteLibraryPath)[MAX_LONGPATH], + INT *multibyteLibraryPathLengthRef); + static BOOL LOADValidateModule(MODSTRUCT *module); static LPWSTR LOADGetModuleFileName(MODSTRUCT *module); +static HMODULE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath, bool setLastError); +static HMODULE LOADRegisterLibraryDirect(HMODULE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic); static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic); static void LOAD_SEH_CallDllMain(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved); static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name); @@ -161,17 +169,8 @@ LoadLibraryExA( (lpLibFileName)?lpLibFileName:"NULL", (lpLibFileName)?lpLibFileName:"NULL"); - if (NULL == lpLibFileName) + if (!LOADVerifyLibraryPath(lpLibFileName)) { - ERROR("lpLibFileName is NULL;Exit.\n"); - SetLastError(ERROR_MOD_NOT_FOUND); - goto Done; - } - - if (lpLibFileName[0]=='\0') - { - ERROR("can't load library with NULL file name...\n"); - SetLastError(ERROR_INVALID_PARAMETER); goto Done; } @@ -230,47 +229,116 @@ LoadLibraryExW( lpLibFileName?lpLibFileName:W16_NULLSTRING, lpLibFileName?lpLibFileName:W16_NULLSTRING); - if (NULL == lpLibFileName) + if (!LOADVerifyLibraryPath(lpLibFileName)) { - ERROR("lpLibFileName is NULL;Exit.\n"); - SetLastError(ERROR_MOD_NOT_FOUND); goto done; } - if (lpLibFileName[0]==0) + if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length)) { - ERROR("Can't load library with NULL file name...\n"); - SetLastError(ERROR_INVALID_PARAMETER); goto done; } /* do the Dos/Unix conversion on our own copy of the name */ + FILEDosToUnixPathA(lpstr); - name_length = WideCharToMultiByte(CP_ACP, 0, lpLibFileName, -1, lpstr, - MAX_LONGPATH, NULL, NULL); - if (name_length == 0) + /* let LOADLoadLibrary call SetLastError in case of failure */ + hModule = LOADLoadLibrary(lpstr, TRUE); + +done: + LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule); + PERF_EXIT(LoadLibraryExW); + return hModule; +} + +/* +Function: +LoadLibraryDirect + +Loads a library using a system call, without registering the library with the module list. + +Returns the system handle to the loaded library, or nullptr upon failure (error is set via SetLastError()). +*/ +HMODULE +PALAPI +PAL_LoadLibraryDirect( + IN LPCWSTR lpLibFileName) +{ + CHAR lpstr[MAX_LONGPATH]; + INT name_length; + HMODULE hModule = NULL; + + PERF_ENTRY(LoadLibraryDirect); + ENTRY("LoadLibraryDirect (lpLibFileName=%p (%S)) \n", + lpLibFileName?lpLibFileName:W16_NULLSTRING, + lpLibFileName?lpLibFileName:W16_NULLSTRING); + + if (!LOADVerifyLibraryPath(lpLibFileName)) + { + goto done; + } + + if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length)) { - DWORD dwLastError = GetLastError(); - if (dwLastError == ERROR_INSUFFICIENT_BUFFER) - { - ERROR("lpLibFileName is larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH); - } - else - { - ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); - } - SetLastError(ERROR_INVALID_PARAMETER); goto done; } + /* do the Dos/Unix conversion on our own copy of the name */ FILEDosToUnixPathA(lpstr); - /* let LOADLoadLibrary call SetLastError in case of failure */ - hModule = LOADLoadLibrary(lpstr, TRUE); + /* let LOADLoadLibraryDirect call SetLastError in case of failure */ + hModule = LOADLoadLibraryDirect(lpstr, true /* setLastError */); done: - LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule); - PERF_EXIT(LoadLibraryExW); + LOGEXIT("LoadLibraryDirect returns HMODULE %p\n", hModule); + PERF_EXIT(LoadLibraryDirect); + return hModule; +} + +/* +Function: +RegisterLibraryDirect + +Registers a system handle to a loaded library with the module list. + +Returns a PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()). +*/ +HMODULE +PALAPI +PAL_RegisterLibraryDirect( + IN HMODULE dl_handle, + IN LPCWSTR lpLibFileName) +{ + CHAR lpstr[MAX_LONGPATH]; + INT name_length; + HMODULE hModule = NULL; + + PERF_ENTRY(RegisterLibraryDirect); + ENTRY("RegisterLibraryDirect (lpLibFileName=%p (%S)) \n", + lpLibFileName ? lpLibFileName : W16_NULLSTRING, + lpLibFileName ? lpLibFileName : W16_NULLSTRING); + + if (!LOADVerifyLibraryPath(lpLibFileName)) + { + goto done; + } + + if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length)) + { + goto done; + } + + /* do the Dos/Unix conversion on our own copy of the name */ + FILEDosToUnixPathA(lpstr); + + /* let LOADRegisterLibraryDirect call SetLastError in case of failure */ + LockModuleList(); + hModule = LOADRegisterLibraryDirect(dl_handle, lpstr, true /* fDynamic */); + UnlockModuleList(); + +done: + LOGEXIT("RegisterLibraryDirect returns HMODULE %p\n", hModule); + PERF_EXIT(RegisterLibraryDirect); return hModule; } @@ -1147,6 +1215,53 @@ done_nolock: /* Static function definitions ************************************************/ +// Checks the library path for null or empty string. On error, calls SetLastError() and returns false. +template<class TChar> +bool LOADVerifyLibraryPath(const TChar *libraryPath) +{ + if (libraryPath == nullptr) + { + ERROR("libraryPath is null\n"); + SetLastError(ERROR_MOD_NOT_FOUND); + return false; + } + if (libraryPath[0] == '\0') + { + ERROR("libraryPath is empty\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + return true; +} + +// Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false. +bool LOADConvertLibraryPathWideStringToMultibyteString( + LPCWSTR wideLibraryPath, + CHAR(&multibyteLibraryPath)[MAX_LONGPATH], + INT *multibyteLibraryPathLengthRef) +{ + _ASSERTE(wideLibraryPath != nullptr); + _ASSERTE(multibyteLibraryPathLengthRef != nullptr); + + *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath, + MAX_LONGPATH, nullptr, nullptr); + if (*multibyteLibraryPathLengthRef == 0) + { + DWORD dwLastError = GetLastError(); + if (dwLastError == ERROR_INSUFFICIENT_BUFFER) + { + ERROR("wideLibraryPath converted to a multibyte string is longer than MAX_LONGPATH (%d)!\n", MAX_LONGPATH); + } + else + { + ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError); + } + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + return true; +} + /*++ Function : LOADValidateModule @@ -1295,88 +1410,60 @@ static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name) return module; } -/*++ -Function : - LOADLoadLibrary [internal] - - implementation of LoadLibrary (for use by the A/W variants) +/* +Function: + LOADLoadLibraryDirect [internal] -Parameters : - LPSTR shortAsciiName : name of module as specified to LoadLibrary + Loads a library using a system call, without registering the library with the module list. - BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary - -Return value : - handle to loaded module +Parameters: + LPCSTR libraryNameOrPath: The library to load. + bool setLastError: True to set the last error upon failure, false otherwise. ---*/ -static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) +Return value: + System handle to the loaded library, or nullptr upon failure (error is set via SetLastError() if 'setLastError' is true). +*/ +static HMODULE LOADLoadLibraryDirect(LPCSTR libraryNameOrPath, bool setLastError) { - CHAR fullLibraryName[MAX_LONGPATH]; - MODSTRUCT *module = NULL; - void *dl_handle = NULL; - DWORD dwError; - DWORD retval; - - // Check whether we have been requested to load 'libc'. If that's the case then use the - // full name of the library that is defined in <gnu/lib-names.h> by the LIBC_SO constant. - // The problem is that calling dlopen("libc.so") will fail for libc even thought it works - // for other libraries. The reason is that libc.so is just linker script (i.e. a test file). - // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO. - if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0) - { -#if defined(__APPLE__) - shortAsciiName = "libc.dylib"; -#elif defined(__FreeBSD__) - shortAsciiName = FREEBSD_LIBC; -#else - shortAsciiName = LIBC_SO; -#endif - } - - LockModuleList(); + _ASSERTE(libraryNameOrPath != nullptr); + _ASSERTE(libraryNameOrPath[0] != '\0'); - // See if file can be dlopen()ed; this should work even if it's already loaded + HMODULE dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY); + if (dl_handle != nullptr) { - // See GetProcAddress for an explanation why we leave the PAL. - PAL_LeaveHolder holder; - - // P/Invokes are often declared with variations on the actual library name. - // For example, it's common to leave off the extension/suffix of the library - // even if it has one, or to leave off a prefix like "lib" even if it has one - // (both of these are done typically to smooth over cross-platform differences). - // We try to dlopen with such variations on the original. - const char* const formatStrings[4] = // used with args: PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX - { - "%s%s%s", // prefix+name+suffix - "%.0s%s%.0s", // name - "%.0s%s%s", // name+suffix - "%s%s%.0s", // prefix+name - }; - const int skipPrefixing = strchr(shortAsciiName, '/') != NULL; // skip prefixing if the name is actually a path - for (int i = 0; i < 4; i++) - { - if (skipPrefixing && (i == 0 || i == 3)) // 0th and 3rd strings include prefixes - continue; - - if (!dl_handle && - snprintf(fullLibraryName, MAX_LONGPATH, formatStrings[i], PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX) < MAX_LONGPATH && - ((dl_handle = dlopen(fullLibraryName, RTLD_LAZY | RTLD_NOLOAD)) || - (dl_handle = dlopen(fullLibraryName, RTLD_LAZY)))) - { - shortAsciiName = fullLibraryName; - break; - } - } + TRACE("dlopen() found module %s\n", libraryNameOrPath); } - - if (!dl_handle) + else if (setLastError) { - WARN("dlopen() failed; dlerror says '%s'\n", dlerror()); + WARN("dlopen() failed; dlerror says '%s'\n", dlerror()); SetLastError(ERROR_MOD_NOT_FOUND); - goto done; } - TRACE("dlopen() found module %s\n", shortAsciiName); + + return dl_handle; +} + +/* +Function: + LOADRegisterLibraryDirect [internal] + + Registers a system handle to a loaded library with the module list. + +Parameters: + HMODULE dl_handle: System handle to the loaded library. + LPCSTR libraryNameOrPath: The library that was loaded. + BOOL fDynamic: TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary. + +Return value: + PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()). +*/ +static HMODULE LOADRegisterLibraryDirect(HMODULE dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic) +{ + _ASSERTE(dl_handle != nullptr); + _ASSERTE(libraryNameOrPath != nullptr); + _ASSERTE(libraryNameOrPath[0] != '\0'); + + MODSTRUCT *module; + DWORD dwError; #if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN /* search module list for a match. */ @@ -1388,25 +1475,25 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) /* found the handle. increment the refcount and return the existing module structure */ TRACE("Found matching module %p for module name %s\n", - module, shortAsciiName); + module, libraryNameOrPath); if (module->refcount != -1) module->refcount++; dlclose(dl_handle); - goto done; + return module; } module = module->next; } while (module != &exe_module); #endif - TRACE("Module doesn't exist : creating %s.\n", shortAsciiName); - module = LOADAllocModule(dl_handle, shortAsciiName); + TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath); + module = LOADAllocModule(dl_handle, libraryNameOrPath); if (NULL == module) { ERROR("couldn't create new module\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); dlclose(dl_handle); - goto done; + return nullptr; } /* Add the new module on to the end of the list */ @@ -1441,7 +1528,7 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule"); if (registerModule) { - module->hinstance = registerModule(shortAsciiName); + module->hinstance = registerModule(libraryNameOrPath); } else { @@ -1452,6 +1539,7 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) } } + BOOL dllMainRetVal; { #if !_NO_DEBUG_MESSAGES_ /* reset ENTRY nesting level back to zero while inside the callback... */ @@ -1463,7 +1551,7 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) // This module may be foreign to our PAL, so leave our PAL. // If it depends on us, it will re-enter. PAL_LeaveHolder holder; - retval = module->pDllMain(module->hinstance, DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1); + dllMainRetVal = module->pDllMain(module->hinstance, DLL_PROCESS_ATTACH, fDynamic ? NULL : (LPVOID)-1); } #if !_NO_DEBUG_MESSAGES_ @@ -1473,14 +1561,14 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) } // If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module - if (!retval) + if (!dllMainRetVal) { ERROR("DllMain returned FALSE; unloading module.\n"); module->pDllMain = NULL; FreeLibrary((HMODULE)module); SetLastError(ERROR_DLL_INIT_FAILED); module = NULL; - goto done; + return nullptr; } } else @@ -1488,9 +1576,96 @@ static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) TRACE("Module does not contain a DllMain function.\n"); } + return module; +} + +/*++ +Function : + LOADLoadLibrary [internal] + + implementation of LoadLibrary (for use by the A/W variants) + +Parameters : + LPSTR shortAsciiName : name of module as specified to LoadLibrary + + BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary + +Return value : + handle to loaded module + +--*/ +static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic) +{ + CHAR fullLibraryName[MAX_LONGPATH]; + HMODULE module = NULL; + HMODULE dl_handle = NULL; + + // Check whether we have been requested to load 'libc'. If that's the case then use the + // full name of the library that is defined in <gnu/lib-names.h> by the LIBC_SO constant. + // The problem is that calling dlopen("libc.so") will fail for libc even thought it works + // for other libraries. The reason is that libc.so is just linker script (i.e. a test file). + // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO. + if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0) + { +#if defined(__APPLE__) + shortAsciiName = "libc.dylib"; +#elif defined(__FreeBSD__) + shortAsciiName = FREEBSD_LIBC; +#else + shortAsciiName = LIBC_SO; +#endif + } + + LockModuleList(); + + // See if file can be dlopen()ed; this should work even if it's already loaded + { + // See GetProcAddress for an explanation why we leave the PAL. + PAL_LeaveHolder holder; + + // P/Invokes are often declared with variations on the actual library name. + // For example, it's common to leave off the extension/suffix of the library + // even if it has one, or to leave off a prefix like "lib" even if it has one + // (both of these are done typically to smooth over cross-platform differences). + // We try to dlopen with such variations on the original. + const char* const formatStrings[4] = // used with args: PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX + { + "%s%s%s", // prefix+name+suffix + "%.0s%s%.0s", // name + "%.0s%s%s", // name+suffix + "%s%s%.0s", // prefix+name + }; + const int skipPrefixing = strchr(shortAsciiName, '/') != NULL; // skip prefixing if the name is actually a path + for (int i = 0; i < 4; i++) + { + if (skipPrefixing && (i == 0 || i == 3)) // 0th and 3rd strings include prefixes + continue; + + _ASSERTE(dl_handle == nullptr); + if (snprintf(fullLibraryName, MAX_LONGPATH, formatStrings[i], PAL_SHLIB_PREFIX, shortAsciiName, PAL_SHLIB_SUFFIX) < MAX_LONGPATH) + { + dl_handle = LOADLoadLibraryDirect(fullLibraryName, false /* setLastError */); + if (dl_handle != nullptr) + { + shortAsciiName = fullLibraryName; + break; + } + } + } + } + + if (!dl_handle) + { + WARN("dlopen() failed; dlerror says '%s'\n", dlerror()); + SetLastError(ERROR_MOD_NOT_FOUND); + goto done; + } + + module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic); + done: UnlockModuleList(); - return (HMODULE)module; + return module; } /*++ diff --git a/src/pal/src/memory/heap.cpp b/src/pal/src/memory/heap.cpp index b85e02fd77..5cc59d0c91 100644 --- a/src/pal/src/memory/heap.cpp +++ b/src/pal/src/memory/heap.cpp @@ -26,7 +26,6 @@ Revision History: #include "pal/handlemgr.hpp" #include "pal/corunix.hpp" #include <errno.h> -#define HEAP_SIZEINFO_SIZE (2 * sizeof(DWORD)) using namespace CorUnix; SET_DEFAULT_DEBUG_CHANNEL(MEM); @@ -36,12 +35,10 @@ SET_DEFAULT_DEBUG_CHANNEL(MEM); // should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MEM) #include <safemath.h> -#define HEAP_MAGIC 0xEAFDC9BB #ifndef __APPLE__ #define DUMMY_HEAP 0x01020304 #endif // __APPLE__ - #ifdef __APPLE__ #define CACHE_HEAP_ZONE #endif // __APPLE__ @@ -192,33 +189,6 @@ GetProcessHeap( /*++ Function: -HeapSize - -See MSDN doc. ---*/ -SIZE_T -PALAPI -HeapSize( - HANDLE hHeap, - DWORD dwFlags, - LPCVOID lpMem) -{ - SIZE_T ret = (SIZE_T)-1; - PERF_ENTRY(HeapSize); - ENTRY("HeapSize(hHeap=%p, dwFlags=%#x, lpMem=%p)\n", - hHeap, dwFlags, lpMem); - - // First four bytes contain magic - // Second four bytes size. - ret = ((DWORD *)(static_cast<LPCBYTE>(lpMem) - HEAP_SIZEINFO_SIZE))[1]; - - LOGEXIT("HeapSize returning %d\n", ret); - PERF_EXIT(HeapSize); - return ret; -} - -/*++ -Function: HeapAlloc Abstract @@ -229,15 +199,15 @@ See MSDN doc. LPVOID PALAPI HeapAlloc( - IN HANDLE hHeap, - IN DWORD dwFlags, - IN SIZE_T dwBytes) + IN HANDLE hHeap, + IN DWORD dwFlags, + IN SIZE_T numberOfBytes) { BYTE *pMem; PERF_ENTRY(HeapAlloc); - ENTRY("HeapAlloc (hHeap=%p, dwFlags=%#x, dwBytes=%u)\n", - hHeap, dwFlags, dwBytes); + ENTRY("HeapAlloc (hHeap=%p, dwFlags=%#x, numberOfBytes=%u)\n", + hHeap, dwFlags, numberOfBytes); #ifdef __APPLE__ if (hHeap == NULL) @@ -261,26 +231,16 @@ HeapAlloc( return NULL; } - - size_t fullsize; - if (!ClrSafeInt<size_t>::addition(dwBytes, HEAP_SIZEINFO_SIZE,fullsize)) - { - ERROR("Integer Overflow\n"); - SetLastError(ERROR_ARITHMETIC_OVERFLOW); - LOGEXIT("HeapAlloc returning NULL\n"); - PERF_EXIT(HeapAlloc); - return NULL; - } #ifdef __APPLE__ // This is patterned off of InternalMalloc in malloc.cpp. { CPalThread *pthrCurrent = InternalGetCurrentThread(); pthrCurrent->suspensionInfo.EnterUnsafeRegion(); - pMem = (BYTE *)malloc_zone_malloc((malloc_zone_t *)hHeap, fullsize); + pMem = (BYTE *)malloc_zone_malloc((malloc_zone_t *)hHeap, numberOfBytes); pthrCurrent->suspensionInfo.LeaveUnsafeRegion(); } #else // __APPLE__ - pMem = (BYTE *) PAL_malloc(fullsize); + pMem = (BYTE *) PAL_malloc(numberOfBytes); #endif // __APPLE__ else if (pMem == NULL) @@ -292,20 +252,15 @@ HeapAlloc( return NULL; } - /* use a magic number, to know it has been allocated with HeapAlloc - when doing HeapFree */ - ((DWORD *) pMem)[0] = HEAP_MAGIC; - /* Store the size in the second word */ - ((DWORD *)pMem)[1] = dwBytes; - - /*If the Heap Zero memory flag is set initialize to zero*/ + /* If the HEAP_ZERO_MEMORY flag is set initialize to zero */ if (dwFlags == HEAP_ZERO_MEMORY) { - memset(pMem+ HEAP_SIZEINFO_SIZE, 0, dwBytes); + memset(pMem, 0, numberOfBytes); } - LOGEXIT("HeapAlloc returning LPVOID %p\n", pMem + HEAP_SIZEINFO_SIZE); + + LOGEXIT("HeapAlloc returning LPVOID %p\n", pMem); PERF_EXIT(HeapAlloc); - return (pMem + HEAP_SIZEINFO_SIZE); + return (pMem); } @@ -321,9 +276,9 @@ See MSDN doc. BOOL PALAPI HeapFree( - IN HANDLE hHeap, - IN DWORD dwFlags, - IN LPVOID lpMem) + IN HANDLE hHeap, + IN DWORD dwFlags, + IN LPVOID lpMem) { BOOL bRetVal = FALSE; @@ -349,23 +304,12 @@ HeapFree( goto done; } - if ( !lpMem ) + if (!lpMem) { bRetVal = TRUE; goto done; } - /*HEAP_SIZEINFO_SIZE + nMemAlloc is the size of Magic Number plus - *size of the int to store value of Memory allocated */ - lpMem = static_cast<LPVOID>(static_cast<LPBYTE>(lpMem) - HEAP_SIZEINFO_SIZE); - - /* check if the memory has been allocated by HeapAlloc */ - if (*((DWORD *) lpMem) != HEAP_MAGIC) - { - ERROR("Pointer hasn't been allocated with HeapAlloc (%p)\n", - static_cast<LPBYTE>(lpMem) + HEAP_SIZEINFO_SIZE); - SetLastError(ERROR_INVALID_PARAMETER); - goto done; - } + *((DWORD *) lpMem) = 0; bRetVal = TRUE; @@ -400,21 +344,21 @@ See MSDN doc. LPVOID PALAPI HeapReAlloc( - IN HANDLE hHeap, - IN DWORD dwFlags, - IN LPVOID lpmem, - IN SIZE_T dwBytes) + IN HANDLE hHeap, + IN DWORD dwFlags, + IN LPVOID lpmem, + IN SIZE_T numberOfBytes) { BYTE *pMem = NULL; PERF_ENTRY(HeapReAlloc); - ENTRY("HeapReAlloc (hHeap=%p, dwFlags=%#x, lpmem=%p, dwBytes=%u)\n", - hHeap, dwFlags, lpmem, dwBytes); + ENTRY("HeapReAlloc (hHeap=%p, dwFlags=%#x, lpmem=%p, numberOfBytes=%u)\n", + hHeap, dwFlags, lpmem, numberOfBytes); #ifdef __APPLE__ if (hHeap == NULL) #else // __APPLE__ - if (hHeap != (HANDLE) DUMMY_HEAP) + if (hHeap != (HANDLE)DUMMY_HEAP) #endif // __APPLE__ else { ASSERT("Invalid heap handle\n"); @@ -438,26 +382,10 @@ HeapReAlloc( goto done; } - /*HEAP_SIZEINFO_SIZE + nMemAlloc is the size of Magic Number plus - *size of the int to store value of Memory allocated */ - lpmem = static_cast<LPVOID>(static_cast<LPBYTE>(lpmem) - HEAP_SIZEINFO_SIZE); - - /* check if the memory has been allocated by HeapAlloc */ - if (*((DWORD *) lpmem) != HEAP_MAGIC) + if(numberOfBytes == 0) { - ERROR("Pointer hasn't been allocated with HeapAlloc (%p)\n", - static_cast<LPBYTE>(lpmem) + HEAP_SIZEINFO_SIZE); - SetLastError(ERROR_INVALID_PARAMETER); - goto done; - } - - - size_t fullsize; - if (!ClrSafeInt<size_t>::addition(dwBytes, HEAP_SIZEINFO_SIZE, fullsize)) - { - ERROR("Integer Overflow\n"); - SetLastError(ERROR_ARITHMETIC_OVERFLOW); - goto done; + // PAL's realloc behaves like free for a requested size of zero bytes. Force a nonzero size to get a valid pointer. + numberOfBytes = 1; } #ifdef __APPLE__ @@ -465,11 +393,11 @@ HeapReAlloc( { CPalThread *pthrCurrent = InternalGetCurrentThread(); pthrCurrent->suspensionInfo.EnterUnsafeRegion(); - pMem = (BYTE *) malloc_zone_realloc((malloc_zone_t *)hHeap, lpmem, fullsize); + pMem = (BYTE *) malloc_zone_realloc((malloc_zone_t *)hHeap, lpmem, numberOfBytes); pthrCurrent->suspensionInfo.LeaveUnsafeRegion(); } #else // __APPLE__ - pMem = (BYTE *) PAL_realloc(lpmem,fullsize); + pMem = (BYTE *) PAL_realloc(lpmem, numberOfBytes); #endif // __APPLE__ else if (pMem == NULL) @@ -479,14 +407,10 @@ HeapReAlloc( goto done; } - /* use a magic number, to know it has been allocated with HeapAlloc - when doing HeapFree */ - *((DWORD *) pMem) = HEAP_MAGIC; - done: - LOGEXIT("HeapReAlloc returns LPVOID %p\n", pMem ? (pMem + HEAP_SIZEINFO_SIZE) : pMem); + LOGEXIT("HeapReAlloc returns LPVOID %p\n", pMem); PERF_EXIT(HeapReAlloc); - return pMem ? (pMem + HEAP_SIZEINFO_SIZE) : pMem; + return pMem; } BOOL diff --git a/src/pal/src/misc/perftrace.cpp b/src/pal/src/misc/perftrace.cpp index d2bfd797cf..d4223a629a 100644 --- a/src/pal/src/misc/perftrace.cpp +++ b/src/pal/src/misc/perftrace.cpp @@ -785,7 +785,7 @@ PERFReadSetting( ) //more code is required to deal with corrupted input file. BOOL ret; unsigned int index; - char line[256 /* PAL_PERF_MAX_INPUT */]; // just use it. can define a new one like MAX_LINE=1024; + char line[PAL_PERF_MAX_INPUT]; char * ptr; char function_name[PAL_PERF_MAX_FUNCTION_NAME]; //no function can be longer than 127 bytes. diff --git a/src/pal/src/misc/stackstring.cpp b/src/pal/src/misc/stackstring.cpp new file mode 100644 index 0000000000..d35c0d88fc --- /dev/null +++ b/src/pal/src/misc/stackstring.cpp @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include "pal/malloc.hpp" +#include "pal/dbgmsg.h" + +SET_DEFAULT_DEBUG_CHANNEL(MISC); + +template <SIZE_T STACKCOUNT> +class StackString +{ +private: + WCHAR m_innerBuffer[STACKCOUNT + 1]; + WCHAR * m_buffer; + SIZE_T m_count; // actual allocated count + + void NullTerminate() + { + m_buffer[m_count] = W('\0'); + } + + void DeleteBuffer() + { + if (m_innerBuffer != m_buffer) + PAL_free(m_buffer); + + m_buffer = NULL; + return; + } + + void ReallocateBuffer(SIZE_T count) + { + // count is always > STACKCOUNT here. + WCHAR * newBuffer = (WCHAR *)PAL_malloc((count + 1) * sizeof(WCHAR)); + if (NULL == newBuffer) + { + ERROR("malloc failed\n"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + DeleteBuffer(); + m_count = 0; + + return; + } + + DeleteBuffer(); + m_buffer = newBuffer; + m_count = count; + + return; + } + + void Resize(SIZE_T count) + { + if (NULL == m_buffer) + { + if (count > STACKCOUNT) + { + ReallocateBuffer(count); + } + else + { + m_buffer = m_innerBuffer; + m_count = count; + } + } + else if (m_innerBuffer == m_buffer) + { + if (count > STACKCOUNT) + ReallocateBuffer(count); + else + m_count = count; + } + else + { + ReallocateBuffer(count); + } + + return; + } + + StackString(const StackString &s) + { + Set(s); + } + + ~StackString() + { + DeleteBuffer(); + } + +public: + StackString() + : m_count(0), m_buffer(m_innerBuffer) + { + } + + BOOL Set(const WCHAR * buffer, SIZE_T count) + { + Resize(count); + if (NULL == m_buffer) + return FALSE; + + CopyMemory(m_buffer, buffer, (count + 1) * sizeof(WCHAR)); + NullTerminate(); + return TRUE; + } + + BOOL Set(const StackString &s) + { + return Set(s.m_buffer, s.m_count); + } + + SIZE_T Getcount() const + { + return m_count; + } + + CONST WCHAR * GetString() const + { + return (const WCHAR *)m_buffer; + } + + WCHAR * OpenStringBuffer(SIZE_T count) + { + Resize(count); + return (WCHAR *)m_buffer; + } + + void CloseBuffer(SIZE_T count) + { + if (m_count > count) + m_count = count; + + NullTerminate(); + return; + } +}; diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp index a1c6eb6c14..4bda53f3f5 100644 --- a/src/pal/src/thread/thread.cpp +++ b/src/pal/src/thread/thread.cpp @@ -2428,79 +2428,108 @@ ThreadInitializationRoutine( return NO_ERROR; } +// Get base address of this thread's stack +// Can be called only for the current thread. void * -PALAPI -PAL_GetStackBase() +CPalThread::GetStackBase() { + _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetStackBase called from foreign thread"); + + if (m_stackBase == NULL) + { #ifdef _TARGET_MAC64 - // This is a Mac specific method - return pthread_get_stackaddr_np(pthread_self()); + // This is a Mac specific method + m_stackBase = pthread_get_stackaddr_np(pthread_self()); #else - pthread_attr_t attr; - void* stackAddr; - size_t stackSize; - int status; - - pthread_t thread = pthread_self(); - - status = pthread_attr_init(&attr); - _ASSERT_MSG(status == 0, "pthread_attr_init call failed"); + pthread_attr_t attr; + void* stackAddr; + size_t stackSize; + int status; + + pthread_t thread = pthread_self(); + + status = pthread_attr_init(&attr); + _ASSERT_MSG(status == 0, "pthread_attr_init call failed"); #if HAVE_PTHREAD_ATTR_GET_NP - status = pthread_attr_get_np(thread, &attr); + status = pthread_attr_get_np(thread, &attr); #elif HAVE_PTHREAD_GETATTR_NP - status = pthread_getattr_np(thread, &attr); + status = pthread_getattr_np(thread, &attr); #else #error Dont know how to get thread attributes on this platform! #endif - _ASSERT_MSG(status == 0, "pthread_getattr_np call failed"); + _ASSERT_MSG(status == 0, "pthread_getattr_np call failed"); - status = pthread_attr_getstack(&attr, &stackAddr, &stackSize); - _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed"); + status = pthread_attr_getstack(&attr, &stackAddr, &stackSize); + _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed"); - status = pthread_attr_destroy(&attr); - _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed"); + status = pthread_attr_destroy(&attr); + _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed"); - return (void*)((size_t)stackAddr + stackSize); + m_stackBase = (void*)((size_t)stackAddr + stackSize); #endif + } + + return m_stackBase; } +// Get limit address of this thread's stack. +// Can be called only for the current thread. void * -PALAPI -PAL_GetStackLimit() +CPalThread::GetStackLimit() { + _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetStackLimit called from foreign thread"); + + if (m_stackLimit == NULL) + { #ifdef _TARGET_MAC64 - // This is a Mac specific method - return ((BYTE *)pthread_get_stackaddr_np(pthread_self()) - - pthread_get_stacksize_np(pthread_self())); + // This is a Mac specific method + m_stackLimit = ((BYTE *)pthread_get_stackaddr_np(pthread_self()) - + pthread_get_stacksize_np(pthread_self())); #else - pthread_attr_t attr; - void* stackAddr; - size_t stackSize; - int status; - - pthread_t thread = pthread_self(); - - status = pthread_attr_init(&attr); - _ASSERT_MSG(status == 0, "pthread_attr_init call failed"); + pthread_attr_t attr; + size_t stackSize; + int status; + + pthread_t thread = pthread_self(); + + status = pthread_attr_init(&attr); + _ASSERT_MSG(status == 0, "pthread_attr_init call failed"); #if HAVE_PTHREAD_ATTR_GET_NP - status = pthread_attr_get_np(thread, &attr); + status = pthread_attr_get_np(thread, &attr); #elif HAVE_PTHREAD_GETATTR_NP - status = pthread_getattr_np(thread, &attr); + status = pthread_getattr_np(thread, &attr); #else #error Dont know how to get thread attributes on this platform! #endif - _ASSERT_MSG(status == 0, "pthread_getattr_np call failed"); + _ASSERT_MSG(status == 0, "pthread_getattr_np call failed"); - status = pthread_attr_getstack(&attr, &stackAddr, &stackSize); - _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed"); + status = pthread_attr_getstack(&attr, &m_stackLimit, &stackSize); + _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed"); - status = pthread_attr_destroy(&attr); - _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed"); - - return stackAddr; + status = pthread_attr_destroy(&attr); + _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed"); #endif + } + + return m_stackLimit; +} + +void * +PALAPI +PAL_GetStackBase() +{ + CPalThread* thread = InternalGetCurrentThread(); + return thread->GetStackBase(); +} + +void * +PALAPI +PAL_GetStackLimit() +{ + CPalThread* thread = InternalGetCurrentThread(); + return thread->GetStackLimit(); } PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread); diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c index 896934065b..7c825375eb 100644 --- a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c +++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c @@ -317,7 +317,7 @@ void starttests(int threadID) ULONGLONG startTime = 0; ULONGLONG endTime = 0; - LONG volatile * Destination; + LONG volatile Destination; LONG Exchange; LONG Comperand; LONG result; @@ -336,10 +336,10 @@ void starttests(int threadID) for (i=0;i<REPEAT_COUNT;i++) { - *Destination = (LONG volatile) threadID; + Destination = (LONG volatile) threadID; Exchange = (LONG) i; Comperand = (LONG) threadID; - result = InterlockedCompareExchange( Destination, Exchange, Comperand); + result = InterlockedCompareExchange(&Destination, Exchange, Comperand); if( i != result ) { diff --git a/src/tools/crossgen/crossgen.cpp b/src/tools/crossgen/crossgen.cpp index 192f6b1bf8..9bdfdd7294 100644 --- a/src/tools/crossgen/crossgen.cpp +++ b/src/tools/crossgen/crossgen.cpp @@ -282,7 +282,7 @@ bool ComputeMscorlibPathFromTrustedPlatformAssemblies(LPWSTR pwzMscorlibPath, DW { LPWSTR wszTrustedPathCopy = new WCHAR[wcslen(pwzTrustedPlatformAssemblies) + 1]; wcscpy_s(wszTrustedPathCopy, wcslen(pwzTrustedPlatformAssemblies) + 1, pwzTrustedPlatformAssemblies); - LPWSTR wszSingleTrustedPath = wcstok(wszTrustedPathCopy, W(";")); + LPWSTR wszSingleTrustedPath = wcstok(wszTrustedPathCopy, PATH_SEPARATOR_STR_W); while (wszSingleTrustedPath != NULL) { @@ -294,12 +294,12 @@ bool ComputeMscorlibPathFromTrustedPlatformAssemblies(LPWSTR pwzMscorlibPath, DW wszSingleTrustedPath++; } - if (StringEndsWith(wszSingleTrustedPath, W("\\mscorlib.dll")) || - StringEndsWith(wszSingleTrustedPath, W("\\mscorlib.ni.dll"))) + if (StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W W("mscorlib.dll")) || + StringEndsWith(wszSingleTrustedPath, DIRECTORY_SEPARATOR_STR_W W("mscorlib.ni.dll"))) { wcscpy_s(pwzMscorlibPath, cbMscorlibPath, wszSingleTrustedPath); - LPWSTR pwzSeparator = wcsrchr(pwzMscorlibPath, W('\\')); + LPWSTR pwzSeparator = wcsrchr(pwzMscorlibPath, DIRECTORY_SEPARATOR_CHAR_W); if (pwzSeparator == NULL) { delete [] wszTrustedPathCopy; @@ -311,7 +311,7 @@ bool ComputeMscorlibPathFromTrustedPlatformAssemblies(LPWSTR pwzMscorlibPath, DW return true; } - wszSingleTrustedPath = wcstok(NULL, W(";")); + wszSingleTrustedPath = wcstok(NULL, PATH_SEPARATOR_STR_W); } delete [] wszTrustedPathCopy; @@ -370,7 +370,7 @@ void PopulateTPAList(SString path, LPCWSTR pwszMask, SString &refTPAList, bool f if (fAddDelimiter) { // Add the path delimiter if we already have entries in the TPAList - refTPAList.Append(W(";")); + refTPAList.Append(PATH_SEPARATOR_CHAR_W); } // Add the path to the TPAList refTPAList.Append(path); @@ -400,7 +400,7 @@ void ComputeTPAListFromPlatformAssembliesPath(LPCWSTR pwzPlatformAssembliesPaths while (itr != end) { start = itr; - BOOL found = ssPlatformAssembliesPath.Find(itr, W(';')); + BOOL found = ssPlatformAssembliesPath.Find(itr, PATH_SEPARATOR_CHAR_W); if (!found) { itr = end; @@ -417,9 +417,9 @@ void ComputeTPAListFromPlatformAssembliesPath(LPCWSTR pwzPlatformAssembliesPaths if (len > 0) { - if (qualifiedPath[len-1]!='\\') + if (qualifiedPath[len-1]!=DIRECTORY_SEPARATOR_CHAR_W) { - qualifiedPath.Append('\\'); + qualifiedPath.Append(DIRECTORY_SEPARATOR_CHAR_W); } // Enumerate the EXE/DLL modules within this path and add them to the TPAList diff --git a/src/utilcode/dlwrap.cpp b/src/utilcode/dlwrap.cpp index f649e5267b..10acc61b76 100644 --- a/src/utilcode/dlwrap.cpp +++ b/src/utilcode/dlwrap.cpp @@ -86,6 +86,7 @@ VerQueryValueW_NoThrow( // is available, and then it will remove unused functions. // Instead of specifying all libs for imported functions needed by the following codes, we just // remove them from compiling phase. +__success(return) BOOL CreateUrlCacheEntryW_NoThrow( IN LPCWSTR lpszUrlName, diff --git a/src/utilcode/downlevel.cpp b/src/utilcode/downlevel.cpp index 3b818e59f2..54d09553be 100644 --- a/src/utilcode/downlevel.cpp +++ b/src/utilcode/downlevel.cpp @@ -1810,6 +1810,7 @@ namespace DownLevel return cchSrc; } + __success(return != 0) int LinguisticCaseString(__in LCID lcid,__in DWORD flags, __in_ecount(cchSrc) const WCHAR * source, __in int cchSrc, diff --git a/src/utilcode/posterror.cpp b/src/utilcode/posterror.cpp index 0ae48aab71..e409695a4b 100644 --- a/src/utilcode/posterror.cpp +++ b/src/utilcode/posterror.cpp @@ -256,7 +256,7 @@ HRESULT FillErrorInfo( // Return status. } CONTRACTL_END; - ICreateErrorInfo *pICreateErr; // Error info creation Iface pointer. + ICreateErrorInfo *pICreateErr = NULL; // Error info creation Iface pointer. IErrorInfo *pIErrInfo = NULL; // The IErrorInfo interface. HRESULT hr; // Return status. diff --git a/src/utilcode/registrywrapper.cpp b/src/utilcode/registrywrapper.cpp index e48fb0941c..96a1d6c886 100644 --- a/src/utilcode/registrywrapper.cpp +++ b/src/utilcode/registrywrapper.cpp @@ -217,10 +217,12 @@ HRESULT CheckUseWow6432Node(REGSAM samDesired, bool * fResult) // lpRedirectedKey is allocated and returned from this method. Caller owns the new string and // should release // +__success(return == ERROR_SUCCESS) HRESULT RedirectKey(REGSAM samDesired, HKEY hKey, LPCWSTR lpKey, __deref_out_z LPWSTR * lpRedirectedKey) { if (hKey != kRegistryRootHive || _wcsnicmp(lpKey, kRegistryRootKey, wcslen(kRegistryRootKey)) != 0) { + *lpRedirectedKey = NULL; return ERROR_SUCCESS; } diff --git a/src/utilcode/regutil.cpp b/src/utilcode/regutil.cpp index c7c37aa028..9fa98b0b71 100644 --- a/src/utilcode/regutil.cpp +++ b/src/utilcode/regutil.cpp @@ -1130,8 +1130,8 @@ HRESULT REGUTIL::RegisterTypeLib( // Return code. WCHAR szID[64]; // The typelib ID to register. WCHAR szTLBID[256]; // TypeLib\\szID. WCHAR szHelpDir[_MAX_PATH]; - WCHAR szDrive[_MAX_DRIVE]; - WCHAR szDir[_MAX_DIR]; + WCHAR szDrive[_MAX_DRIVE] = {0}; + WCHAR szDir[_MAX_DIR] = {0}; WCHAR szVersion[64]; LPWSTR szTmp; diff --git a/src/utilcode/securitywrapper.cpp b/src/utilcode/securitywrapper.cpp index 1fa8fca54a..f9d709c1e2 100644 --- a/src/utilcode/securitywrapper.cpp +++ b/src/utilcode/securitywrapper.cpp @@ -412,13 +412,14 @@ void SidBuffer::InitFromProcess(DWORD pid) HRESULT SidBuffer::InitFromProcessAppContainerSidNoThrow(DWORD pid) { HRESULT hr = S_OK; + HANDLE hToken = NULL; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (hProcess == NULL) { hr = HRESULT_FROM_GetLastError(); goto exit; } - HANDLE hToken = NULL; if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) { hr = HRESULT_FROM_GetLastError(); diff --git a/src/utilcode/sortversioning.cpp b/src/utilcode/sortversioning.cpp index 6b9f56cc8c..5f0d75b58e 100644 --- a/src/utilcode/sortversioning.cpp +++ b/src/utilcode/sortversioning.cpp @@ -209,6 +209,7 @@ namespace SortVersioning } // Attempts to load a Sort DLL. If this fails, the values of the __out parameters are unchanged. + __success(return) BOOL LoadSortDllAndPublish( __in LPCWSTR sDllName, __in DWORD dwVersion, diff --git a/src/utilcode/util.cpp b/src/utilcode/util.cpp index e7d6a620ff..062cf61d95 100644 --- a/src/utilcode/util.cpp +++ b/src/utilcode/util.cpp @@ -3783,6 +3783,7 @@ namespace Com { namespace __imp { + __success(return == S_OK) static HRESULT FindSubKeyDefaultValueForCLSID(REFCLSID rclsid, LPCWSTR wszSubKeyName, SString & ssValue) { @@ -3803,6 +3804,7 @@ namespace Com return Clr::Util::Reg::ReadStringValue(HKEY_CLASSES_ROOT, ssKeyName.GetUnicode(), NULL, ssValue); } + __success(return == S_OK) static HRESULT FindSubKeyDefaultValueForCLSID(REFCLSID rclsid, LPCWSTR wszSubKeyName, __deref_out __deref_out_z LPWSTR* pwszValue) { diff --git a/src/utilcode/util_nodependencies.cpp b/src/utilcode/util_nodependencies.cpp index 27720ae0f8..9f4bc9423d 100644 --- a/src/utilcode/util_nodependencies.cpp +++ b/src/utilcode/util_nodependencies.cpp @@ -516,7 +516,7 @@ HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString, } // Look in AeDebug key for "Debugger"; get the size of any value stored there. - DWORD valueType, valueSize; + DWORD valueType, valueSize = 0; ret = WszRegQueryValueEx(hKeyHolder, kUnmanagedDebuggerValue, 0, &valueType, 0, &valueSize); _ASSERTE(pcchDebuggerString != NULL); diff --git a/src/utilcode/utilmessagebox.cpp b/src/utilcode/utilmessagebox.cpp index f28d2d48f3..8b936daea8 100644 --- a/src/utilcode/utilmessagebox.cpp +++ b/src/utilcode/utilmessagebox.cpp @@ -190,7 +190,7 @@ int MessageBoxImpl( mustUseMessageBox = (pfnTaskDialogIndirect == NULL); } - int result; + int result = MB_OK; if (mustUseMessageBox) { result = WszMessageBox(hWnd, message, title, uType); } @@ -247,6 +247,9 @@ int MessageBoxImpl( if (hr == S_OK) { result = nButtonPressed; } + else { + result = IDOK; + } _ASSERTE(result == IDOK || result == IDRETRY || result == IDIGNORE); } diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 9282ce1d75..e1e6138644 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -207,6 +207,7 @@ set(VM_SOURCES_WKS listlock.cpp managedmdimport.cpp marshalnative.cpp + marvin32.cpp mdaassistants.cpp message.cpp methodtablebuilder.cpp @@ -276,7 +277,6 @@ set(VM_SOURCES_DAC_AND_WKS_WIN32 list(APPEND VM_SOURCES_WKS ${VM_SOURCES_DAC_AND_WKS_WIN32} - marvin32.cpp # move out of win32 when FEATURE_RANDOMIZED_STRING_HASHING is enabled for linux # These should not be included for Linux appxutil.cpp assemblynativeresource.cpp diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 0067f6b37e..aed588c61d 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -8256,8 +8256,11 @@ public: } else { - IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, *pcchBuffer)); - *pcchBuffer = cchName; + IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchBuffer)); + if (pcchBuffer != nullptr) + { + *pcchBuffer = cchName; + } return S_OK; } } diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp index 5b4e0c5347..b6b69ca900 100644 --- a/src/vm/assemblynative.cpp +++ b/src/vm/assemblynative.cpp @@ -25,6 +25,7 @@ #include "asm.h" #endif #include "assemblynative.hpp" +#include "dllimport.h" #include "field.h" #include "assemblyname.hpp" #include "eeconfig.h" @@ -880,6 +881,22 @@ void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext END_QCALL; } +// static +INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath) +{ + QCALL_CONTRACT; + + HMODULE moduleHandle = nullptr; + + BEGIN_QCALL; + + moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath); + + END_QCALL; + + return reinterpret_cast<INT_PTR>(moduleHandle); +} + /*static */ void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray, INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength, diff --git a/src/vm/assemblynative.hpp b/src/vm/assemblynative.hpp index f4ca12ee68..23c9914795 100644 --- a/src/vm/assemblynative.hpp +++ b/src/vm/assemblynative.hpp @@ -279,6 +279,7 @@ public: static BOOL QCALLTYPE OverrideDefaultAssemblyLoadContextForCurrentDomain(INT_PTR ptrNativeAssemblyLoadContext); static BOOL QCALLTYPE CanUseAppPathAssemblyLoadContextInCurrentDomain(); static void QCALLTYPE LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly); + static INT_PTR QCALLTYPE InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath); static void QCALLTYPE LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray, INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength, QCall::ObjectHandleOnStack retLoadedAssembly); static Assembly* LoadFromPEImage(CLRPrivBinderAssemblyLoadContext* pBinderContext, PEImage *pILImage, PEImage *pNIImage); static INT_PTR QCALLTYPE GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly); diff --git a/src/vm/assemblynativeresource.cpp b/src/vm/assemblynativeresource.cpp index 2f13e2b78d..8c18299c9d 100644 --- a/src/vm/assemblynativeresource.cpp +++ b/src/vm/assemblynativeresource.cpp @@ -281,8 +281,8 @@ VOID Win32Res::WriteVerResource() WORD cbStringBlocks; int i; bool bUseFileVer = false; - WCHAR rcFile[_MAX_PATH]; // Name of file without path - WCHAR rcFileExtension[_MAX_PATH]; // file extension + WCHAR rcFile[_MAX_PATH] = {0}; // Name of file without path + WCHAR rcFileExtension[_MAX_PATH] = {0}; // file extension WCHAR rcFileName[_MAX_PATH]; // Name of file with extension but without path DWORD cbTmp; diff --git a/src/vm/callingconvention.h b/src/vm/callingconvention.h index b1ed3853c6..244a3df878 100644 --- a/src/vm/callingconvention.h +++ b/src/vm/callingconvention.h @@ -1282,6 +1282,7 @@ void ArgIteratorTemplate<ARGITERATOR_BASE>::ForceSigWalk() #ifdef FEATURE_INTERPRETER BYTE callconv = CallConv(); switch (callconv) + { case IMAGE_CEE_CS_CALLCONV_C: case IMAGE_CEE_CS_CALLCONV_STDCALL: numRegistersUsed = NUM_ARGUMENT_REGISTERS; diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp index b379d94365..d3d5bb8700 100644 --- a/src/vm/ceeload.cpp +++ b/src/vm/ceeload.cpp @@ -3068,7 +3068,7 @@ BOOL Module::IsRuntimeWrapExceptions() if (hr == S_OK) { CustomAttributeParser ca(pVal, cbVal); - CaNamedArg namedArgs[1]; + CaNamedArg namedArgs[1] = {{0}}; // First, the void constructor: IfFailGo(ParseKnownCaArgs(ca, NULL, 0)); diff --git a/src/vm/clrprivbinderfusion.cpp b/src/vm/clrprivbinderfusion.cpp index aedecde9c6..8b27d7942f 100644 --- a/src/vm/clrprivbinderfusion.cpp +++ b/src/vm/clrprivbinderfusion.cpp @@ -232,7 +232,7 @@ public: STDMETHOD(GetName)( - __out LPDWORD lpcwBuffer, + __inout LPDWORD lpcwBuffer, __out_ecount_opt(*lpcwBuffer) WCHAR *pwzName) { LIMITED_METHOD_CONTRACT; diff --git a/src/vm/clrprivbinderwinrt.cpp b/src/vm/clrprivbinderwinrt.cpp index dc6556a7cf..1532943f35 100644 --- a/src/vm/clrprivbinderwinrt.cpp +++ b/src/vm/clrprivbinderwinrt.cpp @@ -390,7 +390,7 @@ HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName( const WCHAR * wszFileName = pFileNameElem->GetValue(); pAssembly = FindAssemblyByFileName(wszFileName); - WCHAR wszFileNameStripped[_MAX_PATH]; + WCHAR wszFileNameStripped[_MAX_PATH] = {0}; SplitPath(wszFileName, NULL, NULL, NULL, NULL, wszFileNameStripped, _MAX_PATH, NULL, NULL); if (pAssembly == nullptr) diff --git a/src/vm/comdynamic.cpp b/src/vm/comdynamic.cpp index 13be5f7008..28bf7ab368 100644 --- a/src/vm/comdynamic.cpp +++ b/src/vm/comdynamic.cpp @@ -1404,7 +1404,7 @@ HRESULT COMDynamicWrite::EmitDebugInfoBegin(Module *pModule, // and fill out the debug directory and save off the symbols now. if (pWriter != NULL) { - IMAGE_DEBUG_DIRECTORY debugDirIDD; + IMAGE_DEBUG_DIRECTORY debugDirIDD = {0}; DWORD debugDirDataSize; BYTE *debugDirData; diff --git a/src/vm/comisolatedstorage.cpp b/src/vm/comisolatedstorage.cpp index 50eb9fe1b0..abdcb9b768 100644 --- a/src/vm/comisolatedstorage.cpp +++ b/src/vm/comisolatedstorage.cpp @@ -312,7 +312,7 @@ void QCALLTYPE COMIsolatedStorageFile::GetRootDir(DWORD dwF QCALL_CONTRACT; BEGIN_QCALL; - WCHAR wszPath[MAX_LONGPATH + 1]; + WCHAR wszPath[MAX_LONGPATH + 1] = {0}; GetRootDirInternal(dwFlags, wszPath, COUNTOF(wszPath)); retRootDir.Set(wszPath); diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp index cf1d399a13..0cb474e2f8 100644 --- a/src/vm/compile.cpp +++ b/src/vm/compile.cpp @@ -759,9 +759,9 @@ HRESULT CEECompileInfo::LoadTypeRefWinRT( Assembly *pAssembly; mdToken tkResolutionScope; - pAssemblyImport->GetResolutionScopeOfTypeRef(ref, &tkResolutionScope); - - if(TypeFromToken(tkResolutionScope) == mdtAssemblyRef) + if(FAILED(pAssemblyImport->GetResolutionScopeOfTypeRef(ref, &tkResolutionScope))) + hr = S_FALSE; + else if(TypeFromToken(tkResolutionScope) == mdtAssemblyRef) { DWORD dwAssemblyRefFlags; IfFailThrow(pAssemblyImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL, diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp index 55a7a1f73a..9664bf9325 100644 --- a/src/vm/comutilnative.cpp +++ b/src/vm/comutilnative.cpp @@ -3067,7 +3067,7 @@ void COMNlsHashProvider::InitializeDefaultSeed() CONTRACTL_END; PCBYTE pEntropy = GetEntropy(); - AllocMemHolder<SYMCRYPT_MARVIN32_EXPANDED_SEED> pSeed = GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_EXPANDED_SEED))); + AllocMemHolder<SYMCRYPT_MARVIN32_EXPANDED_SEED> pSeed(GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_EXPANDED_SEED)))); SymCryptMarvin32ExpandSeed(pSeed, pEntropy, SYMCRYPT_MARVIN32_SEED_SIZE); if(InterlockedCompareExchangeT(&pDefaultSeed, (PCSYMCRYPT_MARVIN32_EXPANDED_SEED) pSeed, NULL) == NULL) @@ -3104,12 +3104,16 @@ PCBYTE COMNlsHashProvider::GetEntropy() if(pEntropy == NULL) { + AllocMemHolder<BYTE> pNewEntropy(GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_SEED_SIZE)))); + +#ifdef FEATURE_PAL + PAL_Random(TRUE, pNewEntropy, SYMCRYPT_MARVIN32_SEED_SIZE); +#else HCRYPTPROV hCryptProv; - AllocMemHolder<BYTE> pNewEntropy = GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_SEED_SIZE))); - WszCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptGenRandom(hCryptProv, SYMCRYPT_MARVIN32_SEED_SIZE, pNewEntropy); CryptReleaseContext(hCryptProv, 0); +#endif if(InterlockedCompareExchangeT(&pEntropy, (PBYTE) pNewEntropy, NULL) == NULL) { @@ -3138,3 +3142,20 @@ void COMNlsHashProvider::CreateMarvin32Seed(INT64 additionalEntropy, PSYMCRYPT_M SymCryptMarvin32ExpandSeed(pExpandedMarvinSeed, (PCBYTE) &entropy, SYMCRYPT_MARVIN32_SEED_SIZE); } #endif // FEATURE_RANDOMIZED_STRING_HASHING + +#ifdef FEATURE_COREFX_GLOBALIZATION +INT32 QCALLTYPE CoreFxGlobalization::HashSortKey(PCBYTE pSortKey, INT32 cbSortKey, BOOL forceRandomizedHashing, INT64 additionalEntropy) +{ + QCALL_CONTRACT; + + INT32 retVal = 0; + + BEGIN_QCALL; + + retVal = COMNlsHashProvider::s_NlsHashProvider.HashSortKey(pSortKey, cbSortKey, forceRandomizedHashing, additionalEntropy); + + END_QCALL; + + return retVal; +} +#endif //FEATURE_COREFX_GLOBALIZATION diff --git a/src/vm/comutilnative.h b/src/vm/comutilnative.h index 0f9c7c9f38..d234d7c62d 100644 --- a/src/vm/comutilnative.h +++ b/src/vm/comutilnative.h @@ -309,4 +309,11 @@ private: #endif // FEATURE_RANDOMIZED_STRING_HASHING }; +#ifdef FEATURE_COREFX_GLOBALIZATION +class CoreFxGlobalization { +public: + static INT32 QCALLTYPE HashSortKey(PCBYTE pSortKey, INT32 cbSortKey, BOOL forceRandomizedHashing, INT64 additionalEntropy); +}; +#endif // FEATURE_COREFX_GLOBALIZATION + #endif // _COMUTILNATIVE_H_ diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp index 71842eef9c..f6fabde447 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -4031,7 +4031,7 @@ struct HiddenParameterInfo void CheckForHiddenParameters(DWORD cParamMarshalInfo, __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo, __out DWORD *pcHiddenNativeParameters, - __out_ecount(*pcHiddenNativeParameters) HiddenParameterInfo **ppHiddenNativeParameters) + __out HiddenParameterInfo **ppHiddenNativeParameters) { CONTRACTL { @@ -6578,6 +6578,25 @@ public: return m_hr; } + void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath) + { + STANDARD_VM_CONTRACT; + + HRESULT theHRESULT = GetHR(); + if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) + { + COMPlusThrow(kBadImageFormatException); + } + else + { + SString hrString; + GetHRMsg(theHRESULT, hrString); + COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, libraryNameOrPath.GetUnicode(), hrString); + } + + __UNREACHABLE(); + } + private: void UpdateHR(DWORD priority, HRESULT hr) { @@ -6593,7 +6612,7 @@ private: }; // class LoadLibErrorTracker -// Local helper function for the LoadLibraryModule below +// Local helper function for the LoadLibraryModule function below static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker ) { STANDARD_VM_CONTRACT; @@ -6636,6 +6655,27 @@ static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTr return hmod; } +// Local helper function for the LoadLibraryFromPath function below +static HMODULE LocalLoadLibraryDirectHelper(LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker) +{ + STANDARD_VM_CONTRACT; + +#ifndef FEATURE_PAL + return LocalLoadLibraryHelper(name, flags, pErrorTracker); +#else // !FEATURE_PAL + // Load the library directly, and don't register it yet with PAL. The system library handle is required here, not the PAL + // handle. The system library handle is registered with PAL to get a PAL handle in LoadLibraryModuleViaHost(). + HMODULE hmod = PAL_LoadLibraryDirect(name); + + if (hmod == NULL) + { + pErrorTracker->TrackErrorCode(GetLastError()); + } + + return hmod; +#endif // !FEATURE_PAL +} + #if !defined(FEATURE_CORESYSTEM) @@ -6771,6 +6811,22 @@ VOID NDirect::CheckUnificationList(NDirectMethodDesc * pMD, DWORD * pDllImportSe } #endif // !FEATURE_CORECLR +// static +HMODULE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath) +{ + STANDARD_VM_CONTRACT; + + LoadLibErrorTracker errorTracker; + const HMODULE systemModuleHandle = + LocalLoadLibraryDirectHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker); + if (systemModuleHandle == nullptr) + { + SString libraryPathSString(libraryPath); + errorTracker.Throw(libraryPathSString); + } + return systemModuleHandle; +} + #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) /* static */ HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName) @@ -6849,6 +6905,14 @@ HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pD GCPROTECT_END(); +#ifdef FEATURE_PAL + if (hmod != nullptr) + { + // Register the system library handle with PAL and get a PAL library handle + hmod = PAL_RegisterLibraryDirect(hmod, wszLibName); + } +#endif // FEATURE_PAL + return (HMODULE)hmod; } #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER) @@ -7250,17 +7314,7 @@ VOID NDirect::NDirectLink(NDirectMethodDesc *pMD) if (!hmod) { - HRESULT theHRESULT = errorTracker.GetHR(); - if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) - { - COMPlusThrow(kBadImageFormatException); - } - else - { - SString hrString; - GetHRMsg(theHRESULT, hrString); - COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, ssLibName.GetUnicode(), hrString); - } + errorTracker.Throw(ssLibName); } WCHAR wszEPName[50]; diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h index 7cf33c3e08..5b87427851 100644 --- a/src/vm/dllimport.h +++ b/src/vm/dllimport.h @@ -78,7 +78,8 @@ public: static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs); static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod); - static HINSTANCE LoadLibraryModule( NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker); + static HMODULE LoadLibraryFromPath(LPCWSTR libraryPath); + static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker); #ifndef FEATURE_CORECLR static VOID CheckUnificationList(NDirectMethodDesc * pMD, DWORD * pDllImportSearchPathFlag, BOOL * pSearchAssemblyDirectory); @@ -133,7 +134,7 @@ private: NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) - static HMODULE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName); + static HMODULE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName); #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER) #if !defined(FEATURE_CORESYSTEM) diff --git a/src/vm/dwbucketmanager.hpp b/src/vm/dwbucketmanager.hpp index 11d56de66b..abcc6f3ed0 100644 --- a/src/vm/dwbucketmanager.hpp +++ b/src/vm/dwbucketmanager.hpp @@ -513,7 +513,7 @@ void BaseBucketParamsManager::GetAppVersion(__out_ecount(maxLength) WCHAR* targe WCHAR appPath[MAX_LONGPATH]; DWORD cchAppPath = NumItems(appPath); - WCHAR verBuf[23]; + WCHAR verBuf[23] = {0}; USHORT major, minor, build, revision; if ((GetCurrentModuleFileName(appPath, &cchAppPath) == S_OK) && SUCCEEDED(DwGetFileVersionInfo(appPath, major, minor, build, revision))) diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index b6bd8eeaf5..e79ab11a95 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -1166,6 +1166,7 @@ FCFuncEnd() FCFuncStart(gAssemblyLoadContextFuncs) QCFuncElement("InitializeAssemblyLoadContext", AssemblyNative::InitializeAssemblyLoadContext) QCFuncElement("LoadFromPath", AssemblyNative::LoadFromPath) + QCFuncElement("InternalLoadUnmanagedDllFromPath", AssemblyNative::InternalLoadUnmanagedDllFromPath) QCFuncElement("OverrideDefaultAssemblyLoadContextForCurrentDomain", AssemblyNative::OverrideDefaultAssemblyLoadContextForCurrentDomain) QCFuncElement("CanUseAppPathAssemblyLoadContextInCurrentDomain", AssemblyNative::CanUseAppPathAssemblyLoadContextInCurrentDomain) QCFuncElement("LoadFromStream", AssemblyNative::LoadFromStream) @@ -1524,6 +1525,12 @@ FCFuncStart(gTextInfoFuncs) FCFuncEnd() #endif // defined(FEATURE_LEGACYSURFACE) && !defined(FEATURE_COREFX_GLOBALIZATION) +#ifdef FEATURE_COREFX_GLOBALIZATION +FCFuncStart(gCompareInfoFuncs) + QCFuncElement("InternalHashSortKey", CoreFxGlobalization::HashSortKey) +FCFuncEnd() +#endif + FCFuncStart(gArrayFuncs) FCFuncElement("get_Rank", ArrayNative::GetRank) FCFuncElement("GetLowerBound", ArrayNative::GetLowerBound) @@ -2183,9 +2190,9 @@ FCClassElement("ChannelServices", "System.Runtime.Remoting.Channels", gChannelSe #ifdef FEATURE_CAS_POLICY FCClassElement("CodeAccessSecurityEngine", "System.Security", gCodeAccessSecurityEngineFuncs) #endif -#if defined(FEATURE_LEGACYSURFACE) && !defined(FEATURE_COREFX_GLOBALIZATION) +#if defined(FEATURE_LEGACYSURFACE) || defined(FEATURE_COREFX_GLOBALIZATION) FCClassElement("CompareInfo", "System.Globalization", gCompareInfoFuncs) -#endif // defined(FEATURE_LEGACYSURFACE) && !defined(FEATURE_COREFX_GLOBALIZATION) +#endif // defined(FEATURE_LEGACYSURFACE) FCClassElement("CompatibilitySwitch", "System.Runtime.Versioning", gCompatibilitySwitchFuncs) #ifdef FEATURE_COMPRESSEDSTACK FCClassElement("CompressedStack", "System.Threading", gCompressedStackFuncs) diff --git a/src/vm/excep.cpp b/src/vm/excep.cpp index 45ac184f9f..4420ea2f3a 100644 --- a/src/vm/excep.cpp +++ b/src/vm/excep.cpp @@ -5868,7 +5868,7 @@ DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionPointers, } const int buf_size = 128; - WCHAR buf[buf_size]; + WCHAR buf[buf_size] = {0}; // See detailed explanation of this flag in threads.cpp. But the basic idea is that we already // reported the exception in the AppDomain where it went unhandled, so we don't need to report @@ -8926,6 +8926,33 @@ LONG ReflectionInvocationExceptionFilter( } #endif // !FEATURE_PAL + // If the application has opted into triggering a failfast when a CorruptedStateException enters the Reflection system, + // then do the needful. + if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_FailFastOnCorruptedStateException) == 1) + { + // Get the thread and the managed exception object - they must exist at this point + Thread *pCurThread = GetThread(); + _ASSERTE(pCurThread != NULL); + + // Get the thread exception state + ThreadExceptionState * pCurTES = pCurThread->GetExceptionState(); + _ASSERTE(pCurTES != NULL); + + // Get the exception tracker for the current exception +#ifdef WIN64EXCEPTIONS + PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker(); +#elif _TARGET_X86_ + PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker(); +#else // !(_WIN64 || _TARGET_X86_) +#error Unsupported platform +#endif // _WIN64 + + if (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting) + { + EEPolicy::HandleFatalError(COR_E_FAILFAST, reinterpret_cast<UINT_PTR>(pExceptionInfo->ExceptionRecord->ExceptionAddress), NULL, pExceptionInfo); + } + } + return ret; } // LONG ReflectionInvocationExceptionFilter() diff --git a/src/vm/interoputil.h b/src/vm/interoputil.h index f2404fa17f..87a70bea5b 100644 --- a/src/vm/interoputil.h +++ b/src/vm/interoputil.h @@ -232,12 +232,12 @@ ULONG SafeAddRefPreemp(IUnknown* pUnk); //-------------------------------------------------------------------------------- // Release helper, enables and disables GC during call-outs -HRESULT SafeVariantChangeType(VARIANT* pVarRes, VARIANT* pVarSrc, +HRESULT SafeVariantChangeType(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc, unsigned short wFlags, VARTYPE vt); //-------------------------------------------------------------------------------- // Release helper, enables and disables GC during call-outs -HRESULT SafeVariantChangeTypeEx(VARIANT* pVarRes, VARIANT* pVarSrc, +HRESULT SafeVariantChangeTypeEx(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc, LCID lcid, unsigned short wFlags, VARTYPE vt); //-------------------------------------------------------------------------------- diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h index 7ee310f825..65e3f54c5e 100644 --- a/src/vm/jitinterface.h +++ b/src/vm/jitinterface.h @@ -1084,7 +1084,7 @@ public: ); void freeStringConfigValue( - wchar_t *value + __in_z wchar_t *value ); CEEInfo(MethodDesc * fd = NULL, bool fVerifyOnly = false) : diff --git a/src/vm/mdaassistants.cpp b/src/vm/mdaassistants.cpp index 38c38d89b0..cac15fdd81 100644 --- a/src/vm/mdaassistants.cpp +++ b/src/vm/mdaassistants.cpp @@ -996,7 +996,11 @@ void MdaPInvokeLog::LogPInvoke(NDirectMethodDesc* pMD, HINSTANCE hMod) StackSString sszEntryPoint; sszEntryPoint.SetUTF8(pMD->GetEntrypointName()); - WCHAR szDllFullName[_MAX_PATH], szDrive[_MAX_PATH], szPath[_MAX_PATH], szFileName[_MAX_PATH], szExt[_MAX_PATH]; + WCHAR szDllFullName[_MAX_PATH] = {0}; + WCHAR szDrive[_MAX_PATH] = {0}; + WCHAR szPath[_MAX_PATH] = {0}; + WCHAR szFileName[_MAX_PATH] = {0}; + WCHAR szExt[_MAX_PATH] = {0}; WszGetModuleFileName(hMod, szDllFullName, _MAX_PATH); SplitPath(szDllFullName, szDrive, _MAX_PATH, szPath, _MAX_PATH, szFileName, _MAX_PATH, szExt, _MAX_PATH); diff --git a/src/vm/profilermetadataemitvalidator.h b/src/vm/profilermetadataemitvalidator.h index 3c0306c24e..469edf6e02 100644 --- a/src/vm/profilermetadataemitvalidator.h +++ b/src/vm/profilermetadataemitvalidator.h @@ -460,6 +460,7 @@ public: mdTypeDef *ptd); // [OUT] Put the TypeDef token here. virtual HRESULT STDMETHODCALLTYPE GetScopeProps( // S_OK or error. + __out_ecount(cchName) LPWSTR szName, // [OUT] Put the name here. ULONG cchName, // [IN] Size of name buffer in wide chars. ULONG *pchName, // [OUT] Put size of name (wide chars) here. @@ -470,6 +471,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetTypeDefProps( // S_OK or error. mdTypeDef td, // [IN] TypeDef token for inquiry. + __out_ecount(cchTypeDef) LPWSTR szTypeDef, // [OUT] Put name here. ULONG cchTypeDef, // [IN] size of name buffer in wide chars. ULONG *pchTypeDef, // [OUT] put size of name (wide chars) here. @@ -484,6 +486,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetTypeRefProps( // S_OK or error. mdTypeRef tr, // [IN] TypeRef token. mdToken *ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef. + __out_ecount(cchName) LPWSTR szName, // [OUT] Name of the TypeRef. ULONG cchName, // [IN] Size of buffer. ULONG *pchName); // [OUT] Size of Name. @@ -597,6 +600,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetMethodProps( mdMethodDef mb, // The method for which to get props. mdTypeDef *pClass, // Put method's class here. + __out_ecount(cchMethod) LPWSTR szMethod, // Put method's name here. ULONG cchMethod, // Size of szMethod buffer in wide chars. ULONG *pchMethod, // Put actual size here @@ -609,6 +613,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetMemberRefProps( // S_OK or error. mdMemberRef mr, // [IN] given memberref mdToken *ptk, // [OUT] Put classref or classdef here. + __out_ecount(cchMember) LPWSTR szMember, // [OUT] buffer to fill for member's name ULONG cchMember, // [IN] the count of char of szMember ULONG *pchMember, // [OUT] actual count of char in member name @@ -715,6 +720,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetUserString( // S_OK or error. mdString stk, // [IN] String token. + __out_ecount(cchString) LPWSTR szString, // [OUT] Copy of string. ULONG cchString, // [IN] Max chars of room in szString. ULONG *pchString); // [OUT] How many chars in actual string. @@ -722,6 +728,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetPinvokeMap( // S_OK or error. mdToken tk, // [IN] FieldDef or MethodDef. DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + __out_ecount(cchImportName) LPWSTR szImportName, // [OUT] Import name. ULONG cchImportName, // [IN] Size of the name buffer. ULONG *pchImportName, // [OUT] Actual number of characters stored. @@ -773,6 +780,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetMemberProps( mdToken mb, // The member for which to get props. mdTypeDef *pClass, // Put member's class here. + __out_ecount(cchMember) LPWSTR szMember, // Put member's name here. ULONG cchMember, // Size of szMember buffer in wide chars. ULONG *pchMember, // Put actual size here @@ -788,6 +796,7 @@ public: virtual HRESULT STDMETHODCALLTYPE GetFieldProps( mdFieldDef mb, // The field for which to get props. mdTypeDef *pClass, // Put field's class here. + __out_ecount(cchField) LPWSTR szField, // Put field's name here. ULONG cchField, // Size of szField buffer in wide chars. ULONG *pchField, // Put actual size here @@ -820,6 +829,7 @@ public: mdParamDef tk, // [IN]The Parameter. mdMethodDef *pmd, // [OUT] Parent Method token. ULONG *pulSequence, // [OUT] Parameter sequence. + __out_ecount(cchName) LPWSTR szName, // [OUT] Put name here. ULONG cchName, // [OUT] Size of name buffer. ULONG *pchName, // [OUT] Put actual size of name here. @@ -864,6 +874,7 @@ public: DWORD *pdwParamFlags, // [OUT] Flags, for future use (e.g. variance) mdToken *ptOwner, // [OUT] Owner (TypeDef or MethodDef) DWORD *reserved, // [OUT] For future use (e.g. non-type parameters) + __out_ecount(cchName) LPWSTR wzname, // [OUT] Put name here ULONG cchName, // [IN] Size of buffer ULONG *pchName); // [OUT] Put size of name (wide chars) here. @@ -891,6 +902,7 @@ public: DWORD* pdwMAchine); // [OUT] Machine as defined in NT header virtual HRESULT STDMETHODCALLTYPE GetVersionString( // S_OK or error. + __out_ecount(ccBufSize) LPWSTR pwzBuf, // [OUT] Put version string here. DWORD ccBufSize, // [IN] size of the buffer, in wide chars DWORD *pccBufSize); // [OUT] Size of the version string, wide chars, including terminating nul. @@ -909,7 +921,8 @@ public: const void **ppbPublicKey, // [OUT] Pointer to the public key. ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. ULONG *pulHashAlgId, // [OUT] Hash Algorithm. - LPWSTR szName, // [OUT] Buffer to fill with assembly's simply name. + __out_ecount(cchName) + LPWSTR szName, // [OUT] Buffer to fill with assembly's simply name. ULONG cchName, // [IN] Size of buffer in wide chars. ULONG *pchName, // [OUT] Actual # of wide chars in name. ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. @@ -919,7 +932,8 @@ public: mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. - LPWSTR szName, // [OUT] Buffer to fill with name. + __out_ecount(cchName) + LPWSTR szName, // [OUT] Buffer to fill with name. ULONG cchName, // [IN] Size of buffer in wide chars. ULONG *pchName, // [OUT] Actual # of wide chars in name. ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. @@ -929,7 +943,8 @@ public: virtual HRESULT STDMETHODCALLTYPE GetFileProps( // S_OK or error. mdFile mdf, // [IN] The File for which to get the properties. - LPWSTR szName, // [OUT] Buffer to fill with name. + __out_ecount(cchName) + LPWSTR szName, // [OUT] Buffer to fill with name. ULONG cchName, // [IN] Size of buffer in wide chars. ULONG *pchName, // [OUT] Actual # of wide chars in name. const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. @@ -938,7 +953,8 @@ public: virtual HRESULT STDMETHODCALLTYPE GetExportedTypeProps( // S_OK or error. mdExportedType mdct, // [IN] The ExportedType for which to get the properties. - LPWSTR szName, // [OUT] Buffer to fill with name. + __out_ecount(cchName) + LPWSTR szName, // [OUT] Buffer to fill with name. ULONG cchName, // [IN] Size of buffer in wide chars. ULONG *pchName, // [OUT] Actual # of wide chars in name. mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef or mdExportedType. @@ -947,7 +963,8 @@ public: virtual HRESULT STDMETHODCALLTYPE GetManifestResourceProps( // S_OK or error. mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. - LPWSTR szName, // [OUT] Buffer to fill with name. + __out_ecount(cchName) + LPWSTR szName, // [OUT] Buffer to fill with name. ULONG cchName, // [IN] Size of buffer in wide chars. ULONG *pchName, // [OUT] Actual # of wide chars in name. mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ManifestResource. diff --git a/src/vm/securitymeta.cpp b/src/vm/securitymeta.cpp index b46ac44b73..9ab6dbe0cb 100644 --- a/src/vm/securitymeta.cpp +++ b/src/vm/securitymeta.cpp @@ -1834,7 +1834,7 @@ TokenSecurityDescriptorFlags ParseAptcaAttribute(const BYTE *pbAptcaBlob, DWORD aptcaFlags |= TokenSecurityDescriptorFlags_APTCA; // Look for the PartialTrustVisibilityLevel named argument - CaNamedArg namedArgs[1]; + CaNamedArg namedArgs[1] = {{0}}; namedArgs[0].InitI4FieldEnum(g_PartialTrustVisibilityLevel, g_SecurityPartialTrustVisibilityLevel); if (SUCCEEDED(ParseKnownCaNamedArgs(cap, namedArgs, _countof(namedArgs)))) diff --git a/src/vm/stubhelpers.h b/src/vm/stubhelpers.h index ca3f604c7c..c538bd0701 100644 --- a/src/vm/stubhelpers.h +++ b/src/vm/stubhelpers.h @@ -73,7 +73,7 @@ public: static FCDECL1(Object *, InterfaceMarshaler__ConvertToManagedWithoutUnboxing, IUnknown *pNative); static FCDECL1(StringObject*, UriMarshaler__GetRawUriFromNative, ABI::Windows::Foundation::IUriRuntimeClass* pIUriRC); - static FCDECL2(IUnknown*, UriMarshaler__CreateNativeUriInstance, CLR_CHAR* pRawUriObj, UINT strLen); + static FCDECL2(IUnknown*, UriMarshaler__CreateNativeUriInstance, __in_ecount(strLen) CLR_CHAR* pRawUriObj, UINT strLen); static ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgs* QCALLTYPE EventArgsMarshaler__CreateNativeNCCEventArgsInstance diff --git a/src/vm/tlbexport.cpp b/src/vm/tlbexport.cpp index 17861387bc..744671099a 100644 --- a/src/vm/tlbexport.cpp +++ b/src/vm/tlbexport.cpp @@ -277,10 +277,10 @@ void ExportTypeLibFromLoadedAssembly( TypeLibExporter exporter; // Exporter object. LPCWSTR szModule=0; // Module filename. - WCHAR rcDrive[_MAX_DRIVE]; - WCHAR rcDir[_MAX_DIR]; - WCHAR rcFile[_MAX_FNAME]; - WCHAR rcTlb[_MAX_PATH+5]; // Buffer for the tlb filename. + WCHAR rcDrive[_MAX_DRIVE] = {0}; + WCHAR rcDir[_MAX_DIR] = {0}; + WCHAR rcFile[_MAX_FNAME] = {0}; + WCHAR rcTlb[_MAX_PATH+5] = {0}; // Buffer for the tlb filename. int bDynamic=0; // If true, dynamic module. Module *pModule; // The Assembly's SecurityModule. diff --git a/src/vm/util.cpp b/src/vm/util.cpp index 9c135407da..f823aa9c8d 100644 --- a/src/vm/util.cpp +++ b/src/vm/util.cpp @@ -31,7 +31,7 @@ // Called again with a nonnull *pdstout to fill in the actual buffer. // // Returns the # of arguments. -static UINT ParseCommandLine(LPCWSTR psrc, __out LPWSTR *pdstout) +static UINT ParseCommandLine(LPCWSTR psrc, __inout LPWSTR *pdstout) { CONTRACTL { diff --git a/src/vm/wrappers.h b/src/vm/wrappers.h index 1a0836b707..d495a64827 100644 --- a/src/vm/wrappers.h +++ b/src/vm/wrappers.h @@ -59,7 +59,7 @@ private: //-------------------------------------------------------------------------------- // safe variant helper -void SafeVariantClear(VARIANT* pVar); +void SafeVariantClear(_Inout_ VARIANT* pVar); class VariantHolder { diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h index c6c8ee3b57..1d16c9b760 100644 --- a/src/zap/zapinfo.h +++ b/src/zap/zapinfo.h @@ -777,7 +777,7 @@ public: wchar_t *getStringConfigValue(const wchar_t *name); - void freeStringConfigValue(wchar_t *value); + void freeStringConfigValue(__in_z wchar_t *value); }; #endif // __ZAPINFO_H__ diff --git a/tests/buildtest.cmd b/tests/buildtest.cmd index a73a67fbff..4d97c798e3 100644 --- a/tests/buildtest.cmd +++ b/tests/buildtest.cmd @@ -166,6 +166,23 @@ set _buildprefix= set _buildpostfix= set _buildappend= call :build %1 + +set CORE_ROOT=%__TestBinDir%\Tests\Core_Root +echo. +echo Creating test overlay... + +:: Log build command line +set _buildprefix=echo +set _buildpostfix=^> "%__TestManagedBuildLog%" +set _buildappend=^> +call :CreateTestOverlay %1 + +:: Build +set _buildprefix= +set _buildpostfix= +set _buildappend= +call :CreateTestOverlay %1 + exit /b %ERRORLEVEL% :build @@ -174,6 +191,12 @@ exit /b %ERRORLEVEL% IF ERRORLEVEL 1 echo Test build failed. Refer to !__TestManagedBuildLog! for details && exit /b 1 exit /b 0 +:CreateTestOverlay + +%_buildprefix% %_msbuildexe% "%__ProjectFilesDir%\runtest.proj" /t:CreateTestOverlay /nologo /maxcpucount /verbosity:minimal /nodeReuse:false /fileloggerparameters:Verbosity=normal;LogFile="%__TestManagedBuildLog%";Append %* %_buildpostfix% +IF ERRORLEVEL 1 echo Failed to create the test overlay. Refer to !__TestManagedBuildLog! for details && exit /b 1 +exit /b 0 + :Usage echo. echo Usage: diff --git a/tests/runtest.cmd b/tests/runtest.cmd index 1c324333c8..f08af94110 100644 --- a/tests/runtest.cmd +++ b/tests/runtest.cmd @@ -27,7 +27,7 @@ if /i "%1" == "vs2015" (set __VSVersion=%1&shift&goto Arg_Loop) if /i "%1" == "/?" (goto Usage) -set Core_Root=%1 +set CORE_ROOT=%1 shift :ArgsDone :: Check prerequisites @@ -70,16 +70,16 @@ if not defined __LogsDir set __LogsDir=%__ProjectFilesDir%..\bin\Logs :: Default global test environment variables if not defined XunitTestBinBase set XunitTestBinBase=%__TestWorkingDir%\ if not defined XunitTestReportDirBase set XunitTestReportDirBase=%XunitTestBinBase%\Reports\ -if defined Core_Root goto :CheckTestEnv +if defined CORE_ROOT goto :CheckTestEnv set noCore_RootSet=true -set Core_Root=%__BinDir% +set CORE_ROOT=%__BinDir% :CheckTestEnv ::Check if the test Binaries are built if not exist %XunitTestBinBase% echo Error: Ensure the Test Binaries are built and are present at %XunitTestBinBase%, Run - buildtest.cmd %__BuildArch% %__BuildType% to build the tests first. && exit /b 1 -if "%Core_Root%" == "" echo Error: Ensure you have done a successful build of the Product and Run - runtest BuildArch BuildType {path to product binaries}. && exit /b 1 -if not exist %Core_Root%\coreclr.dll echo Error: Ensure you have done a successful build of the Product and %Core_Root% contains runtime binaries. && exit /b 1 +if "%CORE_ROOT%" == "" echo Error: Ensure you have done a successful build of the Product and Run - runtest BuildArch BuildType {path to product binaries}. && exit /b 1 +if not exist %CORE_ROOT%\coreclr.dll echo Error: Ensure you have done a successful build of the Product and %CORE_ROOT% contains runtime binaries. && exit /b 1 if not "%__Exclude%"=="" (if not exist %__Exclude% echo Error: Exclusion .targets file not found && exit /b 1) if not "%__TestEnv%"=="" (if not exist %__TestEnv% echo Error: Test Environment script not found && exit /b 1) if not exist %__LogsDir% md %__LogsDir% @@ -90,7 +90,7 @@ set __TestRunBuildLog=%__LogsDir%\TestRunResults_%__BuildOS%__%__BuildArch%__%__ set __TestRunHtmlLog=%__LogsDir%\TestRun_%__BuildOS%__%__BuildArch%__%__BuildType%.html set __TestRunXmlLog=%__LogsDir%\TestRun_%__BuildOS%__%__BuildArch%__%__BuildType%.xml -echo Core_Root that will be used is: %Core_Root% +echo CORE_ROOT that will be used is: %CORE_ROOT% echo Starting The Test Run ... if "%__SkipWrapperGeneration%"=="true" goto :preptests @@ -121,12 +121,12 @@ set _buildprefix= set _buildpostfix= set _buildappend= if not "%noCore_RootSet%"=="true" goto :runtests -set Core_Root=%XunitTestBinBase%\Tests\Core_Root -echo Using Default Core_Root as %Core_Root% -echo Copying Built binaries from %__BinDir% to %Core_Root% -if exist %Core_Root% rd /s /q %Core_Root% -md %Core_Root% -xcopy /s %__BinDir% %Core_Root% +set CORE_ROOT=%XunitTestBinBase%\Tests\Core_Root +echo Using Default CORE_ROOT as %CORE_ROOT% +echo Copying Built binaries from %__BinDir% to %CORE_ROOT% +if exist %CORE_ROOT% rd /s /q %CORE_ROOT% +md %CORE_ROOT% +xcopy /s %__BinDir% %CORE_ROOT% call :runtests if ERRORLEVEL 1 ( echo Test Run failed. Refer to the following" diff --git a/tests/runtest.proj b/tests/runtest.proj index 97ab648f73..96f1c05d56 100644 --- a/tests/runtest.proj +++ b/tests/runtest.proj @@ -306,6 +306,11 @@ public class $([System.String]::Copy('%(AllCMDs.FullPath)').Replace("$(_CMDDIR)" <Import Project="tests.targets" /> <Import Project="publishdependency.targets" /> + <Target Name="CreateTestOverlay"> + <MSBuild Projects="$(MSBuildProjectFile)" + Targets="CopyDependecyToCoreRoot"/> + </Target> + <Target Name="Build"> <!-- Default for building --> <MSBuild Projects="$(MSBuildProjectFile)" @@ -315,7 +320,8 @@ public class $([System.String]::Copy('%(AllCMDs.FullPath)').Replace("$(_CMDDIR)" <!-- Execution --> - <MSBuild Projects="$(MSBuildProjectFile)" Targets="CopyDependecyToCoreRoot" + <MSBuild Projects="$(MSBuildProjectFile)" + Targets="CreateTestOverlay" Condition=" '$(NoRun)'!='true' "/> <MSBuild Projects="$(MSBuildProjectFile)" Targets="RunTests" diff --git a/tests/runtest.sh b/tests/runtest.sh index 00847c6466..6333873266 100644..100755 --- a/tests/runtest.sh +++ b/tests/runtest.sh @@ -1,13 +1,44 @@ #!/usr/bin/env bash function print_usage { - echo "" - echo "CoreCLR test runner script." - echo "Arguments:" - echo " -v, --verbose : Show output from each test." - echo " --testDirFile=<path> : Run tests only in the directories specified by the file at <path>." - echo " The file should specify one directory per line." - echo "" + echo '' + echo 'CoreCLR test runner script.' + echo '' + echo 'Typical command line:' + echo '' + echo 'coreclr/tests/runtest.sh' + echo ' --testRootDir="temp/Windows.x64.Debug"' + echo ' --testNativeBinDir="coreclr/bin/obj/Linux.x64.Debug/tests"' + echo ' --coreClrBinDir="coreclr/bin/Product/Linux.x64.Debug"' + echo ' --mscorlibDir="windows/coreclr/bin/Product/Linux.x64.Debug"' + echo ' --coreFxBinDir="corefx/bin/Linux.AnyCPU.Debug"' + echo ' --coreFxNativeBinDir="corefx/bin/Linux.x64.Debug"' + echo '' + echo 'Required arguments:' + echo ' --testRootDir=<path> : Root directory of the test build (e.g. coreclr/bin/tests/Windows_NT.x64.Debug).' + echo ' --testNativeBinDir=<path> : Directory of the native CoreCLR test build (e.g. coreclr/bin/obj/Linux.x64.Debug/tests).' + echo ' (Also required: Either --coreOverlayDir, or all of the switches --coreOverlayDir overrides)' + echo '' + echo 'Optional arguments:' + echo ' --coreOverlayDir=<path> : Directory containing core binaries and test dependencies. If not specified, the' + echo ' default is testRootDir/Tests/coreoverlay. This switch overrides --coreClrBinDir,' + echo ' --mscorlibDir, --coreFxBinDir, and --coreFxNativeBinDir.' + echo ' --coreClrBinDir=<path> : Directory of the CoreCLR build (e.g. coreclr/bin/Product/Linux.x64.Debug).' + echo ' --mscorlibDir=<path> : Directory containing the built mscorlib.dll. If not specified, it is expected to be' + echo ' in the directory specified by --coreClrBinDir.' + echo ' --coreFxBinDir=<path> : Directory of the CoreFX build (e.g. corefx/bin/Linux.AnyCPU.Debug).' + echo ' --coreFxNativeBinDir=<path> : Directory of the CoreFX native build (e.g. corefx/bin/Linux.x64.Debug).' + echo ' --testDir=<path> : Run tests only in the specified directory. The path is relative to the directory' + echo ' specified by --testRootDir. Multiple of this switch may be specified.' + echo ' --testDirFile=<path> : Run tests only in the directories specified by the file at <path>. Paths are listed' + echo ' one line, relative to the directory specified by --testRootDir.' + echo ' --runFailingTestsOnly : Run only the tests that are disabled on this platform due to unexpected failures.' + echo ' Failing tests are listed in coreclr/tests/failingTestsOutsideWindows.txt, one per' + echo ' line, as paths to .sh files relative to the directory specified by --testRootDir.' + echo ' --sequential : Run tests sequentially (default is to run in parallel).' + echo ' -v, --verbose : Show output from each test.' + echo ' -h|--help : Show usage information.' + echo '' } function print_results { @@ -22,120 +53,590 @@ function print_results { echo "=======================" } +# Initialize counters for bookkeeping. +countTotalTests=0 +countPassedTests=0 +countFailedTests=0 +countSkippedTests=0 + +# Variables for xUnit-style XML output. XML format: https://xunit.github.io/docs/format-xml-v2.html +xunitOutputPath= +xunitTestOutputPath= + +function xunit_output_begin { + xunitOutputPath=$testRootDir/coreclrtests.xml + xunitTestOutputPath=${xunitOutputPath}.test + if [ -e "$xunitOutputPath" ]; then + rm -f -r "$xunitOutputPath" + fi + if [ -e "$xunitTestOutputPath" ]; then + rm -f -r "$xunitTestOutputPath" + fi +} + +function xunit_output_add_test { + # <assemblies> + # <assembly> + # <collection> + # <test .../> <!-- Write this element here --> + + local scriptFilePath=$1 + local outputFilePath=$2 + local testResult=$3 # Pass, Fail, or Skip + local testScriptExitCode=$4 + + local testPath=${scriptFilePath:0:(-3)} # Remove trailing ".sh" + local testDir=$(dirname "$testPath") + local testName=$(basename "$testPath") + + # Replace '/' with '.' + testPath=$(echo "$testPath" | tr / .) + testDir=$(echo "$testDir" | tr / .) + + local line + + line=" " + line="${line}<test" + line="${line} name=\"${testPath}\"" + line="${line} type=\"${testDir}\"" + line="${line} method=\"${testName}\"" + line="${line} result=\"${testResult}\"" + + if [ "$testResult" == "Pass" ]; then + line="${line}/>" + echo "$line" >>"$xunitTestOutputPath" + return + fi + + line="${line}>" + echo "$line" >>"$xunitTestOutputPath" + + line=" " + if [ "$testResult" == "Skip" ]; then + line="${line}<reason><![CDATA[$(cat "$outputFilePath")]]></reason>" + echo "$line" >>"$xunitTestOutputPath" + else + line="${line}<failure exception-type=\"Exit code: ${testScriptExitCode}\">" + echo "$line" >>"$xunitTestOutputPath" + + line=" " + line="${line}<message>" + echo "$line" >>"$xunitTestOutputPath" + line=" " + line="${line}<![CDATA[" + echo "$line" >>"$xunitTestOutputPath" + cat "$outputFilePath" >>"$xunitTestOutputPath" + line=" " + line="${line}]]>" + echo "$line" >>"$xunitTestOutputPath" + line=" " + line="${line}</message>" + echo "$line" >>"$xunitTestOutputPath" + + line=" " + line="${line}</failure>" + echo "$line" >>"$xunitTestOutputPath" + fi + + line=" " + line="${line}</test>" + echo "$line" >>"$xunitTestOutputPath" +} + +function xunit_output_end { + local errorSource=$1 + local errorMessage=$2 + + local errorCount + if [ -z "$errorSource" ]; then + ((errorCount = 0)) + else + ((errorCount = 1)) + fi + + echo '<?xml version="1.0" encoding="utf-8"?>' >>"$xunitOutputPath" + echo '<assemblies>' >>"$xunitOutputPath" + + local line + + # <assembly ...> + line=" " + line="${line}<assembly" + line="${line} name=\"CoreClrTestAssembly\"" + line="${line} total=\"${countTotalTests}\"" + line="${line} passed=\"${countPassedTests}\"" + line="${line} failed=\"${countFailedTests}\"" + line="${line} skipped=\"${countSkippedTests}\"" + line="${line} errors=\"${errorCount}\"" + line="${line}>" + echo "$line" >>"$xunitOutputPath" + + # <collection ...> + line=" " + line="${line}<collection" + line="${line} name=\"CoreClrTestCollection\"" + line="${line} total=\"${countTotalTests}\"" + line="${line} passed=\"${countPassedTests}\"" + line="${line} failed=\"${countFailedTests}\"" + line="${line} skipped=\"${countSkippedTests}\"" + line="${line}>" + echo "$line" >>"$xunitOutputPath" + + # <test .../> <test .../> ... + if [ -f "$xunitTestOutputPath" ]; then + cat "$xunitTestOutputPath" >>"$xunitOutputPath" + rm -f "$xunitTestOutputPath" + fi + + # </collection> + line=" " + line="${line}</collection>" + echo "$line" >>"$xunitOutputPath" + + if [ -n "$errorSource" ]; then + # <errors> + line=" " + line="${line}<errors>" + echo "$line" >>"$xunitOutputPath" + + # <error ...> + line=" " + line="${line}<error" + line="${line} type=\"TestHarnessError\"" + line="${line} name=\"${errorSource}\"" + line="${line}>" + echo "$line" >>"$xunitOutputPath" + + # <failure .../> + line=" " + line="${line}<failure>${errorMessage}</failure>" + echo "$line" >>"$xunitOutputPath" + + # </error> + line=" " + line="${line}</error>" + echo "$line" >>"$xunitOutputPath" + + # </errors> + line=" " + line="${line}</errors>" + echo "$line" >>"$xunitOutputPath" + fi + + # </assembly> + line=" " + line="${line}</assembly>" + echo "$line" >>"$xunitOutputPath" + + # </assemblies> + echo '</assemblies>' >>"$xunitOutputPath" +} + +function exit_with_error { + local errorSource=$1 + local errorMessage=$2 + local printUsage=$3 + + if [ -z "$printUsage" ]; then + ((printUsage = 0)) + fi + + echo "$errorMessage" + xunit_output_end "$errorSource" "$errorMessage" + if ((printUsage != 0)); then + print_usage + fi + exit 1 +} + # Handle Ctrl-C. We will stop execution and print the results that # we gathered so far. function handle_ctrl_c { + local errorSource='handle_ctrl_c' + echo "" echo "*** Stopping... ***" print_results - exit 0 + exit_with_error "$errorSource" "Test run aborted by Ctrl+C." } # Register the Ctrl-C handler trap handle_ctrl_c INT +function create_core_overlay { + local errorSource='create_core_overlay' + local printUsage=1 + + if [ -n "$coreOverlayDir" ]; then + export CORE_ROOT="$coreOverlayDir" + return + fi + + # Check inputs to make sure we have enough information to create the core layout. $testRootDir/Tests/Core_Root should + # already exist and contain test dependencies that are not built. + local testDependenciesDir=$testRootDir/Tests/Core_Root + if [ ! -d "$testDependenciesDir" ]; then + exit_with_error "$errorSource" "Did not find the test dependencies directory: $testDependenciesDir" + fi + if [ -z "$coreClrBinDir" ]; then + exit_with_error "$errorSource" "One of --coreOverlayDir or --coreClrBinDir must be specified." "$printUsage" + fi + if [ ! -d "$coreClrBinDir" ]; then + exit_with_error "$errorSource" "Directory specified by --coreClrBinDir does not exist: $coreClrBinDir" + fi + if [ -z "$mscorlibDir" ]; then + mscorlibDir=$coreClrBinDir + fi + if [ ! -f "$mscorlibDir/mscorlib.dll" ]; then + exit_with_error "$errorSource" "mscorlib.dll was not found in: $mscorlibDir" + fi + if [ -z "$coreFxBinDir" ]; then + exit_with_error "$errorSource" "One of --coreOverlayDir or --coreFxBinDir must be specified." "$printUsage" + fi + if [ ! -d "$coreFxBinDir" ]; then + exit_with_error "$errorSource" "Directory specified by --coreFxBinDir does not exist: $coreFxBinDir" + fi + if [ -z "$coreFxNativeBinDir" ]; then + exit_with_error "$errorSource" "One of --coreOverlayDir or --coreFxBinDir must be specified." "$printUsage" + fi + if [ ! -d "$coreFxNativeBinDir/Native" ]; then + exit_with_error "$errorSource" "Directory specified by --coreFxBinDir does not exist: $coreFxNativeBinDir/Native" + fi + + # Create the overlay + coreOverlayDir=$testRootDir/Tests/coreoverlay + export CORE_ROOT="$coreOverlayDir" + if [ -e "$coreOverlayDir" ]; then + rm -f -r "$coreOverlayDir" + fi + mkdir "$coreOverlayDir" + find "$coreFxBinDir" -iname '*.dll' \! -iwholename '*test*' \! -iwholename '*/ToolRuntime/*' -exec cp -f -u '{}' "$coreOverlayDir/" \; + cp -f "$coreFxNativeBinDir/Native/"*.so "$coreOverlayDir/" 2>/dev/null + cp -f "$coreClrBinDir/"* "$coreOverlayDir/" 2>/dev/null + cp -f "$mscorlibDir/mscorlib.dll" "$coreOverlayDir/" + cp -n "$testDependenciesDir"/* "$coreOverlayDir/" 2>/dev/null + if [ -f "$coreOverlayDir/mscorlib.ni.dll" ]; then + rm -f "$coreOverlayDir/mscorlib.ni.dll" + fi +} + +function copy_test_native_bin_to_test_root { + local errorSource='copy_test_native_bin_to_test_root' + + if [ -z "$testNativeBinDir" ]; then + exit_with_error "$errorSource" "--testNativeBinDir is required." + fi + testNativeBinDir=$testNativeBinDir/src + if [ ! -d "$testNativeBinDir" ]; then + exit_with_error "$errorSource" "Directory specified by --testNativeBinDir does not exist: $testNativeBinDir" + fi + + # Copy native test components from the native test build into the respective test directory in the test root directory + find "$testNativeBinDir" -type f -iname '*.so' | + while IFS='' read -r filePath || [ -n "$filePath" ]; do + local dirPath=$(dirname "$filePath") + local destinationDirPath=${testRootDir}${dirPath:${#testNativeBinDir}} + if [ ! -d "$destinationDirPath" ]; then + exit_with_error "$errorSource" "Cannot copy native test bin '$filePath' to '$destinationDirPath/', as the destination directory does not exist." + fi + cp -f "$filePath" "$destinationDirPath/" + done +} + +# Variables for unsupported and failing tests +declare -a unsupportedTests +declare -a failingTests +((runFailingTestsOnly = 0)) + +function load_unsupported_tests { + # Load the list of tests that fail and on this platform. These tests are disabled (skipped), pending investigation. + # 'readarray' is not used here, as it includes the trailing linefeed in lines placed in the array. + while IFS='' read -r line || [ -n "$line" ]; do + unsupportedTests[${#unsupportedTests[@]}]=$line + done <"$(dirname "$0")/testsUnsupportedOutsideWindows.txt" +} + +function load_failing_tests { + # Load the list of tests that fail and on this platform. These tests are disabled (skipped), pending investigation. + # 'readarray' is not used here, as it includes the trailing linefeed in lines placed in the array. + while IFS='' read -r line || [ -n "$line" ]; do + failingTests[${#failingTests[@]}]=$line + done <"$(dirname "$0")/testsFailingOutsideWindows.txt" +} + +function is_unsupported_test { + for unsupportedTest in "${unsupportedTests[@]}"; do + if [ "$1" == "$unsupportedTest" ]; then + return 0 + fi + done + return 1 +} + +function is_failing_test { + for failingTest in "${failingTests[@]}"; do + if [ "$1" == "$failingTest" ]; then + return 0 + fi + done + return 1 +} + +function skip_unsupported_test { + # This function runs in a background process. It should not echo anything, and should not use global variables. This + # function is analogous to run_test, and causes the test to be skipped with the message below. + + local scriptFilePath=$1 + local outputFilePath=$2 + + echo "Not supported on this platform." >"$outputFilePath" + return 2 # skip the test +} + +function skip_failing_test { + # This function runs in a background process. It should not echo anything, and should not use global variables. This + # function is analogous to run_test, and causes the test to be skipped with the message below. + + local scriptFilePath=$1 + local outputFilePath=$2 + + echo "Temporarily disabled on this platform due to unexpected failures." >"$outputFilePath" + return 2 # skip the test +} + +function run_test { + # This function runs in a background process. It should not echo anything, and should not use global variables. + + local scriptFilePath=$1 + local outputFilePath=$2 + + # Switch to directory where the script is + cd "$(dirname "$scriptFilePath")" + + local scriptFileName=$(basename "$scriptFilePath") + local outputFileName=$(basename "$outputFilePath") + + # Convert DOS line endings to Unix if needed + sed -i 's/\r$//' "$scriptFileName" + + "./$scriptFileName" >"$outputFileName" 2>&1 + return $? +} + +# Variables for running tests in the background +((maxProcesses = $(getconf _NPROCESSORS_ONLN) * 3 / 2)) # long tests delay process creation, use a few more processors +((nextProcessIndex = 0)) +((processCount = 0)) +declare -a scriptFilePaths +declare -a outputFilePaths +declare -a processIds + +function finish_test { + wait ${processIds[$nextProcessIndex]} + local testScriptExitCode=$? + ((--processCount)) + + local scriptFilePath=${scriptFilePaths[$nextProcessIndex]} + local outputFilePath=${outputFilePaths[$nextProcessIndex]} + local scriptFileName=$(basename "$scriptFilePath") + + local xunitTestResult + case $testScriptExitCode in + 0) + let countPassedTests++ + xunitTestResult='Pass' + if ((verbose == 1 || runFailingTestsOnly == 1)); then + echo "PASSED - $scriptFilePath" + else + echo " - $scriptFilePath" + fi + ;; + 2) + let countSkippedTests++ + xunitTestResult='Skip' + echo "SKIPPED - $scriptFilePath" + ;; + *) + let countFailedTests++ + xunitTestResult='Fail' + echo "FAILED - $scriptFilePath" + ;; + esac + let countTotalTests++ + + if ((verbose == 1 || testScriptExitCode != 0)); then + while IFS='' read -r line || [ -n "$line" ]; do + echo " $line" + done <"$outputFilePath" + fi + + xunit_output_add_test "$scriptFilePath" "$outputFilePath" "$xunitTestResult" "$testScriptExitCode" +} + +function finish_remaining_tests { + # Finish the remaining tests in the order in which they were started + if ((nextProcessIndex >= processCount)); then + ((nextProcessIndex = 0)) + fi + while ((processCount > 0)); do + finish_test + ((nextProcessIndex = (nextProcessIndex + 1) % maxProcesses)) + done + ((nextProcessIndex = 0)) +} + +function start_test { + local scriptFilePath=$1 + + if ((runFailingTestsOnly == 1)) && ! is_failing_test "$scriptFilePath"; then + return + fi + + if ((nextProcessIndex < processCount)); then + finish_test + fi + + scriptFilePaths[$nextProcessIndex]=$scriptFilePath + local scriptFileName=$(basename "$scriptFilePath") + local outputFilePath=$(dirname "$scriptFilePath")/${scriptFileName}.out + outputFilePaths[$nextProcessIndex]=$outputFilePath + + test "$verbose" == 1 && echo "Starting $scriptFilePath" + if is_unsupported_test "$scriptFilePath"; then + skip_unsupported_test "$scriptFilePath" "$outputFilePath" & + elif ((runFailingTestsOnly == 0)) && is_failing_test "$scriptFilePath"; then + skip_failing_test "$scriptFilePath" "$outputFilePath" & + else + run_test "$scriptFilePath" "$outputFilePath" & + fi + processIds[$nextProcessIndex]=$! + + ((nextProcessIndex = (nextProcessIndex + 1) % maxProcesses)) + ((++processCount)) +} + # Get a list of directories in which to scan for tests by reading the # specified file line by line. function set_test_directories { - listFileName=$1 + local errorSource='set_test_directories' + + local listFileName=$1 if [ ! -f "$listFileName" ] then - echo "Test directories file not found at $listFileName" - echo "Exiting..." - exit 1 + exit_with_error "$errorSource" "Test directories file not found at $listFileName" fi readarray testDirectories < "$listFileName" } function run_tests_in_directory { - rootDir=$1 + local testDir=$1 # Recursively search through directories for .sh files to run. - for file in $(find "$rootDir" -name '*.sh' -printf '%P\n') + for scriptFilePath in $(find "$testDir" -type f -iname '*.sh' | sort) do - scriptFullPath="$rootDir/$file" - - # Switch to directory where the script is - cd "$(dirname "$scriptFullPath")" - - # Convert DOS line endings to Unix if needed - sed -i 's/\r$//' "$scriptFullPath" - - scriptName=$(basename "$file") - test "$verbose" == 1 && echo "Starting $scriptName" - - # Run the test - ./"$scriptName" | - while testOutput= read -r line - do - # Print the test output if verbose mode is on - test "$verbose" == 1 && echo " $line" - done; - - testScriptExitCode=${PIPESTATUS[0]} - case $testScriptExitCode in - 0) - let countPassedTests++ - echo "PASSED - $scriptFullPath" - ;; - 1) - let countFailedTests++ - echo "FAILED - $scriptFullPath" - ;; - 2) - let countSkippedTests++ - echo "SKIPPED - $scriptFullPath" - ;; - esac - - let countTotalTests++ - - # Return to root directory - cd "$rootDir" + start_test "${scriptFilePath:2}" done } -# Initialize counters for bookkeeping. -countTotalTests=0 -countPassedTests=0 -countFailedTests=0 -countSkippedTests=0 - -currDir=`pwd` +# Argument variables +testRootDir= +testNativeBinDir= +coreOverlayDir= +coreClrBinDir= +mscorlibDir= +coreFxBinDir= +coreFxNativeBinDir= # Handle arguments verbose=0 for i in "$@" do case $i in - -h|--help) - print_usage - exit 0; - ;; - -v|--verbose) - verbose=1 - ;; - --testDirFile=*) - set_test_directories "${i#*=}" - ;; - *);; + -h|--help) + print_usage + exit 0 + ;; + -v|--verbose) + verbose=1 + ;; + --testRootDir=*) + testRootDir=${i#*=} + ;; + --testNativeBinDir=*) + testNativeBinDir=${i#*=} + ;; + --coreOverlayDir=*) + coreOverlayDir=${i#*=} + ;; + --coreClrBinDir=*) + coreClrBinDir=${i#*=} + ;; + --mscorlibDir=*) + mscorlibDir=${i#*=} + ;; + --coreFxBinDir=*) + coreFxBinDir=${i#*=} + ;; + --coreFxNativeBinDir=*) + coreFxNativeBinDir=${i#*=} + ;; + --testDir=*) + testDirectories[${#testDirectories[@]}]=${i#*=} + ;; + --testDirFile=*) + set_test_directories "${i#*=}" + ;; + --runFailingTestsOnly) + ((runFailingTestsOnly = 1)) + ;; + --sequential) + ((maxProcesses = 1)) + ;; + *) + echo "Unknown switch: $i" + print_usage + exit 0 + ;; esac done +if [ -z "$testRootDir" ]; then + echo "--testRootDir is required." + print_usage + exit 1 +fi +if [ ! -d "$testRootDir" ]; then + echo "Directory specified by --testRootDir does not exist: $testRootDir" + exit 1 +fi +cd "$testRootDir" + +xunit_output_begin +create_core_overlay +copy_test_native_bin_to_test_root +load_unsupported_tests +load_failing_tests + if [ -z "$testDirectories" ] then # No test directories were specified, so run everything in the current # directory and its subdirectories. - run_tests_in_directory "$currDir" + run_tests_in_directory "." else # Otherwise, run all the tests in each specified test directory. for testDir in "${testDirectories[@]}" do - run_tests_in_directory $currDir/$testDir + if [ ! -d "$testDir" ]; then + echo "Test directory does not exist: $testDir" + else + run_tests_in_directory "./$testDir" + fi done fi +finish_remaining_tests print_results +xunit_output_end exit 0 diff --git a/tests/src/CLRTest.Execute.Bash.targets b/tests/src/CLRTest.Execute.Bash.targets index 72d3619e69..7e91d5618e 100644 --- a/tests/src/CLRTest.Execute.Bash.targets +++ b/tests/src/CLRTest.Execute.Bash.targets @@ -101,7 +101,7 @@ fi <_CLRTestRunFile Condition="'$(_CLRTestNeedsProjectToRun)' != 'True'">"$(AssemblyName).exe"</_CLRTestRunFile> <!-- TODO: make this better? --> - <_CLRTestRunFile Condition=" '$(CLRTestIsHosted)'=='true' And !$(_CLRTestNeedsProjectToRun) ">"$Core_Root/corerun" $(_CLRTestRunFile)</_CLRTestRunFile> + <_CLRTestRunFile Condition=" '$(CLRTestIsHosted)'=='true' And !$(_CLRTestNeedsProjectToRun) ">"$CORE_ROOT/corerun" $(_CLRTestRunFile)</_CLRTestRunFile> <BashCLRTestLaunchCmds Condition=" '$(BashCLRTestLaunchCmds)'=='' "><![CDATA[ echo $(_CLRTestRunFile) $CLRTestExecutionArguments $Host_Args @@ -129,22 +129,6 @@ CLRTestExitCode=$? <Output TaskParameter="ParamList" PropertyName="_CLRTestParamList"/> </GenerateParamList> - <!-- If a test has precommands or postcommands but no bash-specific ones, - we will skip running that test. In order to enable the test on Unix, - the corresponding bash versions (_BashCLRTest[Pre|Post]Commands) of - the commands should be specified. --> - <PropertyGroup> - <ShouldSkipTest>false</ShouldSkipTest> - <ShouldSkipTest Condition="('$(_CLRTestPreCommands)' != '' AND '$(_BashCLRTestPreCommands)' == '') - OR ('$(_CLRTestPostCommands)' != '' AND '$(_BashCLRTestPostCommands)' == '')" - >true</ShouldSkipTest> - - <SkipTest> -echo "Skipping this test due to presence of pre- or post-commands that are not bash-specific." -exit 2 # Exit code indicating skip - </SkipTest> - </PropertyGroup> - <PropertyGroup> <!-- This generates the script portion to parse all of the command line arguments. @@ -183,14 +167,8 @@ done $(BashCLRTestArgPrep) ]]></BashCLRTestArgPrep> - <_CLRTestExecutionScriptText Condition="$(ShouldSkipTest)"> - <![CDATA[ -$(SkipTest) - ]]> - </_CLRTestExecutionScriptText> - <!-- NOTE! semicolons must be escaped with %3B boooo --> - <_CLRTestExecutionScriptText Condition="!$(ShouldSkipTest)"> + <_CLRTestExecutionScriptText> <![CDATA[ # The __TestEnv variable may be used to specify something to run before the test. $__TestEnv diff --git a/tests/src/CLRTest.Execute.Batch.targets b/tests/src/CLRTest.Execute.Batch.targets index d32feb2f8e..06e9524b95 100644 --- a/tests/src/CLRTest.Execute.Batch.targets +++ b/tests/src/CLRTest.Execute.Batch.targets @@ -103,7 +103,7 @@ IF NOT "%CLRTestExitCode%"=="%CLRTestExpectedExitCode%" ( <_CLRTestRunFile Condition="'$(_CLRTestNeedsProjectToRun)' != 'True'">"$(AssemblyName).exe"</_CLRTestRunFile> <!-- TODO: make this better? --> - <_CLRTestRunFile Condition=" '$(CLRTestIsHosted)'=='true' And !$(_CLRTestNeedsProjectToRun) ">"%Core_Root%\corerun.exe" $(_CLRTestRunFile)</_CLRTestRunFile> + <_CLRTestRunFile Condition=" '$(CLRTestIsHosted)'=='true' And !$(_CLRTestNeedsProjectToRun) ">"%CORE_ROOT%\corerun.exe" $(_CLRTestRunFile)</_CLRTestRunFile> <BatchCLRTestLaunchCmds Condition=" '$(BatchCLRTestLaunchCmds)'=='' "><![CDATA[ ECHO $(_CLRTestRunFile) %CLRTestExecutionArguments% %Host_Args% diff --git a/tests/src/managed/Compilation/Compilation.cs b/tests/src/managed/Compilation/Compilation.cs index 0a0037af29..9b3ebcdd90 100644 --- a/tests/src/managed/Compilation/Compilation.cs +++ b/tests/src/managed/Compilation/Compilation.cs @@ -14,11 +14,11 @@ class Program static int Main(string[] args) { Console.WriteLine("Starting the test"); - string codeFile = @"helloWorld.cs"; + string codeFile = @"HelloWorld.cs"; var sourceTree = new List<SyntaxTree>(){SyntaxFactory.ParseSyntaxTree(File.ReadAllText(codeFile))}; - string mscorlibFile = Path.Combine(Environment.GetEnvironmentVariable("Core_root"), "mscorlib.dll"); + string mscorlibFile = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "mscorlib.dll"); Console.WriteLine("Using reference to: {0}", mscorlibFile); var reference = new List<MetadataReference>(){ MetadataReference.CreateFromFile(mscorlibFile)}; diff --git a/tests/testsFailingOutsideWindows.txt b/tests/testsFailingOutsideWindows.txt new file mode 100644 index 0000000000..ba354dc807 --- /dev/null +++ b/tests/testsFailingOutsideWindows.txt @@ -0,0 +1,76 @@ +Interop/ICastable/Castable.sh +Interop/ReversePInvoke/Marshalling/MarshalBoolArray.sh +JIT/Directed/lifetime/lifetime2.sh +JIT/Directed/newarr/newarr.sh +JIT/Directed/PREFIX/unaligned/1/arglist.sh +JIT/Directed/PREFIX/unaligned/2/arglist.sh +JIT/Directed/PREFIX/unaligned/4/arglist.sh +JIT/Directed/PREFIX/volatile/1/arglist.sh +JIT/Directed/TypedReference/TypedReference.sh +JIT/Methodical/ELEMENT_TYPE_IU/_il_dbgi_ref.sh +JIT/Methodical/ELEMENT_TYPE_IU/_il_dbgu_ref.sh +JIT/Methodical/ELEMENT_TYPE_IU/_il_reli_ref.sh +JIT/Methodical/ELEMENT_TYPE_IU/_il_relu_ref.sh +JIT/Methodical/refany/array1.sh +JIT/Methodical/refany/array2.sh +JIT/Methodical/refany/format.sh +JIT/Methodical/refany/gcreport.sh +JIT/Methodical/refany/_il_dbgarray1.sh +JIT/Methodical/refany/_il_dbgarray2.sh +JIT/Methodical/refany/_il_dbgarray3.sh +JIT/Methodical/refany/_il_dbgnative.sh +JIT/Methodical/refany/_il_dbgseq.sh +JIT/Methodical/refany/_il_dbgu_native.sh +JIT/Methodical/refany/_il_relarray1.sh +JIT/Methodical/refany/_il_relarray2.sh +JIT/Methodical/refany/_il_relarray3.sh +JIT/Methodical/refany/_il_relnative.sh +JIT/Methodical/refany/_il_relseq.sh +JIT/Methodical/refany/_il_relu_native.sh +JIT/Methodical/refany/lcs.sh +JIT/Methodical/refany/native.sh +JIT/Methodical/refany/virtcall.sh +JIT/Methodical/tailcall_v4/tailcall_AV.sh +JIT/Methodical/varargs/callconv/gc_ctor_il_d.sh +JIT/Methodical/varargs/callconv/gc_ctor_il_r.sh +JIT/Methodical/varargs/callconv/val_ctor_il_d.sh +JIT/Methodical/varargs/callconv/val_ctor_il_r.sh +JIT/Methodical/varargs/misc/Dev10_615402.sh +JIT/Methodical/VT/etc/gc_nested.sh +JIT/Methodical/VT/etc/nested.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_I8.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_I.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_R4.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_R8.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_U2.sh +JIT/Methodical/xxobj/ldobj/_il_dbgldobj_V.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_I8.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_I.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_R4.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_R8.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_U2.sh +JIT/Methodical/xxobj/ldobj/_il_relldobj_V.sh +JIT/Methodical/xxobj/operand/_il_dbgrefanyval.sh +JIT/Methodical/xxobj/operand/_il_relrefanyval.sh +JIT/Methodical/xxobj/operand/refanyval.sh +JIT/Regression/CLR-x86-EJIT/V1-M12-Beta2/b26323/b26323.sh +JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b16423/b16423.sh +JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b28901/b28901.sh +JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b29583/b29583.sh +JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b30838/b30838.sh +JIT/Regression/CLR-x86-JIT/V1-M09.5-PDC/b30864/b30864.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b35784/b35784.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b36472/b36472.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b37598/b37598.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b41391/b41391.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b41621/b41621.sh +JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b46867/b46867.sh +JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b31745/b31745.sh +JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b31746/b31746.sh +JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b37646/b37646.sh +JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b41852/b41852.sh +JIT/Regression/CLR-x86-JIT/V1-M12-Beta2/b51575/b51575.sh +JIT/Regression/CLR-x86-JIT/V1-M13-RTM/b88793/b88793.sh +JIT/Regression/CLR-x86-JIT/V1-M13-RTM/b91248/b91248.sh +JIT/Regression/CLR-x86-JIT/V2.0-Beta2/b409748/b409748.sh +Regressions/expl_double/expl_double_1.sh diff --git a/tests/testsUnsupportedOutsideWindows.txt b/tests/testsUnsupportedOutsideWindows.txt new file mode 100644 index 0000000000..dd0509ede1 --- /dev/null +++ b/tests/testsUnsupportedOutsideWindows.txt @@ -0,0 +1,11 @@ +Interop/NativeCallable/NativeCallableTest.sh +JIT/Directed/coverage/oldtests/callipinvoke.sh +JIT/Directed/coverage/oldtests/Desktop/callipinvoke_il_d.sh +JIT/Directed/coverage/oldtests/Desktop/callipinvoke_il_r.sh +JIT/Directed/IL/PInvokeTail/TailWinApi.sh +JIT/Directed/pinvoke/jump.sh +JIT/Directed/pinvoke/sysinfo_il.sh +JIT/Regression/clr-x64-JIT/v2.1/b173569/b173569.sh +managed/Compilation/Compilation.sh +readytorun/mainv1.sh +readytorun/mainv2.sh |