diff options
Diffstat (limited to 'tests')
22 files changed, 1528 insertions, 261 deletions
diff --git a/tests/CoreFX/CoreFX.issues.json b/tests/CoreFX/CoreFX.issues.json index 9398076e62..35fe2d5d61 100644 --- a/tests/CoreFX/CoreFX.issues.json +++ b/tests/CoreFX/CoreFX.issues.json @@ -455,5 +455,89 @@ "classes": null, "methods": null } + }, + { + "name": "Microsoft.VisualBasic.Tests", + "enabled": true, + "exclusions": { + "namespaces": null, + "classes": null, + "methods": [ + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToChar_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToSingle_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToBoolean_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToSByte_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToDouble_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToDecimal_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToByte_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToLong_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToUShort_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToUInteger_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToInteger_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToShort_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + }, + { + "name" : "Microsoft.VisualBasic.Tests.ConversionsTests.ToULong_InvalidObject_ThrowsInvalidCastException", + "reason" : "outdated" + } + ] + } + }, + { + "name": "System.Numerics.Vectors.Tests", + "enabled": true, + "exclusions": { + "namespaces": null, + "classes": null, + "methods": [ + { + "name" : "System.Numerics.Tests.Vector2Tests.Vector2ClampTest", + "reason" : "outdated" + }, + { + "name" : "System.Numerics.Tests.Vector3Tests.Vector3ClampTest", + "reason" : "outdated" + }, + { + "name" : "System.Numerics.Tests.Vector4Tests.Vector4ClampTest", + "reason" : "outdated" + } + ] + } } ] diff --git a/tests/issues.targets b/tests/issues.targets index 3ff8ff3611..1c1ca62504 100644 --- a/tests/issues.targets +++ b/tests/issues.targets @@ -245,6 +245,12 @@ </ExcludeList> </ItemGroup> + <ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(TargetsWindows)' == 'true'"> + <ExcludeList Include="$(XunitTestBinBase)/tracing/tracecontrol/tracecontrol/*"> + <Issue>Unable to write config file to app location</Issue> + </ExcludeList> + </ItemGroup> + <!-- Windows x64 specific excludes --> <ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(BuildArch)' == 'x64' and '$(TargetsWindows)' == 'true'"> <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/TypeGeneratorTests/TypeGeneratorTest612/Generated612/*"> @@ -381,9 +387,48 @@ <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape_r/*"> <Issue>9565</Issue> </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/GC/API/NoGCRegion/NoGC/*"> + <Issue>needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/baseservices/varargs/varargsupport_r/*"> + <Issue>Varargs supported on this platform</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/baseservices/varargs/varargsupport/*"> + <Issue>Varargs supported on this platform</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/arglist/vararg/*"> + <Issue>Needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/tracing/runtimeeventsource/runtimeeventsource/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/tracing/tracevalidation/inducedgc/inducedgc/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/opt/rngchk/RngchkStress3/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i53/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i13/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i03/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i33/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i63/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i73/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> </ItemGroup> - <!-- Windows arm32 specific excludes --> + <!-- arm32 All OS specific excludes --> <ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(BuildArch)' == 'arm'"> <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/tailcall_v4/hijacking/*"> <Issue>6217</Issue> @@ -391,6 +436,45 @@ <ExcludeList Include="$(XunitTestBinBase)/JIT/opt/Tailcall/TailcallVerifyWithPrefix/*"> <Issue>2420</Issue> </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/baseservices/varargs/varargsupport_r/*"> + <Issue>Varargs supported on this platform</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/baseservices/varargs/varargsupport/*"> + <Issue>Varargs supported on this platform</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/arglist/vararg/*"> + <Issue>Needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/ManagedCallingNative/ManagedCallingNative/*"> + <Issue>Needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/NativeCallingManaged/NativeCallingManaged/*"> + <Issue>Needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/baseservices/exceptions/WindowsEventLog/WindowsEventLog/*"> + <Issue>Needs triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i53/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i13/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i03/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i33/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i63/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i73/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/mcc/interop/mcc_i83/*"> + <Issue>Needs Triage</Issue> + </ExcludeList> </ItemGroup> <!-- The following are x64 Unix failures. --> @@ -474,6 +558,9 @@ <ExcludeList Include="$(XunitTestBinBase)/JIT/jit64/eh/FinallyExec/nonlocalexitinroot/*"> <Issue>Test times out</Issue> </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/GitHub_19361/GitHub_19361/*"> + <Issue>20232</Issue> + </ExcludeList> <ExcludeList Include="$(XunitTestBinBase)/GC/Scenarios/DoublinkList/dlstack/*"> <Issue>Release only crash</Issue> </ExcludeList> diff --git a/tests/runtest.cmd b/tests/runtest.cmd index 45e722f1e7..c0991ce1ee 100644 --- a/tests/runtest.cmd +++ b/tests/runtest.cmd @@ -7,14 +7,18 @@ set "__MsgPrefix=RUNTEST: " set __ThisScriptDir="%~dp0" -call "%__ThisScriptDir%"\..\setup_vs_tools.cmd -if NOT '%ERRORLEVEL%' == '0' exit /b 1 - -if defined VS150COMNTOOLS ( - set __VSVersion=vs2017 -) else ( - set __VSVersion=vs2015 -) +if /I not "%PROCESSOR_ARCHITECTURE%"=="arm64" ( + if /I not "%PROCESSOR_ARCHITECTURE%"=="arm" ( + call "%__ThisScriptDir%"\..\setup_vs_tools.cmd + if NOT '%ERRORLEVEL%' == '0' exit /b 1 + + if defined VS150COMNTOOLS ( + set __VSVersion=vs2017 + ) else ( + set __VSVersion=vs2015 + ) + ) +) :: Set the default arguments set __BuildArch=x64 @@ -43,6 +47,7 @@ set __CoreFXTests= set __CoreFXTestsRunAllAvailable= set __SkipGenerateLayout= set __BuildXUnitWrappers= +set __PrintLastResultsOnly= :Arg_Loop if "%1" == "" goto ArgsDone @@ -82,6 +87,7 @@ if /i "%1" == "ilasmroundtrip" (set __IlasmRoundTrip=1&shift&goto Arg_Loo if /i "%1" == "GenerateLayoutOnly" (set __GenerateLayoutOnly=1&shift&goto Arg_Loop) if /i "%1" == "skipgeneratelayout" (set __SkipGenerateLayout=1&shift&goto Arg_Loop) if /i "%1" == "buildxunitwrappers" (set __BuildXunitWrappers=1&shift&goto Arg_Loop) +if /i "%1" == "printlastresultsonly" (set __PrintLastResultsOnly=1&shift&goto Arg_Loop) if /i "%1" == "PerfTests" (set __PerfTests=true&shift&goto Arg_Loop) if /i "%1" == "CoreFXTests" (set __CoreFXTests=true&shift&goto Arg_Loop) if /i "%1" == "CoreFXTestsAll" (set __CoreFXTests=true&set __CoreFXTestsRunAllAvailable=true&shift&goto Arg_Loop) @@ -198,6 +204,10 @@ if defined __DoCrossgen ( set __RuntestPyArgs=%__RuntestPyArgs% --precompile_core_root ) +if defined __PrintLastResultsOnly ( + set __RuntestPyArgs=%__RuntestPyArgs% --analyze_results_only +) + REM __ProjectDir is poorly named, it is actually <projectDir>/tests set NEXTCMD=python "%__ProjectDir%\runtest.py" %__RuntestPyArgs% echo !NEXTCMD! @@ -691,6 +701,7 @@ echo VSVersion ^<vs_version^> - VS2015 or VS2017 ^(default: VS2017^). echo TestEnv ^<test_env_script^> - Run a custom script before every test to set custom test environment settings. echo AgainstPackages - This indicates that we are running tests that were built against packages. echo GenerateLayoutOnly - If specified will not run the tests and will only create the Runtime Dependency Layout +echo skipgeneratelayout - Do not generate the core root. Used for cross target testing. echo sequential - Run tests sequentially (no parallelism). echo crossgen - Precompile ^(crossgen^) the managed assemblies in CORE_ROOT before running the tests. echo crossgenaltjit ^<altjit^> - Precompile ^(crossgen^) the managed assemblies in CORE_ROOT before running the tests, using the given altjit. @@ -716,6 +727,7 @@ echo timeout ^<n^> - Sets the per-test timeout in milliseconds ^(d echo Note: some options override this ^(gcstresslevel, longgc, gcsimulator^). echo msbuildargs ^<args...^> - Pass all subsequent args directly to msbuild invocations. echo ^<CORE_ROOT^> - Path to the runtime to test ^(if specified^). +echo printlastresultsonly - Print the last test results without running tests. echo. echo Note that arguments are not case-sensitive. echo. diff --git a/tests/runtest.py b/tests/runtest.py index 0845183690..a90a0eab99 100755 --- a/tests/runtest.py +++ b/tests/runtest.py @@ -560,12 +560,10 @@ def call_msbuild(coreclr_repo_location, """ global g_verbose - common_msbuild_arguments = ["/nologo", "/nodeReuse:false", "/p:Platform=%s" % arch] + common_msbuild_arguments = [] if sequential: - common_msbuild_arguments += ["/p:ParallelRun=false"] - else: - common_msbuild_arguments += ["/maxcpucount"] + common_msbuild_arguments += ["/p:ParallelRun=none"] logs_dir = os.path.join(coreclr_repo_location, "bin", "Logs") if not os.path.isdir(logs_dir): @@ -577,6 +575,8 @@ def call_msbuild(coreclr_repo_location, "/p:Runtests=true", "/clp:showcommandline"] + command += common_msbuild_arguments + if is_illink: command += ["/p:RunTestsViaIllink=true"] @@ -671,16 +671,28 @@ def correct_line_endings(host_os, test_location, root=True): for item in os.listdir(test_location): correct_line_endings(host_os, os.path.join(test_location, item), False) elif test_location.endswith(extension): - content = None - with open(test_location) as file_handle: - content = file_handle.read() - - assert content != None - subbed_content = content.replace(incorrect_line_ending, correct_line_ending) + if sys.version_info < (3,0): + + content = None + with open(test_location) as file_handle: + content = file_handle.read() + + assert content != None + subbed_content = content.replace(incorrect_line_ending, correct_line_ending) + + if content != subbed_content: + with open(test_location, 'w') as file_handle: + file_handle.write(subbed_content) - if content != subbed_content: + else: + # Python3 will correct line endings automatically. + + content = None + with open(test_location) as file_handle: + content = file_handle.read() + with open(test_location, 'w') as file_handle: - file_handle.write(subbed_content) + file_handle.write(content) def run_tests(host_os, arch, @@ -866,7 +878,7 @@ def setup_args(args): if test_location[-1] == os.path.sep: test_location = test_location[:-1] - if test_location != default_test_location and os.path.isdir(default_test_location): + if test_location.lower() != default_test_location.lower() and os.path.isdir(default_test_location): # Remove the existing directory if there is one. shutil.rmtree(default_test_location) @@ -916,7 +928,20 @@ def setup_args(args): else: print("Core_Root: %s" % core_root) - if host_os != "Windows_NT": + is_same_os = False + is_same_arch = False + is_same_build_type = False + + # We will write out build information into the test directory. This is used + # by runtest.py to determine whether we need to rebuild the test wrappers. + if os.path.isfile(os.path.join(test_location, "build_info.json")): + with open(os.path.join(test_location, "build_info.json")) as file_handle: + build_info = json.load(file_handle) + is_same_os = build_info["build_os"] == host_os + is_same_arch = build_info["build_arch"] == arch + is_same_build_type = build_info["build_type"] == build_type + + if host_os != "Windows_NT" and not (is_same_os and is_same_arch and is_same_build_type): if test_native_bin_location is None: print("Using default location for test_native_bin_location.") test_native_bin_location = os.path.join(os.path.join(coreclr_repo_location, "bin", "obj", "%s.%s.%s" % (host_os, arch, build_type), "tests")) @@ -1804,6 +1829,16 @@ def print_summary(tests): test_output = test_output.replace("\\n", "\n") print(test_output) + test_output = test_output.replace("/r", "\r") + test_output = test_output.replace("/n", "\n") + unicode_output = None + if sys.version_info < (3,0): + # Handle unicode characters in output in python2.* + unicode_output = unicode(test_output, "utf-8") + else: + unicode_output = test_output + + print(unicode_output) print("") print("") @@ -1898,31 +1933,33 @@ def do_setup(host_os, if gc_stress_c: setup_coredis_tools(coreclr_repo_location, host_os, arch, core_root) + build_info = None + is_same_os = None + is_same_arch = None + is_same_build_type = None + + # We will write out build information into the test directory. This is used + # by runtest.py to determine whether we need to rebuild the test wrappers. + if os.path.isfile(os.path.join(test_location, "build_info.json")): + with open(os.path.join(test_location, "build_info.json")) as file_handle: + build_info = json.load(file_handle) + is_same_os = build_info["build_os"] == host_os + is_same_arch = build_info["build_arch"] == arch + is_same_build_type = build_info["build_type"] == build_type + # Copy all the native libs to core_root - if host_os != "Windows_NT": + if host_os != "Windows_NT" and not (is_same_os and is_same_arch and is_same_build_type): copy_native_test_bin_to_core_root(host_os, os.path.join(test_native_bin_location, "src"), core_root) - correct_line_endings(host_os, test_location) + # Line ending only need to be corrected if this is a cross build. + correct_line_endings(host_os, test_location) if unprocessed_args.build_test_wrappers: build_test_wrappers(host_os, arch, build_type, coreclr_repo_location, test_location) - else: - # We will write out build information into the test directory. This is used - # by runtest.py to determine whether we need to rebuild the test wrappers. - if os.path.isfile(os.path.join(test_location, "build_info.json")): - build_info = None - with open(os.path.join(test_location, "build_info.json")) as file_handle: - build_info = json.load(file_handle) - - is_same_os = build_info["build_os"] == host_os - is_same_arch = build_info["build_arch"] == arch - is_same_build_type = build_info["build_type"] == build_type - - # We will force a build of the test wrappers if they were cross built - if not (is_same_os and is_same_arch and is_same_build_type): - build_test_wrappers(host_os, arch, build_type, coreclr_repo_location, test_location) - else: - build_test_wrappers(host_os, arch, build_type, coreclr_repo_location, test_location) + elif build_info is None: + build_test_wrappers(host_os, arch, build_type, coreclr_repo_location, test_location) + elif not (is_same_os and is_same_arch and is_same_build_type): + build_test_wrappers(host_os, arch, build_type, coreclr_repo_location, test_location) return run_tests(host_os, arch, @@ -1950,6 +1987,8 @@ def main(args): host_os, arch, build_type, coreclr_repo_location, product_location, core_root, test_location, test_native_bin_location = setup_args(args) + ret_code = 0 + env = get_environment(test_env=args.test_env) if not args.analyze_results_only: if args.test_env is not None: diff --git a/tests/runtest.sh b/tests/runtest.sh index 0917094710..e8bd197251 100755 --- a/tests/runtest.sh +++ b/tests/runtest.sh @@ -223,6 +223,7 @@ buildXUnitWrappers= printLastResultsOnly= generateLayoutOnly= generateLayout= +runSequential= for i in "$@" do @@ -340,7 +341,7 @@ do export testHostDir=${i#*=} ;; --sequential) - ((maxProcesses = 1)) + runSequential=1 ;; --useServerGC) ((serverGC = 1)) @@ -535,7 +536,7 @@ if [ ! -z "$generateLayout" ]; then runtestPyArguments+=("--generate_layout") fi -if [ ! -z "$sequential" ]; then +if [ ! "$runSequential" -eq 0 ]; then echo "Run tests sequentially." runtestPyArguments+=("--sequential") fi @@ -552,7 +553,14 @@ if (($doCrossgen!=0)); then runtestPyArguments+=("--precompile_core_root") fi + +# Default to python3 if it is installed +__Python=python + if command -v python3 &>/dev/null; then + __Python=python3 +fi + # Run the tests using cross platform runtest.py echo "python ${scriptPath}/runtest.py ${runtestPyArguments[@]}" -python "${scriptPath}/runtest.py" "${runtestPyArguments[@]}" +$__Python "${scriptPath}/runtest.py" "${runtestPyArguments[@]}" exit "$?" diff --git a/tests/src/Common/Platform/platformdefines.cpp b/tests/src/Common/Platform/platformdefines.cpp index 82061ac90d..826e741e06 100644 --- a/tests/src/Common/Platform/platformdefines.cpp +++ b/tests/src/Common/Platform/platformdefines.cpp @@ -5,312 +5,312 @@ #include "platformdefines.h" -LPWSTR HackyConvertToWSTR(char* pszInput) +LPWSTR HackyConvertToWSTR(const char* pszInput) { - size_t cchInput; - LPWSTR pwszOutput; - char* pStr; + size_t cchInput; + LPWSTR pwszOutput; + char* pStr; - if (NULL == pszInput) return NULL; + if (NULL == pszInput) return NULL; - // poor mans strlen - pStr = pszInput; - cchInput = 0; - while('\0' != *pStr) {cchInput++; pStr++;} - pwszOutput = new WCHAR[ cchInput + 1]; + // poor mans strlen + pStr = (char*)pszInput; + cchInput = 0; + while('\0' != *pStr) {cchInput++; pStr++;} + pwszOutput = new WCHAR[ cchInput + 1]; - for(size_t i=0; i<=cchInput; i++) - { - pwszOutput[i] = (WCHAR)pszInput[i]; - } + for(size_t i=0; i<=cchInput; i++) + { + pwszOutput[i] = (WCHAR)pszInput[i]; + } - return pwszOutput; + return pwszOutput; } LPSTR HackyConvertToSTR(LPWSTR pwszInput) { - size_t cchInput; - LPSTR pszOutput; + size_t cchInput; + LPSTR pszOutput; - if (NULL == pwszInput) return NULL; + if (NULL == pwszInput) return NULL; - cchInput = wcslen(pwszInput); - pszOutput = new char[ cchInput + 1]; + cchInput = wcslen(pwszInput); + pszOutput = new char[ cchInput + 1]; - for(size_t i=0; i<=cchInput; i++) - { - // ugly down cast - pszOutput[i] = (char)pwszInput[i]; - } + for(size_t i=0; i<=cchInput; i++) + { + // ugly down cast + pszOutput[i] = (char)pwszInput[i]; + } - return pszOutput; + return pszOutput; } error_t TP_scpy_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource) { - size_t cnt; - // copy sizeInBytes bytes of strSource into strDestination + size_t cnt; + // copy sizeInBytes bytes of strSource into strDestination - if (NULL == strDestination || NULL == strSource) return 1; + if (NULL == strDestination || NULL == strSource) return 1; - cnt = 0; - while(cnt < sizeInWords && '\0' != strSource[cnt]) - { - strDestination[cnt] = strSource[cnt]; - cnt++; - } - strDestination[cnt] = '\0'; + cnt = 0; + while(cnt < sizeInWords && '\0' != strSource[cnt]) + { + strDestination[cnt] = strSource[cnt]; + cnt++; + } + strDestination[cnt] = '\0'; - return 0; + return 0; } error_t TP_scat_s(LPWSTR strDestination, size_t sizeInWords, LPCWSTR strSource) { - LPWSTR strEnd; - // locate the end (ie. '\0') and TP_scpy_s the string + LPWSTR strEnd; + // locate the end (ie. '\0') and TP_scpy_s the string - if (NULL == strDestination || NULL == strSource) return 1; + if (NULL == strDestination || NULL == strSource) return 1; - strEnd = strDestination; - while('\0' != *strEnd) strEnd++; + strEnd = strDestination; + while('\0' != *strEnd) strEnd++; - return TP_scpy_s(strEnd, sizeInWords - ((strEnd - strDestination) / sizeof(WCHAR)), strSource); + return TP_scpy_s(strEnd, sizeInWords - ((strEnd - strDestination) / sizeof(WCHAR)), strSource); } int TP_slen(LPWSTR str) { - int len; + int len; - if (NULL == str) return 0; + if (NULL == str) return 0; - len = 0; - while('\0' != *(str+len)) len++; + len = 0; + while('\0' != *(str+len)) len++; - return len; + return len; } int TP_scmp_s(LPCSTR str1, LPCSTR str2) { - // < 0 str1 less than str2 - // 0 str1 identical to str2 - // > 0 str1 greater than str2 + // < 0 str1 less than str2 + // 0 str1 identical to str2 + // > 0 str1 greater than str2 - if (NULL == str1 && NULL != str2) return -1; - if (NULL != str1 && NULL == str2) return 1; - if (NULL == str1 && NULL == str2) return 0; + if (NULL == str1 && NULL != str2) return -1; + if (NULL != str1 && NULL == str2) return 1; + if (NULL == str1 && NULL == str2) return 0; - while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) - { - str1++; - str2++; - } + while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) + { + str1++; + str2++; + } - if ('\0' == *str1 && '\0' == *str2) return 0; + if ('\0' == *str1 && '\0' == *str2) return 0; - if ('\0' != *str1) return -1; - if ('\0' != *str2) return 1; + if ('\0' != *str1) return -1; + if ('\0' != *str2) return 1; - return (*str1 > *str2) ? 1 : -1; + return (*str1 > *str2) ? 1 : -1; } int TP_wcmp_s(LPWSTR str1, LPWSTR str2) { - // < 0 str1 less than str2 - // 0 str1 identical to str2 - // > 0 str1 greater than str2 + // < 0 str1 less than str2 + // 0 str1 identical to str2 + // > 0 str1 greater than str2 - if (NULL == str1 && NULL != str2) return -1; - if (NULL != str1 && NULL == str2) return 1; - if (NULL == str1 && NULL == str2) return 0; + if (NULL == str1 && NULL != str2) return -1; + if (NULL != str1 && NULL == str2) return 1; + if (NULL == str1 && NULL == str2) return 0; - while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) - { - str1++; - str2++; - } + while (*str1 == *str2 && '\0' != *str1 && '\0' != *str2) + { + str1++; + str2++; + } - if ('\0' == *str1 && '\0' == *str2) return 0; + if ('\0' == *str1 && '\0' == *str2) return 0; - if ('\0' != *str1) return -1; - if ('\0' != *str2) return 1; + if ('\0' != *str1) return -1; + if ('\0' != *str2) return 1; - return (*str1 > *str2) ? 1 : -1; + return (*str1 > *str2) ? 1 : -1; } error_t TP_getenv_s(size_t* pReturnValue, LPWSTR buffer, size_t sizeInWords, LPCWSTR varname) { - if (NULL == pReturnValue || NULL == varname) return 1; + if (NULL == pReturnValue || NULL == varname) return 1; #ifdef WINDOWS - - size_t returnValue; + + size_t returnValue; WCHAR buf[100]; if( 0 != _wgetenv_s(&returnValue, buf, 100, varname) || returnValue<=0 ) - return 2; - - - TP_scpy_s(buffer, sizeInWords, (LPWSTR)buf); + return 2; + + + TP_scpy_s(buffer, sizeInWords, (LPWSTR)buf); #else - LPSTR pRet; - pRet = getenv( HackyConvertToSTR((LPWSTR)varname) ); - if (NULL == pRet) return 2; - TP_scpy_s(buffer, sizeInWords, HackyConvertToWSTR(pRet)); + LPSTR pRet; + pRet = getenv( HackyConvertToSTR((LPWSTR)varname) ); + if (NULL == pRet) return 2; + TP_scpy_s(buffer, sizeInWords, HackyConvertToWSTR(pRet)); #endif - return 0; + return 0; } error_t TP_putenv_s(LPTSTR name, LPTSTR value) { - if (NULL == name || NULL == value) return 1; + if (NULL == name || NULL == value) return 1; #ifdef WINDOWS - if( 0 != _putenv_s(name, value)) - return 2; - else - return 0; + if( 0 != _putenv_s(name, value)) + return 2; + else + return 0; #else - int retVal = 0; - char *assignment = (char*) malloc(sizeof(char) * (strlen(name) + strlen(value) + 1)); - sprintf(assignment, "%s=%s", name, value); - - if (0 != putenv(assignment)) - retVal = 2; - free(assignment); - return retVal; + int retVal = 0; + char *assignment = (char*) malloc(sizeof(char) * (strlen(name) + strlen(value) + 1)); + sprintf(assignment, "%s=%s", name, value); + + if (0 != putenv(assignment)) + retVal = 2; + free(assignment); + return retVal; #endif } void TP_ZeroMemory(LPVOID buffer, size_t sizeInBytes) { - BYTE* bBuf; + BYTE* bBuf; - // clear out the memory with 0's - if (NULL == buffer) return; + // clear out the memory with 0's + if (NULL == buffer) return; - bBuf = (BYTE*)buffer; - for(size_t i=0; i<sizeInBytes; i++) - { - bBuf[i] = 0; - } + bBuf = (BYTE*)buffer; + for(size_t i=0; i<sizeInBytes; i++) + { + bBuf[i] = 0; + } } error_t TP_itow_s(int num, LPWSTR buffer, size_t sizeInCharacters, int radix) { - size_t len; - int tmpNum; - - // only support radix == 10 and only positive numbers - if (10 != radix) return 1; - if (0 > num) return 2; - if (NULL == buffer) return 3; - if (2 > sizeInCharacters) return 4; - - // take care of the trivial case - if (0 == num) - { - buffer[0] = '\0'; - buffer[1] = '\0'; - } - - // get length of final string (dumb implementation) - len = 0; - tmpNum = num; - while (0 < tmpNum) - { - tmpNum /= 10; - len++; - } - - if (len >= sizeInCharacters) return 5; - - // convert num into a string (backwards) - buffer[len] = '\0'; - while(0 < num && 0 < len) - { + size_t len; + int tmpNum; + + // only support radix == 10 and only positive numbers + if (10 != radix) return 1; + if (0 > num) return 2; + if (NULL == buffer) return 3; + if (2 > sizeInCharacters) return 4; + + // take care of the trivial case + if (0 == num) + { + buffer[0] = '\0'; + buffer[1] = '\0'; + } + + // get length of final string (dumb implementation) + len = 0; + tmpNum = num; + while (0 < tmpNum) + { + tmpNum /= 10; + len++; + } + + if (len >= sizeInCharacters) return 5; + + // convert num into a string (backwards) + buffer[len] = '\0'; + while(0 < num && 0 < len) + { len--; - buffer[len] = (WCHAR)((num % 10) + '0'); - num /= 10; - } + buffer[len] = (WCHAR)((num % 10) + '0'); + num /= 10; + } - return 0; + return 0; } LPWSTR TP_sstr(LPWSTR str, LPWSTR searchStr) { - LPWSTR start; - LPWSTR current; - LPWSTR searchCurrent; - - if (NULL == str || NULL == searchStr) return NULL; - - // return a pointer to where searchStr - // exists in str - current = str; - start = NULL; - searchCurrent = searchStr; - while('\0' != *current) - { - if (NULL != start && '\0' == *searchCurrent) - { - break; - } - - if (*current == *searchCurrent) - { - searchCurrent++; - if (NULL == start) start = current; - } - else - { - searchCurrent = searchStr; - start = NULL; - } - current++; - } - - return start; + LPWSTR start; + LPWSTR current; + LPWSTR searchCurrent; + + if (NULL == str || NULL == searchStr) return NULL; + + // return a pointer to where searchStr + // exists in str + current = str; + start = NULL; + searchCurrent = searchStr; + while('\0' != *current) + { + if (NULL != start && '\0' == *searchCurrent) + { + break; + } + + if (*current == *searchCurrent) + { + searchCurrent++; + if (NULL == start) start = current; + } + else + { + searchCurrent = searchStr; + start = NULL; + } + current++; + } + + return start; } DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer) { #ifdef WINDOWS - return GetFullPathNameW(fileName, nBufferLength, lpBuffer, NULL); + return GetFullPathNameW(fileName, nBufferLength, lpBuffer, NULL); #else - char nativeFullPath[MAX_PATH]; - (void)realpath(HackyConvertToSTR(fileName), nativeFullPath); - LPWSTR fullPathForCLR = HackyConvertToWSTR(nativeFullPath); - wcscpy_s(lpBuffer, MAX_PATH, fullPathForCLR); - return wcslen(lpBuffer); + char nativeFullPath[MAX_PATH]; + (void)realpath(HackyConvertToSTR(fileName), nativeFullPath); + LPWSTR fullPathForCLR = HackyConvertToWSTR(nativeFullPath); + wcscpy_s(lpBuffer, MAX_PATH, fullPathForCLR); + return wcslen(lpBuffer); #endif } DWORD TP_CreateThread(THREAD_ID* tThread, LPTHREAD_START_ROUTINE worker, LPVOID lpParameter) { #ifdef WINDOWS - DWORD ret; - *tThread = CreateThread( - NULL, - 0, - worker, - lpParameter, - 0, - &ret); - return ret; + DWORD ret; + *tThread = CreateThread( + NULL, + 0, + worker, + lpParameter, + 0, + &ret); + return ret; #else - pthread_create( - tThread, - NULL, - (MacWorker)worker, - lpParameter); + pthread_create( + tThread, + NULL, + (MacWorker)worker, + lpParameter); #ifdef MAC64 - // This is a major kludge...64 bit posix threads just can't be cast into a DWORD and there just isn't - // a great way to get what we're using for the ID. The fact that we're casting this at all is kind of - // silly since we're returing the actual thread handle and everything being done to manipulate the thread - // is done with that. Anyhow, the only thing done with the dword returned from this method is a printf - // which is good since this DWORD really shouldn't be reliably used. Just in case it is though, return - // a value that can be traced back to here. - return 42; + // This is a major kludge...64 bit posix threads just can't be cast into a DWORD and there just isn't + // a great way to get what we're using for the ID. The fact that we're casting this at all is kind of + // silly since we're returing the actual thread handle and everything being done to manipulate the thread + // is done with that. Anyhow, the only thing done with the dword returned from this method is a printf + // which is good since this DWORD really shouldn't be reliably used. Just in case it is though, return + // a value that can be traced back to here. + return 42; #else - return (DWORD)*tThread; + return (DWORD)*tThread; #endif #endif } @@ -318,8 +318,184 @@ DWORD TP_CreateThread(THREAD_ID* tThread, LPTHREAD_START_ROUTINE worker, LPVOID void TP_JoinThread(THREAD_ID tThread) { #ifdef WINDOWS - WaitForSingleObject(tThread, INFINITE); + WaitForSingleObject(tThread, INFINITE); #else - pthread_join(tThread, NULL); + pthread_join(tThread, NULL); #endif } + +#define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW +#define ULONG_ERROR (0xffffffffUL) +#define WIN32_ALLOC_ALIGN (16 - 1) +// +// ULONGLONG -> ULONG conversion +// +HRESULT ULongLongToULong(ULONGLONG ullOperand, ULONG* pulResult) +{ + HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + *pulResult = ULONG_ERROR; + + if (ullOperand <= ULONG_MAX) + { + *pulResult = (ULONG)ullOperand; + hr = S_OK; + } + + return hr; +} + +HRESULT ULongAdd(ULONG ulAugend, ULONG ulAddend,ULONG* pulResult) +{ + HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + *pulResult = ULONG_ERROR; + + if ((ulAugend + ulAddend) >= ulAugend) + { + *pulResult = (ulAugend + ulAddend); + hr = S_OK; + } + + return hr; +} + +HRESULT ULongMult(ULONG ulMultiplicand, ULONG ulMultiplier, ULONG* pulResult) +{ + ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier); + + return ULongLongToULong(ull64Result, pulResult); +} + +HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result) +{ + if (result == NULL) + return E_INVALIDARG; + + // +2 for the null terminator + // + DWORD_PTR to store the byte length of the string + int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN; + + if (isByteLen) + { + if (SUCCEEDED(ULongAdd(constant, cchSize, result))) + { + *result = *result & ~WIN32_ALLOC_ALIGN; + return S_OK; + } + } + else + { + ULONG temp = 0; // should not use in-place addition in ULongAdd + if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) & + SUCCEEDED(ULongAdd(temp, constant, result))) + { + *result = *result & ~WIN32_ALLOC_ALIGN; + return S_OK; + } + } + return INTSAFE_E_ARITHMETIC_OVERFLOW; +} + +BSTR TP_SysAllocString(LPWSTR psz) +{ +#ifdef WINDOWS + return SysAllocString(psz); +#else + if(psz == NULL) + return NULL; + return TP_SysAllocStringLen(psz, (DWORD)wcslen(psz)); +#endif +} + +BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len) +{ + ULONG cbTotal = 0; + + if (FAILED(CbSysStringSize((ULONG)len, FALSE, &cbTotal))) + return NULL; + + BSTR bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal); + + if(bstr != NULL){ + +#if defined(_WIN64) + // NOTE: There are some apps which peek back 4 bytes to look at the size of the BSTR. So, in case of 64-bit code, + // we need to ensure that the BSTR length can be found by looking one DWORD before the BSTR pointer. + *(DWORD_PTR *)bstr = (DWORD_PTR) 0; + bstr = (BSTR) ((char *) bstr + sizeof (DWORD)); +#endif + *(DWORD *)bstr = (DWORD)len * sizeof(OLECHAR); + + bstr = (BSTR) ((char*) bstr + sizeof(DWORD)); + + if(psz != NULL){ + memcpy(bstr, psz, len * sizeof(OLECHAR)); + } + + bstr[len] = '\0'; // always 0 terminate + } + + return bstr; +} + +BSTR TP_SysAllocStringByteLen(LPCSTR psz, size_t len) +{ +#ifdef WINDOWS + return SysAllocStringByteLen(psz, (UINT)len); +#else + BSTR bstr; + ULONG cbTotal = 0; + + if (FAILED(CbSysStringSize(len, TRUE, &cbTotal))) + return NULL; + + bstr = (BSTR)TP_CoTaskMemAlloc(cbTotal); + + if (bstr != NULL) { +#if defined(_WIN64) + *(DWORD *)((char *)bstr + sizeof (DWORD)) = (DWORD)len; +#else + *(DWORD *)bstr = (DWORD)len; +#endif + + bstr = (WCHAR*) ((char*) bstr + sizeof(DWORD_PTR)); + + if (psz != NULL) { + memcpy(bstr, psz, len); + } + + // NULL-terminate with both a narrow and wide zero. + *((char *)bstr + len) = '\0'; + *(WCHAR *)((char *)bstr + ((len + 1) & ~1)) = 0; + } + + return bstr; +#endif +} + +void TP_SysFreeString(BSTR bstr) +{ +#ifdef WINDOWS + return SysFreeString(bstr); +#else + if (bstr == NULL) + return; + TP_CoTaskMemFree((BYTE *)bstr - sizeof(DWORD_PTR)); +#endif +} + +size_t TP_SysStringByteLen(BSTR bstr) +{ +#ifdef WINDOWS + return SysStringByteLen(bstr); +#else + if(bstr == NULL) + return 0; + int32_t * p32 = (int32_t *) bstr; + int32_t * p32_1 = p32 -1; + DWORD * d32 = (DWORD *) bstr; + DWORD * d32_1 = d32 - 1; + //std::cout << p32 << p32_1 << endl; + //std::cout << d32 << d32_1 << endl; + return (unsigned int)(((DWORD *)bstr)[-1]); +#endif +} diff --git a/tests/src/Common/Platform/platformdefines.h b/tests/src/Common/Platform/platformdefines.h index 0961e86b2d..aa96483124 100644 --- a/tests/src/Common/Platform/platformdefines.h +++ b/tests/src/Common/Platform/platformdefines.h @@ -6,6 +6,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <cstdint> #ifndef _PLATFORMDEFINES__H #define _PLATFORMDEFINES__H @@ -19,7 +20,7 @@ #define FS_SEPERATOR L"\\" #define PATH_DELIMITER L";" #define L(t) L##t - +#define W(str) L##str typedef unsigned error_t; typedef HANDLE THREAD_ID; @@ -30,11 +31,34 @@ typedef HANDLE THREAD_ID; #include <pthread.h> typedef char16_t WCHAR; -typedef unsigned long DWORD; +typedef unsigned int DWORD; typedef int BOOL; typedef WCHAR *LPWSTR, *PWSTR; typedef const WCHAR *LPCWSTR, *PCWSTR; +typedef long HRESULT; +#define LONGLONG long long +#define ULONGLONG unsigned LONGLONG +typedef unsigned long ULONG, *PULONG; +#define S_OK 0x0 +#define SUCCEEDED(_hr) ((HRESULT)(_hr) >= 0) +#define FAILED(_hr) ((HRESULT)(_hr) < 0) + +#ifdef ULONG_MAX +#undef ULONG_MAX +#endif +#define ULONG_MAX 0xffffffffUL +#define CCH_BSTRMAX 0x7FFFFFFF // 4 + (0x7ffffffb + 1 ) * 2 ==> 0xFFFFFFFC +#define CB_BSTRMAX 0xFFFFFFFa // 4 + (0xfffffff6 + 2) ==> 0xFFFFFFFC + +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) _sc +#else // RC_INVOKED +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#endif // RC_INVOKED +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) +#define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b))) + #ifndef TRUE #define TRUE 1 #endif @@ -51,9 +75,11 @@ typedef const WCHAR *LPCWSTR, *PCWSTR; #if __i386__ #define __stdcall __attribute__((stdcall)) #define _cdecl __attribute__((cdecl)) +#define __cdecl __attribute__((cdecl)) #else #define __stdcall #define _cdecl +#define __cdecl #endif #endif @@ -63,11 +89,12 @@ typedef const WCHAR *LPCWSTR, *PCWSTR; #define DLL_EXPORT #endif -LPWSTR HackyConvertToWSTR(char* pszInput); +LPWSTR HackyConvertToWSTR(const char* pszInput); #define FS_SEPERATOR L("/") #define PATH_DELIMITER L(":") #define L(t) HackyConvertToWSTR(t) +#define W(str) u##str #define MAX_PATH 260 typedef pthread_t THREAD_ID; @@ -91,6 +118,8 @@ typedef unsigned char BYTE; typedef WCHAR OLECHAR; #endif +typedef ULONG_PTR DWORD_PTR; + // // Method declarations // @@ -110,6 +139,13 @@ void TP_JoinThread(THREAD_ID tThread); void TP_DebugBreak(); DWORD TP_GetFullPathName(LPWSTR fileName, DWORD nBufferLength, LPWSTR lpBuffer); +typedef WCHAR* BSTR; +BSTR TP_SysAllocStringByteLen(LPSTR psz, size_t len); +void TP_SysFreeString(BSTR bstr); +size_t TP_SysStringByteLen(BSTR bstr); +BSTR TP_SysAllocStringLen(LPWSTR psz, size_t len); +BSTR TP_SysAllocString(LPWSTR psz); + // // Method redirects // diff --git a/tests/src/Interop/ArrayMarshalling/ByValArray/MarshalArrayByValNative.cpp b/tests/src/Interop/ArrayMarshalling/ByValArray/MarshalArrayByValNative.cpp index 83c844e412..9e6be4ff13 100644 --- a/tests/src/Interop/ArrayMarshalling/ByValArray/MarshalArrayByValNative.cpp +++ b/tests/src/Interop/ArrayMarshalling/ByValArray/MarshalArrayByValNative.cpp @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. #include <xplatform.h> - +#include "platformdefines.h" const int ARRAY_SIZE = 100; template<typename T> bool IsObjectEquals(T o1, T o2); diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index fad9760d99..7b509d6174 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -2,6 +2,7 @@ if(WIN32) list(APPEND LINK_LIBRARIES_ADDITIONAL ole32.lib advapi32.lib + OleAut32.lib ) endif(WIN32) @@ -26,6 +27,7 @@ add_subdirectory(RefCharArray) add_subdirectory(StringMarshalling/LPSTR) add_subdirectory(StringMarshalling/LPTSTR) add_subdirectory(StringMarshalling/UTF8) +add_subdirectory(StringMarshalling/BSTR) add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) add_subdirectory(SizeConst) diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs new file mode 100644 index 0000000000..fbd0b729d4 --- /dev/null +++ b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.cs @@ -0,0 +1,200 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Text; +using NativeDefs; + +class Test +{ + + #region "Report Failure" + static int fails = 0; //record the fail numbers + // Overload methods for reportfailure + static int ReportFailure(string s) + { + Console.WriteLine(" === Fail:" + s); + return (++fails); + } + static int ReportFailure(string expect, string actual) + { + Console.WriteLine(" === Fail: Expected:" + expect + "\n Actual:" + actual); + return (++fails); + } + static int ReportFailure(string describe, string expect, string actual) + { + Console.WriteLine(" === Fail: " + describe + "\n\tExpected:" + expect + "\n\tActual:" + actual); + return (++fails); + } + #endregion + + #region "Helper" + // ************************************************************ + // Returns the appropriate exit code + // ************************************************************* + static int ExitTest() + { + if (fails == 0) + { + Console.WriteLine("PASS"); + return 100; + } + else + { + Console.WriteLine("FAIL - " + fails + " failure(s) occurred"); + return 101; + } + } + #endregion + + #region ReversePInvoke + + public static string Call_DelMarshal_InOut(string s) + { + string strRet; + if (!s.Equals("\u0148")) + { + Console.WriteLine(s.Length); + ReportFailure("Method Call_DelMarshal_InOut[Managed Side],The passed string is wrong", "\u0148", s); + strRet = "\0\0\0"; + return strRet; + } + s = "Managed"; + strRet = "Return\0Return\0"; + return strRet; + } + + public static string Call_DelMarshalPointer_Out(out string s) + { + s = "Native\0String\0"; + string strRet = "Return\0Return\0"; + return strRet; + } + + public static StringBuilder Call_Del_MarshalStrB_InOut(StringBuilder r) + { + StringBuilder retstr = new StringBuilder("Return\0Native"); + + if (!r.ToString().Equals(new StringBuilder("a", 1).ToString())) + { + ReportFailure("Method Call_Del_MarshalStrB_InOut[Managed Side] Failure. String is different than expected", "ă", r.ToString()); + } + r.Replace('a', 'm'); + return retstr; + } + + public static StringBuilder Call_Del_MarshalStrB_Out(out StringBuilder r) + { + StringBuilder retstr = new StringBuilder("Native\0Native"); + r = new StringBuilder("Managed", 7); + return retstr; + } + + #endregion + + public static int Main(string[] args) + { +#pragma warning disable 0219 + string strManaged = "Managed\0String\0"; + string strRet = "a"; + StringBuilder strBRet = new StringBuilder("a", 1); + string strNative = " Native"; + StringBuilder strBNative = new StringBuilder(" Native", 7); +#pragma warning restore 0219 + + //since the out attributes doesnt work for string, so i dont check the out value. + string strPara2 = strManaged; + string strRet2 = PInvokeDef.Marshal_InOut(strPara2); + if (!strRet2.Equals(strRet)) + { + ReportFailure("Method PInvokeDef.Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet2); + } + if (!strPara2.Equals(strManaged)) + { + ReportFailure("Method PInvokeDef.Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara2); + } + + //TestMethod3 + string strPara3 = strManaged; + string strRet3 = PInvokeDef.Marshal_Out(strPara3); + if (!strRet.Equals(strRet3)) + { + ReportFailure("Method PInvokeDef.Marshal_Out[Managed Side],The Return string is wrong", strRet, strRet3); + } + if (!strPara3.Equals(strManaged)) + { + ReportFailure("Method PInvokeDef.Marshal_Out[Managed Side],The Parameter string is not Changed", strManaged, strPara3); + } + + //TestMethod5 + string strPara5 = strManaged; + string strRet5 = PInvokeDef.MarshalPointer_InOut(ref strPara5); + + if (!strRet5.Equals(strRet)) + { + ReportFailure("Method PInvokeDef.MarshalPointer_InOut[Managed Side],The Return string is wrong", strRet, strRet5); + } + if (!strPara5.Equals(strNative)) + { + ReportFailure("Method PInvokeDef.MarshalPointer_InOut[Managed Side],The Passed string is wrong", strNative, strPara5); + } + + //TestMethod6 + string strPara6 = strManaged; + string strRet6 = PInvokeDef.MarshalPointer_Out(out strPara6); + if (!strRet6.Equals(strRet)) + { + ReportFailure("Method PInvokeDef.MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet6); + } + if (!strPara6.Equals(strNative)) + { + ReportFailure("Method PInvokeDef.MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara6); + } + + #region ReversePinvoke + DelMarshal_InOut d1 = new DelMarshal_InOut(Call_DelMarshal_InOut); + if (!PInvokeDef.RPinvoke_DelMarshal_InOut(d1, "\u0148")) + { + ReportFailure("Method RPinvoke_DelMarshal_InOut[Managed Side],Return value is false"); + } + + DelMarshalPointer_Out d2 = new DelMarshalPointer_Out(Call_DelMarshalPointer_Out); + if (!PInvokeDef.RPinvoke_DelMarshalPointer_Out(d2)) + { + ReportFailure("Method RPinvoke_DelMarshal_Out[Managed Side],Return value is false"); + } + + #endregion + #region DelegatePInvoke + + Del_Marshal_InOut d3 = new Del_Marshal_InOut(PInvokeDef.Marshal_InOut); + string strPara9 = strManaged; + string strRet9 = d3(strPara9); + if (!strRet9.Equals(strRet)) + { + ReportFailure("Method Del_Marshal_InOut[Managed Side],The Return string is wrong", strRet, strRet9); + } + if (!strPara9.Equals(strManaged)) + { + ReportFailure("Method Del_Marshal_InOut[Managed Side],The Parameter string is Changed", strManaged, strPara9); + } + + Del_MarshalPointer_Out d4 = new Del_MarshalPointer_Out(PInvokeDef.MarshalPointer_Out); + string strPara10 = strManaged; + string strRet10 = d4(out strPara10); + if (!strRet10.Equals(strRet)) + { + ReportFailure("Method Del_MarshalPointer_Out[Managed Side],The Return string is wrong", strRet, strRet10); + } + if (!strPara10.Equals(strNative)) + { + ReportFailure("Method Del_MarshalPointer_Out[Managed Side],The Passed string is wrong", strNative, strPara10); + } + + #endregion + return ExitTest(); + } +} diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj new file mode 100644 index 0000000000..05c7287f93 --- /dev/null +++ b/tests/src/Interop/StringMarshalling/BSTR/BSTRTest.csproj @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>BSTRTest</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{176EC495-7AE9-42CF-A591-06A382DB4048}</ProjectGuid> + <OutputType>exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <DefineConstants>$(DefineConstants);STATIC</DefineConstants> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="*.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj"> + <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project> + <Name>CoreCLRTestLibrary</Name> + </ProjectReference> + <ProjectReference Include="CMakeLists.txt"> + </ProjectReference> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp b/tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp new file mode 100644 index 0000000000..9a4668bf2e --- /dev/null +++ b/tests/src/Interop/StringMarshalling/BSTR/BSTRTestNative.cpp @@ -0,0 +1,164 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "platformdefines.h" + +WCHAR strManaged[] = W("Managed\0String\0"); +size_t lenstrManaged = sizeof(strManaged) - sizeof(WCHAR); + +WCHAR strReturn[] = W("a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +WCHAR strerrReturn[] = W("error"); + +WCHAR strNative[] = W(" Native"); +size_t lenstrNative = sizeof(strNative) - sizeof(WCHAR); + +//Test Method1 +extern "C" BSTR ReturnString() +{ + return TP_SysAllocString(strReturn); +} + +extern "C" BSTR ReturnErrorString() +{ + return TP_SysAllocString(strerrReturn); +} + +//Test Method2 +extern "C" DLL_EXPORT BSTR Marshal_InOut(/*[In,Out]*/BSTR s) +{ + //Check the Input + size_t len = TP_SysStringByteLen(s); + + if (len != lenstrManaged || memcmp(s,strManaged,lenstrManaged) != 0) + { + printf("Error in Function Marshal_InOut(Native Client)\n"); + printf("Error: Actual: %d, Expected: %d\n",(int32_t) len, (int32_t)lenstrManaged); + + return ReturnErrorString(); + } + + //In-Place Change + memcpy(s, strNative, len); + + //Return + return ReturnString(); +} + + +extern "C" DLL_EXPORT BSTR Marshal_Out(/*[Out]*/BSTR s) +{ + s = TP_SysAllocString(strNative); + + //Return + return ReturnString(); +} + + +extern "C" DLL_EXPORT BSTR MarshalPointer_InOut(/*[in,out]*/BSTR *s) +{ + //Check the Input + size_t len = TP_SysStringByteLen(*s); + + if (len != lenstrManaged || memcmp(*s,strManaged,lenstrManaged)!=0) + { + printf("Error in Function MarshalPointer_InOut\n"); + printf("Error: Expected: %d, Actual: %d", (int32_t)lenstrManaged, (int32_t)len); + + return ReturnErrorString(); + } + + //Allocate New + TP_SysFreeString(*s); + *s = TP_SysAllocString(strNative); + + //Return + return ReturnString(); +} + +extern "C" DLL_EXPORT BSTR MarshalPointer_Out(/*[out]*/ BSTR *s) +{ + *s = TP_SysAllocString(strNative); + return ReturnString(); +} + +typedef BSTR (__stdcall * Test_DelMarshal_InOut)(/*[in]*/ BSTR s); +extern "C" DLL_EXPORT BOOL __cdecl RPinvoke_DelMarshal_InOut(Test_DelMarshal_InOut d, /*[in]*/ BSTR s) +{ + BSTR str = d(s); + WCHAR ret[] = W("Return\0Return\0"); + + size_t lenstr = TP_SysStringByteLen(str); + size_t lenret = sizeof(ret) - sizeof(WCHAR); + + if (lenret != lenstr || memcmp(str,ret,lenstr) != 0) + { + printf("Error in RPinvoke_DelMarshal_InOut, Returned value didn't match\n"); + return FALSE; + } + + TP_SysFreeString(str); + return TRUE; +} + +// +// PInvokeDef.cs explicitly declares that RPinvoke_DelMarshalPointer_Out uses STDCALL +// +typedef BSTR (__cdecl * Test_DelMarshalPointer_Out)(/*[out]*/ BSTR * s); +extern "C" DLL_EXPORT BOOL __stdcall RPinvoke_DelMarshalPointer_Out(Test_DelMarshalPointer_Out d) +{ + BSTR str; + BSTR ret = d(&str); + + WCHAR changedstr[] = W("Native\0String\0"); + + size_t lenstr = TP_SysStringByteLen(str); + size_t lenchangedstr = sizeof(changedstr) - sizeof(WCHAR); + + if ( lenstr != lenchangedstr || (memcmp(str,changedstr,lenstr)!=0)) + { + printf("Error in RPinvoke_DelMarshalPointer_Out, Value didn't change\n"); + return FALSE; + } + + WCHAR expected[] = W("Return\0Return\0"); + size_t lenret = TP_SysStringByteLen(ret); + size_t lenexpected = sizeof(expected) - sizeof(WCHAR); + + if (lenret != lenexpected || memcmp(ret,expected,lenret)!=0) + { + printf("Error in RPinvoke_DelMarshalPointer_Out, Return vaue is different than expected\n"); + return FALSE; + } + + return TRUE; +} + +// +// PInvokeDef.cs explicitly declares that ReverseP_MarshalStrB_InOut uses STDCALL +// +typedef BSTR (__stdcall * Test_Del_MarshalStrB_InOut)(/*[in,out]*/ BSTR s); +extern "C" DLL_EXPORT BOOL __stdcall ReverseP_MarshalStrB_InOut(Test_Del_MarshalStrB_InOut d, /*[in]*/ BSTR s) +{ + BSTR ret = d((BSTR)s); + WCHAR expected[] = W("Return"); + size_t lenret = TP_SysStringByteLen(ret); + size_t lenexpected = sizeof(expected) - sizeof(WCHAR); + + if (lenret != lenexpected || memcmp(ret,expected,lenret) != 0) + { + printf("Error in ReverseP_MarshalStrB_InOut, Return vaue is different than expected\n"); + return FALSE; + } + + WCHAR expectedchange[] = W("m"); + size_t lenstr = TP_SysStringByteLen(s); + size_t lenexpectedchange = sizeof(expectedchange) - sizeof(WCHAR); + + if (lenstr != lenexpectedchange || memcmp(s,expectedchange,lenstr) != 0) + { + printf("Error in ReverseP_MarshalStrB_InOut, Value didn't get change\n"); + return FALSE; + } + return TRUE; +} diff --git a/tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt b/tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt new file mode 100644 index 0000000000..d485437f54 --- /dev/null +++ b/tests/src/Interop/StringMarshalling/BSTR/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required (VERSION 2.6) +project (BSTRTestNative) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES BSTRTestNative.cpp) + +# add the executable +add_library (BSTRTestNative SHARED ${SOURCES}) + +if(WIN32) + list(APPEND LINK_LIBRARIES_ADDITIONAL + OleAut32.lib + ) +endif(WIN32) + +target_link_libraries(BSTRTestNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS BSTRTestNative DESTINATION bin) diff --git a/tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs b/tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs new file mode 100644 index 0000000000..241eeff2e5 --- /dev/null +++ b/tests/src/Interop/StringMarshalling/BSTR/PinvokeDef.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Text; + +namespace NativeDefs +{ + + [return: MarshalAs(UnmanagedType.BStr)] + public delegate string Del_MarshalPointer_Out([MarshalAs(UnmanagedType.BStr)] out string s); + + [return: MarshalAs(UnmanagedType.BStr)] + public delegate string Del_Marshal_InOut([MarshalAs(UnmanagedType.BStr)]string s); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.BStr)] + public delegate string DelMarshalPointer_Out([MarshalAs(UnmanagedType.BStr)][Out] out string s); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.BStr)] + public delegate string DelMarshal_InOut([MarshalAs(UnmanagedType.BStr)][In, Out]string s); + + public static class PInvokeDef + { + public const string NativeBinaryName = "BSTRTestNative"; + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string Marshal_InOut([In, Out][MarshalAs(UnmanagedType.BStr)]string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string Marshal_Out([Out][MarshalAs(UnmanagedType.BStr)]string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string MarshalPointer_InOut([MarshalAs(UnmanagedType.BStr)]ref string s); + + [DllImport(NativeBinaryName)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern string MarshalPointer_Out([MarshalAs(UnmanagedType.BStr)]out string s); + + [DllImport(NativeBinaryName, CallingConvention = CallingConvention.Cdecl)] + public static extern bool RPinvoke_DelMarshal_InOut(DelMarshal_InOut d, [MarshalAs(UnmanagedType.BStr)]string s); + + [DllImport(NativeBinaryName, CallingConvention = CallingConvention.StdCall)] + public static extern bool RPinvoke_DelMarshalPointer_Out(DelMarshalPointer_Out d); + } +} diff --git a/tests/src/Interop/common/types.h b/tests/src/Interop/common/types.h index 37c14546ae..1443e5920f 100755 --- a/tests/src/Interop/common/types.h +++ b/tests/src/Interop/common/types.h @@ -9,7 +9,6 @@ #define INT_MIN (-2147483647 - 1) typedef char16_t WCHAR; -typedef unsigned long DWORD; typedef int BOOL; typedef WCHAR *LPWSTR, *PWSTR; typedef const WCHAR *LPCWSTR, *PCWSTR; @@ -18,7 +17,6 @@ typedef char* LPSTR; typedef const char* LPCSTR; typedef void* FARPROC; typedef void* HMODULE; -typedef void* ULONG_PTR; typedef unsigned error_t; typedef void* LPVOID; typedef unsigned char BYTE; @@ -37,8 +35,6 @@ typedef unsigned short USHORT; typedef signed short SHORT; typedef unsigned short WORD, *PWORD, *LPWORD; -typedef int* DWORD_PTR; - #ifndef TRUE #define TRUE 1 #endif diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.cs b/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.cs new file mode 100644 index 0000000000..2224f6556a --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Numerics; + +namespace GitHub_20260 +{ + class Program + { + static int Main(string[] args) + { + // The jit will devirtualize the call to ToString and then undo the box. + // Make sure that happens properly for vectors. + + Vector<double> x = new Vector<double>(); + string s = ((IFormattable)x).ToString("G", CultureInfo.InvariantCulture); + string e = null; + + switch (Vector<double>.Count) + { + case 2: + e = "<0, 0>"; + break; + case 4: + e = "<0, 0, 0, 0>"; + break; + case 8: + e = "<0, 0, 0, 0, 0, 0, 0, 0>"; + break; + default: + e = "unexpected vector length"; + break; + } + + if (s != e) + { + Console.WriteLine($"FAIL: Expected {e}, got {s}"); + return -1; + } + + Console.WriteLine($"PASS: {s}"); + return 100; + } + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.csproj new file mode 100644 index 0000000000..e191e01217 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_20260/GitHub_20260.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Compile Include="$(MSBuildProjectName).cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il new file mode 100644 index 0000000000..308ead9a37 --- /dev/null +++ b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.il @@ -0,0 +1,91 @@ +.assembly extern System.Runtime { } + +.assembly sharedinterfacemethod { } + +.class interface private abstract auto ansi IFoo`1<T> +{ + .method public hidebysig virtual newslot instance class [System.Runtime]System.Type Frob() cil managed + { + ldtoken !0 + call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + ret + } +} + +.class private auto ansi beforefieldinit Fooer + extends [System.Runtime]System.Object + implements class IFoo`1<class [System.Runtime]System.Object>, + class IFoo`1<valuetype [System.Runtime]System.Int32> +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ret + } +} + +.method public hidebysig static int32 Main() cil managed +{ + .entrypoint + + // Callvirt to a shared interface method + + newobj instance void Fooer::.ctor() + callvirt instance class [System.Runtime]System.Type class IFoo`1<valuetype [System.Runtime]System.Int32>::Frob() + ldtoken valuetype [System.Runtime]System.Int32 + call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + ceq + brtrue UnsharedCallvirtIsGood + + ldc.i4.1 + ret + +UnsharedCallvirtIsGood: + + // Call to a shared interface + + newobj instance void Fooer::.ctor() + call instance class [System.Runtime]System.Type class IFoo`1<valuetype [System.Runtime]System.Int32>::Frob() + ldtoken valuetype [System.Runtime]System.Int32 + call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + ceq + brtrue UnsharedCallIsGood + + ldc.i4.2 + ret + +UnsharedCallIsGood: + + // Callvirt to an unshared interface method + + newobj instance void Fooer::.ctor() + callvirt instance class [System.Runtime]System.Type class IFoo`1<class [System.Runtime]System.Object>::Frob() + ldtoken class [System.Runtime]System.Object + call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + ceq + brtrue SharedCallvirtIsGood + + ldc.i4.3 + ret + +SharedCallvirtIsGood: + + // Call to an unshared interface method + + newobj instance void Fooer::.ctor() + call instance class [System.Runtime]System.Type class IFoo`1<class [System.Runtime]System.Object>::Frob() + ldtoken class [System.Runtime]System.Object + call class [System.Runtime]System.Type class [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + ceq + brtrue SharedCallIsGood + + ldc.i4.4 + ret + +SharedCallIsGood: + + ldc.i4 100 + ret +} diff --git a/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj new file mode 100644 index 0000000000..7521917db5 --- /dev/null +++ b/tests/src/Regressions/coreclr/16775/sharedinterfacemethod.ilproj @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{85DFC527-4DB1-595E-A7D7-E94EE1F8140D}</ProjectGuid> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib> + <OutputType>Exe</OutputType> + <CLRTestKind>BuildAndRun</CLRTestKind> + <CLRTestPriority>0</CLRTestPriority> + </PropertyGroup> + + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + + <ItemGroup> + <Compile Include="sharedinterfacemethod.il" /> + </ItemGroup> + + + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/dir.props b/tests/src/dir.props index 9c367e208d..b56c686d1d 100644 --- a/tests/src/dir.props +++ b/tests/src/dir.props @@ -46,6 +46,7 @@ <OutputPath>$(BaseOutputPathWithConfig)$(BuildProjectRelativeDir)\</OutputPath> <TestWorkingDir Condition="'$(TestWorkingDir)'==''">$(BaseOutputPath)\testStagingDir\</TestWorkingDir> <TestPath Condition="'$(TestPath)'==''">$(TestWorkingDir)$(OSPlatformConfig)\$(MSBuildProjectName)/</TestPath> + <SkipXunitDependencyCopying>true</SkipXunitDependencyCopying> </PropertyGroup> <!-- Disable some standard properties for building our projects --> diff --git a/tests/src/tracing/tracecontrol/TraceControl.cs b/tests/src/tracing/tracecontrol/TraceControl.cs new file mode 100644 index 0000000000..fbdc97abf8 --- /dev/null +++ b/tests/src/tracing/tracecontrol/TraceControl.cs @@ -0,0 +1,113 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Tracing.Tests.Common; + +using Microsoft.Diagnostics.Tracing; +using Microsoft.Diagnostics.Tracing.Parsers.Clr; + +namespace Tracing.Tests +{ + public static class TraceControlTest + { + private static string ConfigFileContents = @" +OutputPath=. +CircularMB=2048 +Providers=*:0xFFFFFFFFFFFFFFFF:5 +"; + + private const int BytesInOneMB = 1024 * 1024; + + /// <summary> + /// This test collects a trace of itself and then performs some basic validation on the trace. + /// </summary> + public static int Main(string[] args) + { + // Calculate the path to the config file. + string configFileName = Assembly.GetEntryAssembly().GetName().Name + ".eventpipeconfig"; + string configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, configFileName); + Console.WriteLine("Calculated config file path: " + configFilePath); + + // Write the config file to disk. + File.WriteAllText(configFilePath, ConfigFileContents); + Console.WriteLine("Wrote contents of config file."); + + // Wait 5 seconds to ensure that tracing has started. + Console.WriteLine("Waiting 5 seconds for the config file to be picked up by the next poll operation."); + Thread.Sleep(TimeSpan.FromSeconds(5)); + + // Do some work that we can look for in the trace. + Console.WriteLine("Do some work that will be captured by the trace."); + GC.Collect(2, GCCollectionMode.Forced); + Console.WriteLine("Done with the work."); + + // Delete the config file to start tracing. + File.Delete(configFilePath); + Console.WriteLine("Deleted the config file."); + + // Build the full path to the trace file. + string[] traceFiles = Directory.GetFiles(".", "*.netperf", SearchOption.TopDirectoryOnly); + Assert.Equal("traceFiles.Length == 1", traceFiles.Length, 1); + string traceFilePath = traceFiles[0]; + + // Poll the file system and wait for the trace file to be written. + Console.WriteLine("Wait for the config file deletion to be picked up and for the trace file to be written."); + + // Wait for 1 second, which is the poll time when tracing is enabled. + Thread.Sleep(TimeSpan.FromSeconds(1)); + + // Poll for file size changes to the trace file itself. When the size of the trace file hasn't changed for 5 seconds, consider it fully written out. + Console.WriteLine("Waiting for the trace file to be written. Poll every second to watch for 5 seconds of no file size changes."); + long lastSizeInBytes = 0; + DateTime timeOfLastChangeUTC = DateTime.UtcNow; + do + { + FileInfo traceFileInfo = new FileInfo(traceFilePath); + long currentSizeInBytes = traceFileInfo.Length; + Console.WriteLine("Trace file size: " + ((double)currentSizeInBytes / BytesInOneMB)); + + if (currentSizeInBytes > lastSizeInBytes) + { + lastSizeInBytes = currentSizeInBytes; + timeOfLastChangeUTC = DateTime.UtcNow; + } + + Thread.Sleep(TimeSpan.FromSeconds(1)); + + } while (DateTime.UtcNow.Subtract(timeOfLastChangeUTC) < TimeSpan.FromSeconds(5)); + + int retVal = 0; + + // Use TraceEvent to consume the trace file and look for the work that we did. + Console.WriteLine("Using TraceEvent to parse the file to find the work that was done during trace capture."); + using (var trace = TraceEventDispatcher.GetDispatcherFromFileName(traceFilePath)) + { + string gcReasonInduced = GCReason.Induced.ToString(); + string providerName = "Microsoft-Windows-DotNETRuntime"; + string gcTriggeredEventName = "GC/Triggered"; + + trace.Clr.GCTriggered += delegate (GCTriggeredTraceData data) + { + if (gcReasonInduced.Equals(data.Reason.ToString())) + { + Console.WriteLine("Detected an induced GC"); + retVal = 100; + } + }; + + trace.Process(); + } + + // Clean-up the resulting trace file. + File.Delete(traceFilePath); + + return retVal; + } + } +} diff --git a/tests/src/tracing/tracecontrol/tracecontrol.csproj b/tests/src/tracing/tracecontrol/tracecontrol.csproj new file mode 100644 index 0000000000..dca25a2e34 --- /dev/null +++ b/tests/src/tracing/tracecontrol/tracecontrol.csproj @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC</DefineConstants> + <CLRTestPriority>0</CLRTestPriority> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"></PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="TraceControl.cs" /> + <ProjectReference Include="../common/common.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> |