diff --git a/src/Agent/NewRelic/Profiler/ConfigurationTest/InstrumentationConfigurationTest.cpp b/src/Agent/NewRelic/Profiler/ConfigurationTest/InstrumentationConfigurationTest.cpp
index 7af24e0f7a..405745a3b8 100644
--- a/src/Agent/NewRelic/Profiler/ConfigurationTest/InstrumentationConfigurationTest.cpp
+++ b/src/Agent/NewRelic/Profiler/ConfigurationTest/InstrumentationConfigurationTest.cpp
@@ -15,7 +15,7 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
class MockTokenResolver : public SignatureParser::ITokenResolver
{
public:
- MockTokenResolver(const std::wstring& typeString = L"MyNamespace.MyClass") : _typeString(typeString) {}
+ MockTokenResolver(const std::wstring& typeString = L"MyNamespace.MyClass") : _typeString(typeString), _typeGenericArgumentCount(0) {}
virtual std::wstring GetTypeStringsFromTypeDefOrRefOrSpecToken(uint32_t /*typeDefOrRefOrSPecToken*/) override
{
@@ -926,5 +926,49 @@ namespace NewRelic { namespace Profiler { namespace Configuration { namespace Te
Assert::IsFalse(instrumentationPoint == nullptr);
}
+ TEST_METHOD(does_not_match_when_assembly_is_mscorlib)
+ {
+ InstrumentationXmlSetPtr xmlSet(new InstrumentationXmlSet());
+ xmlSet->emplace(L"filename", L"\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ ");
+ InstrumentationConfiguration instrumentation(xmlSet);
+ auto function = std::make_shared();
+ function->_assemblyName = _X("mscorlib");
+ auto instrumentationPoint = instrumentation.TryGetInstrumentationPoint(function);
+ Assert::IsTrue(instrumentationPoint == nullptr);
+ }
+
+ TEST_METHOD(does_not_match_when_assembly_is_SystemPrivateCoreLib)
+ {
+ InstrumentationXmlSetPtr xmlSet(new InstrumentationXmlSet());
+ xmlSet->emplace(L"filename", L"\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ ");
+ InstrumentationConfiguration instrumentation(xmlSet);
+ auto function = std::make_shared();
+ function->_assemblyName = _X("System.Private.CoreLib");
+ auto instrumentationPoint = instrumentation.TryGetInstrumentationPoint(function);
+ Assert::IsTrue(instrumentationPoint == nullptr);
+ }
+
};
}}}}
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/AgentCallStyleTests.cpp b/src/Agent/NewRelic/Profiler/MethodRewriterTest/AgentCallStyleTests.cpp
index 2f4acdd603..6383d25c7d 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/AgentCallStyleTests.cpp
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/AgentCallStyleTests.cpp
@@ -37,6 +37,26 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter{ namespace Te
RunTest(_X("true"), _X("true"), AgentCallStyle::Strategy::Reflection);
}
+ TEST_METHOD(AgentCallStrategy_EnvironmentVariable_0)
+ {
+ RunTest(_X("0"), _X("false"), AgentCallStyle::Strategy::InAgentCache);
+ }
+
+ TEST_METHOD(AgentCallStrategy_EnvironmentVariable_1)
+ {
+ RunTest(_X("1"), _X("false"), AgentCallStyle::Strategy::AppDomainCache);
+ }
+
+ TEST_METHOD(AgentCallStrategy_EnvironmentVariable_Empty)
+ {
+ RunTest(_X(""), _X("false"), AgentCallStyle::Strategy::InAgentCache);
+ }
+
+ TEST_METHOD(AgentCallStrategy_EnvironmentVariable_NotSet)
+ {
+ RunTestNoEnvironmentVariablesSet(AgentCallStyle::Strategy::InAgentCache);
+ }
+
TEST_METHOD(AgentCallStrategy_ToString_InAgentCache)
{
const xstring_t expectedValue = _X("In Agent Cache");
@@ -59,22 +79,19 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter{ namespace Te
void RunTest(const xstring_t& legacyCachingEnabled, const xstring_t& disableAppDomainCache, const AgentCallStyle::Strategy expectedStrategy)
{
auto systemCalls = std::make_shared();
- systemCalls->EnvironmentVariableResult = [&legacyCachingEnabled, &disableAppDomainCache](const xstring_t& variableName)
- {
- if (variableName == _X("NEW_RELIC_ENABLE_LEGACY_CACHING"))
- {
- return std::make_unique(legacyCachingEnabled);
- }
- else if (variableName == _X("NEW_RELIC_DISABLE_APPDOMAIN_CACHING"))
- {
- return std::make_unique(disableAppDomainCache);
- }
- else
- {
- return std::make_unique(_X(""));
- }
- };
+ systemCalls->SetEnvironmentVariable(_X("NEW_RELIC_ENABLE_LEGACY_CACHING"), legacyCachingEnabled);
+ systemCalls->SetEnvironmentVariable(_X("NEW_RELIC_DISABLE_APPDOMAIN_CACHING"), disableAppDomainCache);
+
+ AgentCallStyle agentCallStyle(systemCalls);
+
+ const auto callStrategy = agentCallStyle.GetConfiguredCallingStrategy();
+ Assert::AreEqual(static_cast(expectedStrategy), static_cast(callStrategy));
+ }
+
+ void RunTestNoEnvironmentVariablesSet(const AgentCallStyle::Strategy expectedStrategy)
+ {
+ auto systemCalls = std::make_shared();
AgentCallStyle agentCallStyle(systemCalls);
const auto callStrategy = agentCallStyle.GetConfiguredCallingStrategy();
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/FunctionManipulatorTest.cpp b/src/Agent/NewRelic/Profiler/MethodRewriterTest/FunctionManipulatorTest.cpp
index 4e14456d90..75c3a6a57d 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/FunctionManipulatorTest.cpp
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/FunctionManipulatorTest.cpp
@@ -11,6 +11,8 @@
#include "MockSystemCalls.h"
#include "../MethodRewriter/FunctionManipulator.h"
#include "../MethodRewriter/InstrumentFunctionManipulator.h"
+#include "../MethodRewriter/ApiFunctionManipulator.h"
+#include "../MethodRewriter/HelperFunctionManipulator.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
@@ -25,15 +27,201 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
FunctionManipulator manipulator(function, false, AgentCallStyle::Strategy::InAgentCache);
}
- TEST_METHOD(instrument_minimal_method)
+ TEST_METHOD(instrument_api_method_netframework_inagentcache)
{
auto function = std::make_shared();
- InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, L""), false, AgentCallStyle::Strategy::InAgentCache);
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_api_method_netframework_appdomaincache)
+ {
+ auto function = std::make_shared();
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::AppDomainCache);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_api_method_netframework_reflection)
+ {
+ auto function = std::make_shared();
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::Reflection);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_api_method_coreclr_inagentcache)
+ {
+ auto function = std::make_shared();
+ function->_isCoreClr = true;
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_api_method_coreclr_appdomaincache)
+ {
+ auto function = std::make_shared();
+ function->_isCoreClr = true;
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::AppDomainCache);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_api_method_coreclr_reflection)
+ {
+ auto function = std::make_shared();
+ function->_isCoreClr = true;
+ ApiFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::Reflection);
+
+ manipulator.InstrumentApi();
+ }
+
+ TEST_METHOD(instrument_minimal_method_netframework_inagentcache)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::InAgentCache);
+
+ auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
+ manipulator.InstrumentDefault(instrumentationPoint);
+ }
+
+ TEST_METHOD(instrument_minimal_method_netframework_appdomaincache)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::AppDomainCache);
+
+ auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
+ manipulator.InstrumentDefault(instrumentationPoint);
+ }
+
+ TEST_METHOD(instrument_minimal_method_netframework_reflection)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), false, AgentCallStyle::Strategy::Reflection);
+
+ auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
+ manipulator.InstrumentDefault(instrumentationPoint);
+ }
+
+ TEST_METHOD(instrument_minimal_method_coreclr_inagentcache)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::InAgentCache);
+
+ auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
+ manipulator.InstrumentDefault(instrumentationPoint);
+ }
+
+ TEST_METHOD(instrument_minimal_method_coreclr_appdomaincache)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::AppDomainCache);
auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
manipulator.InstrumentDefault(instrumentationPoint);
}
+ TEST_METHOD(instrument_minimal_method_coreclr_reflection)
+ {
+ auto function = std::make_shared();
+ InstrumentFunctionManipulator manipulator(function, std::make_shared(nullptr, _X("")), true, AgentCallStyle::Strategy::Reflection);
+
+ auto instrumentationPoint = CreateInstrumentationPointThatMatchesFunction(function);
+ manipulator.InstrumentDefault(instrumentationPoint);
+ }
+
+ TEST_METHOD(helper_method_unsupported_method)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("ThisMethodShouldNotExist");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_LoadAssemblyOrThrow)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("LoadAssemblyOrThrow");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetTypeViaReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetTypeViaReflectionOrThrow");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetMethodViaReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetMethodViaReflectionOrThrow");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_StoreMethodInAppDomainStorageOrThrow)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("StoreMethodInAppDomainStorageOrThrow");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetMethodFromAppDomainStorage)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetMethodFromAppDomainStorage");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetMethodFromAppDomainStorageOrReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetMethodFromAppDomainStorageOrReflectionOrThrow");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_EnsureInitialized)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("EnsureInitialized");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetMethodCacheLookupMethod)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetMethodCacheLookupMethod");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
+ TEST_METHOD(helper_method_GetMethodInfoFromAgentCache)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("GetMethodInfoFromAgentCache");
+ HelperFunctionManipulator manipulator(function, true, AgentCallStyle::Strategy::InAgentCache);
+
+ manipulator.InstrumentHelper();
+ }
+
//TEST_METHOD(test_method_with_no_code)
//{
// Assert::Fail(L"Test not implemented.");
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/InstrumentorsTest.cpp b/src/Agent/NewRelic/Profiler/MethodRewriterTest/InstrumentorsTest.cpp
new file mode 100644
index 0000000000..c07dc9c42a
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/InstrumentorsTest.cpp
@@ -0,0 +1,434 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include "UnreferencedFunctions.h"
+
+#include "MockFunction.h"
+#include "../MethodRewriter/Instrumentors.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace Test
+{
+ TEST_CLASS(InstrumentatorsTest)
+ {
+ public:
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionShouldNotBeTraced)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("NotInstrumentedMethod");
+ function->_shouldTrace = false;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldTraceWhenFunctionShouldBeTraced)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X("NotInstrumentedMethod");
+ function->_shouldTrace = true;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsTrue(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionHasTdSequentialLayout)
+ {
+ auto function = std::make_shared();
+ function->_classAttributes = CorTypeAttr::tdSequentialLayout;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionHasMdSpecialName)
+ {
+ auto function = std::make_shared();
+ function->_methodAttributes = CorMethodAttr::mdSpecialName;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldTraceWhenFunctionHasMdSpecialNameAndIsConstructor)
+ {
+ auto function = std::make_shared();
+ function->_functionName = _X(".ctor");
+ function->_methodAttributes = CorMethodAttr::mdSpecialName | CorMethodAttr::mdRTSpecialName;
+ function->_shouldTrace = true;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsTrue(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionHasMdPInvokeImpl)
+ {
+ auto function = std::make_shared();
+ function->_methodAttributes = CorMethodAttr::mdPinvokeImpl;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionHasMdUnmanagedExport)
+ {
+ auto function = std::make_shared();
+ function->_methodAttributes = CorMethodAttr::mdUnmanagedExport;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionShouldInjectInstrumentation)
+ {
+ auto function = std::make_shared();
+ // This flag is confusing because it seems to do the opposite of what the name suggests but it is used
+ // to track the difference between an initial JIT and a ReJIT. We inject the instrumentation on a ReJIT.
+ function->_shouldInjectMethodInstrumentation = true;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(DefaultInstrumentor_ShouldNotTraceWhenFunctionIsNotValid)
+ {
+ auto function = std::make_shared();
+ function->_isValid = false;
+
+ DefaultInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(ApiInstrumentor_ShouldNotInstrumentWhenTypeIsNotTheStubApiType)
+ {
+ auto function = std::make_shared();
+ function->_typeName = _X("NotTheApi");
+
+ ApiInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(ApiInstrumentor_ShouldInstrumentWhenTypeIsTheStubApiType)
+ {
+ auto function = std::make_shared();
+ function->_typeName = _X("NewRelic.Api.Agent.NewRelic");
+
+ ApiInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsTrue(result);
+ }
+
+ TEST_METHOD(ApiInstrumentor_ShouldNotInstrumentWhenMethodIsTheStaticConstructor)
+ {
+ auto function = std::make_shared();
+ function->_typeName = _X("NewRelic.Api.Agent.NewRelic");
+ function->_functionName = _X(".cctor");
+
+ ApiInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(ApiInstrumentor_ShouldNotInstrumentWhenMethodIsGetAgent)
+ {
+ auto function = std::make_shared();
+ function->_typeName = _X("NewRelic.Api.Agent.NewRelic");
+ function->_functionName = _X("GetAgent");
+
+ ApiInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInCoreClrWhenAssemblyIsMscorlib)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = _X("mscorlib.dll");
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), true, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInCoreClrWhenAssemblyIsNotSystemPrivateCoreLib)
+ {
+ auto function = std::make_shared();
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), true, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInNetFrameworkWhenAssemblyIsNotMscorlib)
+ {
+ auto function = std::make_shared();
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInCoreClrForTheWrongType)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = _X("System.Private.CoreLib.dll");
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), true, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInNetFrameworkForTheWrongType)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = _X("mscorlib.dll");
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInCoreClrForNonHelperMethods)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = _X("System.Private.CoreLib.dll");
+ function->_typeName = _X("System.CannotUnloadAppDomainException");
+ function->_functionName = _X(".ctor");
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), true, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_ShouldNotInstrumentInNetFrameworkForNonHelperMethods)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = _X("mscorlib.dll");
+ function->_typeName = _X("System.CannotUnloadAppDomainException");
+ function->_functionName = _X(".ctor");
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), false, AgentCallStyle::Strategy::InAgentCache);
+
+ Assert::IsFalse(result);
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetThreadLocalBoolean)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetThreadLocalBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_SetThreadLocalBoolean)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("SetThreadLocalBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetAppDomainBoolean)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetAppDomainBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_SetAppDomainBoolean)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("SetAppDomainBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_LoadAssemblyOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("LoadAssemblyOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetTypeViaReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetTypeViaReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetMethodViaReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetMethodViaReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetMethodFromAppDomainStorage)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetMethodFromAppDomainStorage"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetMethodFromAppDomainStorageOrReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetMethodFromAppDomainStorageOrReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_StoreMethodInAppDomainStorageOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("StoreMethodInAppDomainStorageOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetMethodCacheLookupMethod)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetMethodCacheLookupMethod"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_GetMethodInfoFromAgentCache)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("GetMethodInfoFromAgentCache"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_CoreClr_ShouldInstrument_EnsureInitialized)
+ {
+ AssertHelperMethodIsInstrumented(true, _X("EnsureInitialized"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetThreadLocalBoolean)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetThreadLocalBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_SetThreadLocalBoolean)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("SetThreadLocalBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetAppDomainBoolean)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetAppDomainBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_SetAppDomainBoolean)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("SetAppDomainBoolean"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_LoadAssemblyOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("LoadAssemblyOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetTypeViaReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetTypeViaReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetMethodViaReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetMethodViaReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetMethodFromAppDomainStorage)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetMethodFromAppDomainStorage"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetMethodFromAppDomainStorageOrReflectionOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetMethodFromAppDomainStorageOrReflectionOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_StoreMethodInAppDomainStorageOrThrow)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("StoreMethodInAppDomainStorageOrThrow"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetMethodCacheLookupMethod)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetMethodCacheLookupMethod"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_GetMethodInfoFromAgentCache)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("GetMethodInfoFromAgentCache"));
+ }
+
+ TEST_METHOD(HelperInstrumentor_NetFramework_ShouldInstrument_EnsureInitialized)
+ {
+ AssertHelperMethodIsInstrumented(false, _X("EnsureInitialized"));
+ }
+
+ private:
+ InstrumentationSettingsPtr GetInstrumentationSettings() const
+ {
+ Configuration::InstrumentationXmlSetPtr xmlSet(new Configuration::InstrumentationXmlSet());
+ xmlSet->emplace(L"filename", L"\
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ \
+ ");
+ Configuration::InstrumentationConfigurationPtr instrumentation(new Configuration::InstrumentationConfiguration(xmlSet));
+ return std::make_shared(instrumentation, _X(""));
+ }
+
+ void AssertHelperMethodIsInstrumented(const bool isCoreClr, const xstring_t& functionName)
+ {
+ auto function = std::make_shared();
+ function->_assemblyName = function->_moduleName = isCoreClr ? _X("System.Private.CoreLib.dll") : _X("mscorlib.dll");
+ function->_typeName = _X("System.CannotUnloadAppDomainException");
+ function->_functionName = functionName;
+
+ HelperInstrumentor instrumentor;
+
+ auto result = instrumentor.Instrument(function, GetInstrumentationSettings(), isCoreClr, AgentCallStyle::Strategy::InAgentCache);
+
+ // The method returns false even in the success case
+ Assert::IsFalse(result);
+ }
+ };
+}}}}
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.cpp b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.cpp
index d15a7d0684..ad0c99b85d 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.cpp
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.cpp
@@ -16,11 +16,11 @@
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
-namespace NewRelic { namespace Profiler { namespace MethodRewriter {
- namespace Test {
- TEST_CLASS(MethodRewriterTest){
- public :
- /*
+namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace Test {
+ TEST_CLASS(MethodRewriterTest)
+ {
+ public:
+ /*
TEST_METHOD(request_function_name_callback)
{
// setup a default method rewriter and function to instrument
@@ -38,53 +38,291 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter {
ValidateDefaultMockFunctionCallback();
}*/
- TEST_METHOD(overloads_are_instrumented){
- // ARRANGE
- auto overload1 = std::make_shared();
- BYTEVECTOR(signature1Bytes,
- 0x00, // default calling convention
- 0x01, // 1 parameter
- 0x01, // void return
- 0x12, // parameter 1 class
- 0x49 // class token (compressed 0x01000012)
- );
- overload1->_signature = std::make_shared(signature1Bytes);
-
- auto overload2 = std::make_shared();
- BYTEVECTOR(signature2Bytes,
- 0x00, // default calling convention
- 0x01, // 1 parameter
- 0x01, // void return
- 0x0e // parameter 1 string
- );
- overload1->_signature = std::make_shared(signature2Bytes);
-
- auto instrumentationSet = std::make_shared();
- instrumentationSet->insert(overload1->GetInstrumentationPoint());
- instrumentationSet->insert(overload2->GetInstrumentationPoint());
- auto instrumentation = std::make_shared(instrumentationSet);
- auto methodRewriter = std::make_shared(instrumentation, _X(""), false);
-
- uint8_t overload1CallCount = 0;
- overload1->_writeMethodHandler = [&overload1CallCount](const ByteVector&) {
- ++overload1CallCount;
- };
-
- uint8_t overload2CallCount = 0;
- overload2->_writeMethodHandler = [&overload2CallCount](const ByteVector&) {
- ++overload2CallCount;
- };
-
- // ACT
- methodRewriter->Instrument(overload1, AgentCallStyle::Strategy::InAgentCache);
- methodRewriter->Instrument(overload2, AgentCallStyle::Strategy::InAgentCache);
-
- // ASSERT
- Assert::AreEqual((uint8_t)1, overload1CallCount, L"Function should have been instrumented 1 time!");
- Assert::AreEqual((uint8_t)1, overload2CallCount, L"Function should have been instrumented 1 time!");
- }
-
-private:
+ TEST_METHOD(overloads_are_instrumented)
+ {
+ // ARRANGE
+ auto overload1 = std::make_shared();
+ BYTEVECTOR(signature1Bytes,
+ 0x00, // default calling convention
+ 0x01, // 1 parameter
+ 0x01, // void return
+ 0x12, // parameter 1 class
+ 0x49 // class token (compressed 0x01000012)
+ );
+ overload1->_signature = std::make_shared(signature1Bytes);
+
+ auto overload2 = std::make_shared();
+ BYTEVECTOR(signature2Bytes,
+ 0x00, // default calling convention
+ 0x01, // 1 parameter
+ 0x01, // void return
+ 0x0e // parameter 1 string
+ );
+ overload1->_signature = std::make_shared(signature2Bytes);
+
+ auto instrumentationSet = std::make_shared();
+ instrumentationSet->insert(overload1->GetInstrumentationPoint());
+ instrumentationSet->insert(overload2->GetInstrumentationPoint());
+ auto instrumentation = std::make_shared(instrumentationSet);
+ auto methodRewriter = std::make_shared(instrumentation, _X(""), false);
+
+ uint8_t overload1CallCount = 0;
+ overload1->_writeMethodHandler = [&overload1CallCount](const ByteVector&) {
+ ++overload1CallCount;
+ };
+
+ uint8_t overload2CallCount = 0;
+ overload2->_writeMethodHandler = [&overload2CallCount](const ByteVector&) {
+ ++overload2CallCount;
+ };
+
+ // ACT
+ methodRewriter->Instrument(overload1, AgentCallStyle::Strategy::InAgentCache);
+ methodRewriter->Instrument(overload2, AgentCallStyle::Strategy::InAgentCache);
+
+ // ASSERT
+ Assert::AreEqual((uint8_t)1, overload1CallCount, L"Function should have been instrumented 1 time!");
+ Assert::AreEqual((uint8_t)1, overload2CallCount, L"Function should have been instrumented 1 time!");
+ }
+
+ TEST_METHOD(GetConfigurationReturnsPointerToOriginalConfiguration)
+ {
+ auto function = std::make_shared();
+
+ auto instrumentation = GetInstrumentationConfigurationForFunction(function);
+
+ auto methodRewriter = std::make_shared(instrumentation, _X(""), false);
+
+ Assert::IsTrue(instrumentation == methodRewriter->GetInstrumentationConfiguration());
+ }
+
+ TEST_METHOD(GetAssemblyInstrumentation_IsEmptyWhenAssemblyIsNotInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ auto instrumentationForAssembly = methodRewriter->GetAssemblyInstrumentation(_X("ADifferentAssembly"));
+
+ Assert::AreEqual(static_cast(0), instrumentationForAssembly.size());
+ }
+
+ TEST_METHOD(GetAssemblyInstrumentation_IsNotEmptyWhenAssemblyIsInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ auto instrumentationForAssembly = methodRewriter->GetAssemblyInstrumentation(function->GetAssemblyName());
+
+ Assert::AreEqual(static_cast(1), instrumentationForAssembly.size());
+ }
+
+ TEST_METHOD(ShouldInstrumentAssembly_FalseWhenAssemblyIsNotInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsFalse(methodRewriter->ShouldInstrumentAssembly(_X("ADifferentAssembly")));
+ }
+
+ TEST_METHOD(ShouldInstrumentAssembly_TrueWhenAssemblyIsInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentAssembly(function->GetAssemblyName()));
+ }
+
+ TEST_METHOD(ShouldInstrumentType_FalseWhenTypeIsNotInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsFalse(methodRewriter->ShouldInstrumentType(_X("ADifferentType")));
+ }
+
+ TEST_METHOD(ShouldInstrumentType_TrueWhenTypeIsInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentType(function->GetTypeName()));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_FalseWhenFunctionIsNotInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsFalse(methodRewriter->ShouldInstrumentFunction(_X("ADifferentMethod")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_TrueWhenFunctionIsInstrumented)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(function->GetFunctionName()));
+ }
+
+ // The following tests ensure that the helper methods are included in the collection of instrumented methods
+
+ TEST_METHOD(ShouldInstrumentAssembly_Mscorlib)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentAssembly(_X("mscorlib")));
+ }
+
+ TEST_METHOD(ShouldInstrumentAssembly_SystemPrivateCoreLib)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentAssembly(_X("System.Private.CoreLib")));
+ }
+
+ TEST_METHOD(ShouldInstrumentType_SystemCannotUnloadAppDomainException)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentType(_X("System.CannotUnloadAppDomainException")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetAppDomainBoolean)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetAppDomainBoolean")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetThreadLocalBoolean)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetThreadLocalBoolean")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_SetThreadLocalBoolean)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("SetThreadLocalBoolean")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetMethodFromAppDomainStorageOrReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetMethodFromAppDomainStorageOrReflectionOrThrow")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetMethodFromAppDomainStorage)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetMethodFromAppDomainStorage")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetMethodViaReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetMethodViaReflectionOrThrow")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetTypeViaReflectionOrThrow)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetTypeViaReflectionOrThrow")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_LoadAssemblyOrThrow)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("LoadAssemblyOrThrow")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_StoreMethodInAppDomainStorageOrThrow)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("StoreMethodInAppDomainStorageOrThrow")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetMethodCacheLookupMethod)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetMethodCacheLookupMethod")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_EnsureInitialized)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("EnsureInitialized")));
+ }
+
+ TEST_METHOD(ShouldInstrumentFunction_GetMethodInfoFromAgentCache)
+ {
+ auto function = std::make_shared();
+
+ auto methodRewriter = GetMethodRewriterWithConfigurationForFunction(function);
+
+ Assert::IsTrue(methodRewriter->ShouldInstrumentFunction(_X("GetMethodInfoFromAgentCache")));
+ }
+
+ private:
+ Configuration::InstrumentationConfigurationPtr GetInstrumentationConfigurationForFunction(std::shared_ptr function)
+ {
+ auto instrumentationSet = std::make_shared();
+ instrumentationSet->insert(function->GetInstrumentationPoint());
+
+ return std::make_shared(instrumentationSet);
+ }
+
+ std::shared_ptr GetMethodRewriterWithConfigurationForFunction(std::shared_ptr function)
+ {
+ return std::make_shared(GetInstrumentationConfigurationForFunction(function), _X(""), false);
+ }
+
/*
static void ValidateDefaultMockFunctionCallback()
{
@@ -107,7 +345,6 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter {
catch (...) { }
}
*/
-};
-}}
-}
-}
+ };
+
+}}}}
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.vcxproj b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.vcxproj
index 4d4ce4eff1..410171fa38 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.vcxproj
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MethodRewriterTest.vcxproj
@@ -194,6 +194,7 @@
+
Create
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockFunction.h b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockFunction.h
index 0bd7651dc0..c637f749fe 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockFunction.h
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockFunction.h
@@ -47,7 +47,13 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
_signatureToken(0x456),
_string(L"[MyAssembly]MyNamespace.MyClass.MyMethod"),
_isGenericType(false),
- _typeToken(0x045612345)
+ _typeToken(0x045612345),
+ _isCoreClr(false),
+ _shouldInjectMethodInstrumentation(false),
+ _shouldTrace(false),
+ _classAttributes(0),
+ _methodAttributes(0),
+ _isValid(true)
{
if (version.empty())
{
@@ -138,14 +144,16 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
return std::make_shared((uint16_t)1);
}
+ unsigned long _classAttributes;
virtual unsigned long GetClassAttributes() override
{
- return 0;
+ return _classAttributes;
}
+ unsigned long _methodAttributes;
virtual unsigned long GetMethodAttributes() override
{
- return 0;
+ return _methodAttributes;
}
virtual bool Preprocess() override
@@ -153,9 +161,10 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
return true;
}
+ bool _shouldTrace;
virtual bool ShouldTrace() override
{
- return false;
+ return _shouldTrace;
}
std::wstring _version;
@@ -171,9 +180,10 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
};
}
+ bool _shouldInjectMethodInstrumentation;
virtual bool ShouldInjectMethodInstrumentation() override
{
- return false;
+ return _shouldInjectMethodInstrumentation;
}
virtual uint32_t GetTracerFlags() override
@@ -181,14 +191,16 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
return 0;
}
+ bool _isValid;
virtual bool IsValid() override
{
- return true;
+ return _isValid;
}
+ bool _isCoreClr;
virtual bool IsCoreClr() override
{
- return false;
+ return _isCoreClr;
}
uint32_t _typeToken;
diff --git a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockSystemCalls.h b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockSystemCalls.h
index d630a2020d..3ab16c7b1d 100644
--- a/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockSystemCalls.h
+++ b/src/Agent/NewRelic/Profiler/MethodRewriterTest/MockSystemCalls.h
@@ -5,24 +5,33 @@
#include
#include
#include
+#include
#include "../MethodRewriter/ISystemCalls.h"
namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace Test {
struct MockSystemCalls : ISystemCalls
{
- std::function(const std::wstring&)> EnvironmentVariableResult;
+ MockSystemCalls() { }
- MockSystemCalls()
+ virtual std::unique_ptr TryGetEnvironmentVariable(const xstring_t& variableName) override
{
- EnvironmentVariableResult = [](const std::wstring&)
+ auto search = _environmentVariables.find(variableName);
+ if (search != _environmentVariables.end())
{
- return std::unique_ptr(new std::wstring(L"C:\\foo\\bar"));
- };
+ return std::make_unique(search->second);
+ }
+
+ return nullptr;
}
- virtual std::unique_ptr TryGetEnvironmentVariable(const std::wstring& variableName) override
+ void SetEnvironmentVariable(const xstring_t& name, const xstring_t& value)
{
- return EnvironmentVariableResult(variableName);
+ _environmentVariables[name] = value;
+ }
+
+ void ResetEnvironmentVariables()
+ {
+ _environmentVariables.clear();
}
virtual bool FileExists(const xstring_t&) override
@@ -41,5 +50,8 @@ namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace T
virtual std::unique_ptr GetNewRelicProfilerLogDirectory() override { return nullptr; }
virtual std::unique_ptr GetNewRelicLogDirectory() override { return nullptr; }
virtual std::unique_ptr GetNewRelicLogLevel() override { return nullptr; }
+
+ private:
+ std::unordered_map _environmentVariables;
};
}}}}
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjector/IModule.h b/src/Agent/NewRelic/Profiler/ModuleInjector/IModule.h
index 2ff8063793..4990b9678e 100644
--- a/src/Agent/NewRelic/Profiler/ModuleInjector/IModule.h
+++ b/src/Agent/NewRelic/Profiler/ModuleInjector/IModule.h
@@ -30,8 +30,6 @@ namespace NewRelic { namespace Profiler { namespace ModuleInjector
virtual bool NeedsReferenceToCoreLib() = 0;
virtual bool GetIsThisTheCoreLibAssembly() = 0;
- virtual CComPtr GetMetaDataAssemblyEmit() = 0;
-
virtual sicily::codegen::ITokenizerPtr GetTokenizer() = 0;
};
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjector/ModuleInjector.h b/src/Agent/NewRelic/Profiler/ModuleInjector/ModuleInjector.h
index 0305c4bbb8..1f701efb27 100644
--- a/src/Agent/NewRelic/Profiler/ModuleInjector/ModuleInjector.h
+++ b/src/Agent/NewRelic/Profiler/ModuleInjector/ModuleInjector.h
@@ -125,8 +125,6 @@ namespace NewRelic { namespace Profiler { namespace ModuleInjector
}
catch (NewRelic::Profiler::Win32Exception&)
{
- //exception in an error if we are injecting methods, otherwise, just neat to know.
- //if is System.Private.CoreLib, allow the loop to proceed. if not, break out of the loop
if (is_coreLib)
{
LogError(L"Failed to tokenize method signature: ", signatum, L". Proceeding to next method.");
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/MockModule.h b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/MockModule.h
new file mode 100644
index 0000000000..309d5b46e8
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/MockModule.h
@@ -0,0 +1,88 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include "../ModuleInjector/IModule.h"
+#include "../Sicily/SicilyTest/RealisticTokenizer.h"
+
+namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace Test
+{
+ class MockModule : public ModuleInjector::IModule
+ {
+ public:
+ MockModule() :
+ _moduleName(_X("MyModule")),
+ _needsReferenceToCoreLib(false),
+ _injectReferenceToCoreLib(true),
+ _isThisTheCoreLibAssembly(false),
+ _tokenizer(std::make_shared())
+ {
+ }
+
+ xstring_t _moduleName;
+ virtual xstring_t GetModuleName() override
+ {
+ return _moduleName;
+ }
+
+ std::function _injectPlatformInvoke;
+ virtual void InjectPlatformInvoke(const xstring_t& methodName, const xstring_t& className, const xstring_t& moduleName, const ByteVector& signature) override
+ {
+ if (_injectPlatformInvoke)
+ {
+ _injectPlatformInvoke(methodName, className, moduleName, signature);
+ }
+ }
+
+ std::function _injectStaticSecuritySafeMethod;
+ virtual void InjectStaticSecuritySafeMethod(const xstring_t& methodName, const xstring_t& className, const ByteVector& signature) override
+ {
+ if (_injectStaticSecuritySafeMethod)
+ {
+ _injectStaticSecuritySafeMethod(methodName, className, signature);
+ }
+ }
+
+ std::function _injectCoreLibSecuritySafeMethodReference;
+ virtual void InjectCoreLibSecuritySafeMethodReference(const xstring_t& methodName, const xstring_t& className, const ByteVector& signature) override
+ {
+ if (_injectCoreLibSecuritySafeMethodReference)
+ {
+ _injectCoreLibSecuritySafeMethodReference(methodName, className, signature);
+ }
+ }
+
+ std::function _injectNRHelperType;
+ virtual void InjectNRHelperType() override
+ {
+ if (_injectNRHelperType)
+ {
+ _injectNRHelperType();
+ }
+ }
+
+ bool _injectReferenceToCoreLib;
+ virtual bool InjectReferenceToCoreLib() override
+ {
+ return _injectReferenceToCoreLib;
+ }
+
+ bool _needsReferenceToCoreLib;
+ virtual bool NeedsReferenceToCoreLib() override
+ {
+ return _needsReferenceToCoreLib;
+ }
+
+ bool _isThisTheCoreLibAssembly;
+ virtual bool GetIsThisTheCoreLibAssembly() override
+ {
+ return _isThisTheCoreLibAssembly;
+ }
+
+ sicily::codegen::ITokenizerPtr _tokenizer;
+ virtual sicily::codegen::ITokenizerPtr GetTokenizer() override
+ {
+ return _tokenizer;
+ }
+ };
+}}}}
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.cpp b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.cpp
new file mode 100644
index 0000000000..3134f0e278
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.cpp
@@ -0,0 +1,211 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#include
+#include
+#include
+#include
+#define WIN32_LEAN_AND_MEAN
+#include
+#define LOGGER_DEFINE_STDLOG
+#include
+#include
+#include "CppUnitTest.h"
+
+#include "MockModule.h"
+#include "../ModuleInjector/ModuleInjector.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace NewRelic { namespace Profiler { namespace MethodRewriter { namespace Test
+{
+ TEST_CLASS(ModuleInjectorTest)
+ {
+ public:
+ TEST_METHOD(ModuleInjector_CoreClr_DoesNotCrash_CannotEnsureReferenceToCoreLib)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_needsReferenceToCoreLib = true;
+ modulePtr->_injectReferenceToCoreLib = false;
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_DoesNotCrash_CannotEnsureReferenceToCoreLib)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_needsReferenceToCoreLib = true;
+ modulePtr->_injectReferenceToCoreLib = false;
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, false);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_InjectsHelperType)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = true;
+ bool wasHelperTypeInjected(false);
+ modulePtr->_injectNRHelperType = [&wasHelperTypeInjected]() { wasHelperTypeInjected = true; };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, true);
+
+ Assert::IsTrue(wasHelperTypeInjected);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_InjectsHelperType)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = true;
+ bool wasHelperTypeInjected(false);
+ modulePtr->_injectNRHelperType = [&wasHelperTypeInjected]() { wasHelperTypeInjected = true; };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, false);
+
+ Assert::IsTrue(wasHelperTypeInjected);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_InjectsHelperMethods_DoesNotThrow)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = true;
+ modulePtr->_injectNRHelperType = []() { throw NewRelic::Profiler::Win32Exception(E_UNEXPECTED); };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_InjectsHelperMethods_DoesNotThrow)
+ {
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = true;
+ modulePtr->_injectNRHelperType = []() { throw NewRelic::Profiler::Win32Exception(E_UNEXPECTED); };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, false);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_InjectsHelperMethods)
+ {
+ AssertHelperMethodsWereInjected(true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_InjectsHelperMethods)
+ {
+ AssertHelperMethodsWereInjected(false);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_AlwaysAttemptsToInjectAllMethods)
+ {
+ AssertHelperMethodsWereInjected(/*isCoreClr*/ true, /*throwsException*/ true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_AlwaysAttemptsToInjectAllMethods)
+ {
+ AssertHelperMethodsWereInjected(/*isCoreClr*/ false, /*throwsException*/ true);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_InjectsHelperMethodReferences)
+ {
+ AssertHelperMethodReferencesWereInjected(true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_InjectsHelperMethodReferences)
+ {
+ AssertHelperMethodReferencesWereInjected(false);
+ }
+
+ TEST_METHOD(ModuleInjector_CoreClr_AlwaysAttemptsToInjectAllMethodReferences)
+ {
+ AssertHelperMethodReferencesWereInjected(/*isCoreClr*/ true, /*throwsException*/ true);
+ }
+
+ TEST_METHOD(ModuleInjector_NetFramework_AlwaysAttemptsToInjectAllMethodReferences)
+ {
+ AssertHelperMethodReferencesWereInjected(/*isCoreClr*/ false, /*throwsException*/ true);
+ }
+
+ private:
+ void AssertHelperMethodsWereInjected(const bool isCoreClr)
+ {
+ AssertHelperMethodsWereInjected(isCoreClr, false);
+ }
+
+ void AssertHelperMethodsWereInjected(const bool isCoreClr, const bool throwsException)
+ {
+ std::array expectedMethods = {
+ _X("System.CannotUnloadAppDomainException.LoadAssemblyOrThrow"),
+ _X("System.CannotUnloadAppDomainException.GetTypeViaReflectionOrThrow"),
+ _X("System.CannotUnloadAppDomainException.GetMethodViaReflectionOrThrow"),
+ _X("System.CannotUnloadAppDomainException.GetMethodFromAppDomainStorage"),
+ _X("System.CannotUnloadAppDomainException.GetMethodFromAppDomainStorageOrReflectionOrThrow"),
+ _X("System.CannotUnloadAppDomainException.StoreMethodInAppDomainStorageOrThrow"),
+ _X("System.CannotUnloadAppDomainException.EnsureInitialized"),
+ _X("System.CannotUnloadAppDomainException.GetMethodInfoFromAgentCache"),
+ _X("System.CannotUnloadAppDomainException.GetMethodCacheLookupMethod")
+ };
+
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = true;
+ std::set injectedMethodNamesWithType;
+ modulePtr->_injectStaticSecuritySafeMethod = [&injectedMethodNamesWithType, throwsException](const xstring_t& methodName, const xstring_t& className, const ByteVector& /*signature*/)
+ {
+ injectedMethodNamesWithType.emplace(className + _X(".") + methodName);
+ if (throwsException)
+ {
+ throw NewRelic::Profiler::Win32Exception(E_UNEXPECTED);
+ }
+ };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, isCoreClr);
+
+ Assert::AreEqual(expectedMethods.size(), injectedMethodNamesWithType.size());
+
+ for (const auto& expected : expectedMethods)
+ {
+ auto search = injectedMethodNamesWithType.find(expected);
+ Assert::IsTrue(search != injectedMethodNamesWithType.end(), (expected + _X(" was not found")).c_str());
+ }
+ }
+
+ void AssertHelperMethodReferencesWereInjected(const bool isCoreClr)
+ {
+ AssertHelperMethodReferencesWereInjected(isCoreClr, false);
+ }
+
+ void AssertHelperMethodReferencesWereInjected(const bool isCoreClr, const bool throwsException)
+ {
+ const xstring_t expectedAssembly = isCoreClr ? _X("[System.Private.CoreLib]") : _X("[mscorlib]");
+ std::array expectedMethods = {
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.LoadAssemblyOrThrow"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetTypeViaReflectionOrThrow"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetMethodViaReflectionOrThrow"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetMethodFromAppDomainStorage"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetMethodFromAppDomainStorageOrReflectionOrThrow"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.StoreMethodInAppDomainStorageOrThrow"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.EnsureInitialized"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetMethodInfoFromAgentCache"),
+ expectedAssembly + _X("System.CannotUnloadAppDomainException.GetMethodCacheLookupMethod")
+ };
+
+ auto modulePtr = std::make_shared();
+ modulePtr->_isThisTheCoreLibAssembly = false;
+ std::set injectedMethodNamesWithType;
+ modulePtr->_injectCoreLibSecuritySafeMethodReference = [&injectedMethodNamesWithType, throwsException](const xstring_t& methodName, const xstring_t& className, const ByteVector& /*signature*/)
+ {
+ injectedMethodNamesWithType.emplace(className + _X(".") + methodName);
+ if (throwsException)
+ {
+ throw NewRelic::Profiler::Win32Exception(E_UNEXPECTED);
+ }
+ };
+
+ ModuleInjector::ModuleInjector::InjectIntoModule(*modulePtr, isCoreClr);
+
+ Assert::AreEqual(expectedMethods.size(), injectedMethodNamesWithType.size());
+
+ for (const auto& expected : expectedMethods)
+ {
+ auto search = injectedMethodNamesWithType.find(expected);
+ Assert::IsTrue(search != injectedMethodNamesWithType.end(), (expected + _X(" was not found")).c_str());
+ }
+ }
+ };
+}}}}
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.vcxproj b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.vcxproj
new file mode 100644
index 0000000000..67199760eb
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/ModuleInjectorTest.vcxproj
@@ -0,0 +1,207 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}
+ Win32Proj
+ ModuleInjectorTest
+ 10.0.18362.0
+ NativeUnitTestProject
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+ false
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+ false
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+ false
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)bin\$(PlatformTarget)\$(Configuration)\
+ $(ProjectDir)obj\$(PlatformTarget)\$(Configuration)\
+
+
+ true
+ $(ProjectDir)bin\$(PlatformTarget)\$(Configuration)\
+ $(ProjectDir)obj\$(PlatformTarget)\$(Configuration)\
+
+
+ false
+ $(ProjectDir)bin\$(PlatformTarget)\$(Configuration)\
+ $(ProjectDir)obj\$(PlatformTarget)\$(Configuration)\
+
+
+ false
+ $(ProjectDir)bin\$(PlatformTarget)\$(Configuration)\
+ $(ProjectDir)obj\$(PlatformTarget)\$(Configuration)\
+
+
+
+ Use
+ Level4
+ Disabled
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;%(PreprocessorDefinitions)
+ true
+ true
+ MultiThreadedDebug
+ stdafx.h
+ 4091
+
+
+ Windows
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Use
+ Disabled
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;%(PreprocessorDefinitions)
+ true
+ true
+ Level4
+ MultiThreadedDebug
+ stdafx.h
+ true
+ 4091
+
+
+ Windows
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+ true
+
+
+
+
+ Level4
+ Use
+ MaxSpeed
+ true
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;%(PreprocessorDefinitions)
+ true
+ true
+ MultiThreaded
+ stdafx.h
+ 4091
+
+
+ Windows
+ true
+ true
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+ Level4
+ Use
+ MaxSpeed
+ true
+ true
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;%(PreprocessorDefinitions)
+ true
+ true
+ MultiThreaded
+ stdafx.h
+ 4091
+
+
+ Windows
+ true
+ true
+ true
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+ {27654994-8403-4bd4-9d1d-4bccc4e93de6}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/UnreferencedFunctions.h b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/UnreferencedFunctions.h
new file mode 100644
index 0000000000..65de1ec3c9
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/UnreferencedFunctions.h
@@ -0,0 +1,98 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+#include
+
+// fix unreferenced local functions warning in CppUnitTest.h
+static inline void UseUnreferenced()
+{
+ std::wstring (*boolFunc)(const bool&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)boolFunc;
+ std::wstring (*intFunc)(const int&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)intFunc;
+ std::wstring (*longFunc)(const long&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)longFunc;
+ std::wstring (*shortFunc)(const short&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)shortFunc;
+ std::wstring (*charFunc)(const char&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)charFunc;
+ std::wstring (*wchar_tFunc)(const wchar_t&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)wchar_tFunc;
+ std::wstring (*signedCharFunc)(const signed char&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)signedCharFunc;
+ std::wstring (*unsignedIntFunc)(const unsigned int&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedIntFunc;
+ std::wstring (*unsignedLongFunc)(const unsigned long&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongFunc;
+ std::wstring (*unsignedLongLongFunc)(const unsigned long long&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongLongFunc;
+ std::wstring (*unsignedCharFunc)(const unsigned char&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedCharFunc;
+ std::wstring (*stringFunc)(const std::string&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)stringFunc;
+ std::wstring (*wstringFunc)(const std::wstring&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)wstringFunc;
+ std::wstring (*doubleFunc)(const double&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)doubleFunc;
+ std::wstring (*floatFunc)(const float&) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)floatFunc;
+
+ std::wstring (*boolFuncConstPtr)(const bool*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)boolFuncConstPtr;
+ std::wstring (*intFuncConstPtr)(const int*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)intFuncConstPtr;
+ std::wstring (*longFuncConstPtr)(const long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)longFuncConstPtr;
+ std::wstring (*shortFuncConstPtr)(const short*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)shortFuncConstPtr;
+ std::wstring (*signedCharFuncConstPtr)(const signed char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)signedCharFuncConstPtr;
+ std::wstring (*unsignedIntFuncConstPtr)(const unsigned int*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedIntFuncConstPtr;
+ std::wstring (*unsignedLongFuncConstPtr)(const unsigned long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongFuncConstPtr;
+ std::wstring (*unsignedLongLongFuncConstPtr)(const unsigned long long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongLongFuncConstPtr;
+ std::wstring (*unsignedCharFuncConstPtr)(const unsigned char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedCharFuncConstPtr;
+ std::wstring (*charFuncConstPtr)(const char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)charFuncConstPtr;
+ std::wstring (*wchar_tFuncConstPtr)(const wchar_t*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)wchar_tFuncConstPtr;
+ std::wstring (*doubleFuncConstPtr)(const double*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)doubleFuncConstPtr;
+ std::wstring (*floatFuncConstPtr)(const float*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)floatFuncConstPtr;
+ std::wstring (*voidFuncConstPtr)(const void*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)voidFuncConstPtr;
+
+ std::wstring (*boolFuncPtr)(bool*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)boolFuncPtr;
+ std::wstring (*intFuncPtr)(int*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)intFuncPtr;
+ std::wstring (*longFuncPtr)(long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)longFuncPtr;
+ std::wstring (*shortFuncPtr)(short*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)shortFuncPtr;
+ std::wstring (*signedCharFuncPtr)(signed char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)signedCharFuncPtr;
+ std::wstring (*unsignedIntFuncPtr)(unsigned int*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedIntFuncPtr;
+ std::wstring (*unsignedLongFuncPtr)(unsigned long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongFuncPtr;
+ std::wstring (*unsignedLongLongFuncPtr)(unsigned long long*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedLongLongFuncPtr;
+ std::wstring (*unsignedCharFuncPtr)(unsigned char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)unsignedCharFuncPtr;
+ std::wstring (*charFuncPtr)(char*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)charFuncPtr;
+ std::wstring (*wchar_tFuncPtr)(wchar_t*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)wchar_tFuncPtr;
+ std::wstring (*doubleFuncPtr)(double*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)doubleFuncPtr;
+ std::wstring (*floatFuncPtr)(float*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)floatFuncPtr;
+ std::wstring (*voidFuncPtr)(void*) = &Microsoft::VisualStudio::CppUnitTestFramework::ToString;
+ (void)voidFuncPtr;
+}
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.cpp b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.cpp
new file mode 100644
index 0000000000..d06dc4585c
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.cpp
@@ -0,0 +1,4 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "stdafx.h"
diff --git a/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.h b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.h
new file mode 100644
index 0000000000..cddfcfe7ed
--- /dev/null
+++ b/src/Agent/NewRelic/Profiler/ModuleInjectorTest/stdafx.h
@@ -0,0 +1,10 @@
+// Copyright 2020 New Relic, Inc. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+// Headers for CppUnitTest
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include "UnreferencedFunctions.h"
diff --git a/src/Agent/NewRelic/Profiler/NewRelic.Profiler.sln b/src/Agent/NewRelic/Profiler/NewRelic.Profiler.sln
index 9ca3fd2c1f..2d02e3f7c2 100644
--- a/src/Agent/NewRelic/Profiler/NewRelic.Profiler.sln
+++ b/src/Agent/NewRelic/Profiler/NewRelic.Profiler.sln
@@ -49,6 +49,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfiledMethods", "Profiled
{DD9D2763-2E4F-48AA-BDFD-E23ABB9822AB} = {DD9D2763-2E4F-48AA-BDFD-E23ABB9822AB}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModuleInjectorTest", "ModuleInjectorTest\ModuleInjectorTest.vcxproj", "{1534117B-A2B3-4403-B391-20DCC8AAEE44}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -209,6 +211,14 @@ Global
{BA254DEB-EA81-428A-8BA7-BA55B0395D7A}.Release|Win32.Build.0 = Release|x86
{BA254DEB-EA81-428A-8BA7-BA55B0395D7A}.Release|x64.ActiveCfg = Release|x64
{BA254DEB-EA81-428A-8BA7-BA55B0395D7A}.Release|x64.Build.0 = Release|x64
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Debug|Win32.Build.0 = Debug|Win32
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Debug|x64.ActiveCfg = Debug|x64
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Debug|x64.Build.0 = Debug|x64
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Release|Win32.ActiveCfg = Release|Win32
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Release|Win32.Build.0 = Release|Win32
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Release|x64.ActiveCfg = Release|x64
+ {1534117B-A2B3-4403-B391-20DCC8AAEE44}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Agent/NewRelic/Profiler/Profiler/Module.h b/src/Agent/NewRelic/Profiler/Profiler/Module.h
index 80226f367b..f9b1b6d432 100644
--- a/src/Agent/NewRelic/Profiler/Profiler/Module.h
+++ b/src/Agent/NewRelic/Profiler/Profiler/Module.h
@@ -66,8 +66,6 @@ namespace NewRelic { namespace Profiler
virtual bool GetIsThisTheCoreLibAssembly() override { return _isCoreLibAssembly; }
- virtual CComPtr GetMetaDataAssemblyEmit() override{ return _metaDataAssemblyEmit; }
-
virtual void InjectPlatformInvoke(const xstring_t& methodName, const xstring_t& className, const xstring_t& moduleName, const ByteVector& signature) override
{
auto interfaceAttributes = CorMethodAttr::mdStatic | CorMethodAttr::mdPublic | CorMethodAttr::mdPinvokeImpl;
diff --git a/src/Agent/NewRelic/Profiler/Sicily/SicilyTest/ParserTest.cpp b/src/Agent/NewRelic/Profiler/Sicily/SicilyTest/ParserTest.cpp
index 38fa027984..6d45f4fdcf 100644
--- a/src/Agent/NewRelic/Profiler/Sicily/SicilyTest/ParserTest.cpp
+++ b/src/Agent/NewRelic/Profiler/Sicily/SicilyTest/ParserTest.cpp
@@ -17,12 +17,17 @@ namespace sicily
{
private:
void TestParser(std::wstring testString)
+ {
+ TestParser(testString, testString);
+ }
+
+ void TestParser(const xstring_t& testString, const xstring_t& expectedParsedString)
{
Scanner scanner(testString);
Parser parser;
ast::TypePtr rootType = parser.Parse(scanner);
Assert::IsTrue(rootType != nullptr, L"rootType was nullptr");
- Assert::AreEqual(std::wstring(testString), rootType->ToString());
+ Assert::AreEqual(expectedParsedString, rootType->ToString());
}
public:
@@ -195,6 +200,73 @@ namespace sicily
{
TestParser(L"int32 System.Threading.Interlocked::CompareExchange(int32&, int32, int32)");
}
+
+ TEST_METHOD(EmptyStringToParseThrowsException)
+ {
+ Assert::ExpectException([this]() {TestParser(_X("")); });
+ }
+
+ TEST_METHOD(ParsingIncompleteInstanceMethodThrowsException)
+ {
+ Assert::ExpectException([this]() {TestParser(_X("instance void")); });
+ }
+
+ TEST_METHOD(ParsingInvalidMethodTypeThrowsException)
+ {
+ Assert::ExpectException([this]() {TestParser(_X("instance void void")); });
+ }
+
+ TEST_METHOD(ParseComplexClassName)
+ {
+ TestParser(_X("class [assemblyname]Foo1_2Bar.__something"));
+ }
+
+ TEST_METHOD(ParseClassNameWithSlashes)
+ {
+ TestParser(_X("class [assemblyname]Foo/Bar"));
+ }
+
+ TEST_METHOD(ParseClassNameWithSpacesBeforeDotss)
+ {
+ // Foo .Bar -> Foo.Bar
+ TestParser(_X("class [assemblyname]Foo .Bar"), _X("class [assemblyname]Foo.Bar"));
+ }
+
+ TEST_METHOD(ParsingGenericClassWithIncorrectGenericCountThrowsException)
+ {
+ Assert::ExpectException([this]() { TestParser(_X("class [mscorlib]System.Action`1