Skip to content

Commit

Permalink
[ObjCRuntime] Improve the debug logging in the Runtime.CoreCLR.cs fil…
Browse files Browse the repository at this point in the history
…e. (#14920)

* Fix an issue where we could run into infinite recursion (and stack overflow)
  when printing method arguments.
* Simplify the output a bit.
  • Loading branch information
rolfbjarne authored May 12, 2022
1 parent a6c92d9 commit 718c72f
Showing 1 changed file with 50 additions and 13 deletions.
63 changes: 50 additions & 13 deletions src/ObjCRuntime/Runtime.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
// which must be set for tracking to work.
//#define TRACK_MONOOBJECTS

// Uncomment VERBOSE_LOG to enable verbose logging
// #define VERBOSE_LOG

#if NET && !COREBUILD

using System;
Expand Down Expand Up @@ -77,13 +80,47 @@ unsafe struct MonoMethodSignature {
static bool? track_monoobject_with_stacktraces;
#endif

// Comment out the attribute to get all printfs
[System.Diagnostics.Conditional ("UNDEFINED")]
// Define VERBOSE_LOG at the top of this file to get all printfs
[System.Diagnostics.Conditional ("VERBOSE_LOG")]
static void log_coreclr (string message)
{
NSLog (message);
}

// Define VERBOSE_LOG at the top of this file to get all printfs
[System.Diagnostics.Conditional ("VERBOSE_LOG")]
static void log_coreclr_render (string message, params object[] argumentsToRender)
{
var args = new string [argumentsToRender.Length];
for (var i = 0; i < args.Length; i++) {
string arg;
var obj = argumentsToRender [i];
if (obj is null) {
arg = "<null>";
} else if (obj is IntPtr ptr) {
arg = $"0x{ptr.ToString ("x")} (IntPtr)";
} else if (obj.GetType ().IsValueType) {
arg = $"{obj.ToString ()} ({obj.GetType ()})";
} else if (obj is INativeObject inativeobj) {
// Don't call ToString on an INativeObject, we may end up with infinite recursion.
arg = $"{inativeobj.Handle.ToString ()} ({obj.GetType ()})";
} else {
var toString = obj.ToString ();
// Print one line, and at most 256 characters.
var strLength = Math.Min (256, toString.Length);
var eol = toString.IndexOf ('\n');
if (eol != -1 && eol < strLength)
strLength = eol;
if (strLength != toString.Length)
toString = toString.Substring (0, strLength) + " [...]";

arg = $"{toString} ({obj.GetType ()})";
}
args [i] = arg;
}
log_coreclr (string.Format (message, args));
}

static unsafe void InitializeCoreCLRBridge (InitializationOptions* options)
{
if (options->xamarin_objc_msgsend != IntPtr.Zero)
Expand Down Expand Up @@ -573,7 +610,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
}

// Log our input
log_coreclr ($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {instance}, 0x{native_parameters.ToString ("x")})");
log_coreclr ($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {(instance is null ? "<null>" : instance.GetType ().FullName)}, 0x{native_parameters.ToString ("x")})");
for (var i = 0; i < methodParameters.Length; i++) {
var nativeParam = nativeParameters [i];
var p = methodParameters [i];
Expand All @@ -591,7 +628,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
log_coreclr ($" Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName} [...]");
log_coreclr ($" Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName}");

if (paramType == typeof (IntPtr)) {
log_coreclr ($" IntPtr");
Expand All @@ -604,7 +641,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
} else {
parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr (nativeParam);
}
log_coreclr ($" => 0x{((IntPtr) parameters [i]).ToString ("x")}");
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsClass || paramType.IsInterface || (paramType.IsValueType && IsNullable (paramType))) {
log_coreclr ($" IsClass/IsInterface/IsNullable IsByRef: {isByRef} IsOut: {p.IsOut} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero) {
Expand All @@ -617,7 +654,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
parameters [i] = GetMonoObjectTarget (mono_obj);
}
}
log_coreclr ($" => {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsValueType) {
log_coreclr ($" IsValueType IsByRef: {isByRef} IsOut: {p.IsOut} nativeParam: 0x{nativeParam.ToString ("x")} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero) {
Expand All @@ -637,7 +674,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
vt = Enum.ToObject (enumType, vt);
parameters [i] = vt;
}
log_coreclr ($" => {(parameters [i] == null ? "<null>" : parameters [i].ToString ())}");
log_coreclr_render (" => {0}", parameters [i]);
} else {
throw ErrorHelper.CreateError (8037, Errors.MX8037 /* Don't know how to marshal the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
}
Expand Down Expand Up @@ -668,13 +705,13 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa

byrefParameterCount++;

log_coreclr ($" Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) value: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");

var parameterType = p.ParameterType.GetElementType ();
var isMonoObject = parameterType.IsClass || parameterType.IsInterface || (parameterType.IsValueType && IsNullable (parameterType));

var nativeParam = nativeParameters [i];

log_coreclr_render ($" Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) nativeParam: 0x{nativeParam.ToString ("x")} value: {{0}}", parameters [i]);

if (nativeParam == IntPtr.Zero) {
log_coreclr ($" No output pointer was provided.");
continue;
Expand All @@ -691,21 +728,21 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa

if (parameterType == typeof (IntPtr)) {
Marshal.WriteIntPtr (nativeParam, (IntPtr) parameters [i]);
log_coreclr ($" IntPtr: 0x{((IntPtr) parameters [i]).ToString ("x")} => Type: {parameters [i]?.GetType ()} nativeParam: 0x{nativeParam.ToString ("x")}");
log_coreclr ($" IntPtr");
} else if (isMonoObject) {
var ptr = GetMonoObject (parameters [i]);
Marshal.WriteIntPtr (nativeParam, ptr);
log_coreclr ($" IsClass/IsInterface/IsNullable: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)} nativeParam: 0x{nativeParam.ToString ("x")} -> MonoObject: 0x{ptr.ToString ("x")}");
log_coreclr ($" IsClass/IsInterface/IsNullable MonoObject: 0x{ptr.ToString ("x")}");
} else if (parameterType.IsValueType) {
StructureToPtr (parameters [i], nativeParam);
log_coreclr ($" IsValueType: {(parameters [i] == null ? "<null>" : parameters [i].ToString ())} nativeParam: 0x{nativeParam.ToString ("x")}");
log_coreclr ($" IsValueType");
} else {
throw ErrorHelper.CreateError (8038, Errors.MX8038 /* Don't know how to marshal back the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
}
}

// we're done!
log_coreclr ($" Invoke complete with {byrefParameterCount} ref parameters and return value of type {rv?.GetType ()}");
log_coreclr_render ($" Invoke complete with {byrefParameterCount} ref parameters and return value: {{0}}", rv);

return rv;
}
Expand Down

5 comments on commit 718c72f

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build] Tests on macOS Mac Catalina (10.15) passed 💻

All tests on macOS Mac Catalina (10.15) passed.

Pipeline on Agent
Hash: 718c72f57e3828dac0a9547045c306b1214d137b

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ [CI Build] Tests on macOS M1 - Mac Big Sur (11.5) failed ❌

Failed tests are:

  • linksdk
  • linkall
  • xammac_tests
  • monotouch-test

Pipeline on Agent
Hash: 718c72f57e3828dac0a9547045c306b1214d137b

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 [CI Build] API Diff 📋

API Current PR diff

ℹ️ API Diff (from PR only) (please review changes)

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

API diff

✅ API Diff from stable

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

Generator diff

Generator Diff (no change)

Pipeline on Agent XAMMINI-054.Monterey'
Hash: 718c72f57e3828dac0a9547045c306b1214d137b

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📚 [CI Build] Artifacts 📚

Packages generated

View packages

Pipeline on Agent XAMMINI-058.Monterey'
Hash: 718c72f57e3828dac0a9547045c306b1214d137b

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ [CI Build] Tests failed on VSTS: simulator tests iOS ❌

Tests failed on VSTS: simulator tests iOS.

Test results

23 tests failed, 211 tests passed.

Failed tests

  • link sdk/Mac [dotnet]/Debug [dotnet]: Failed (Test run failed.
    Tests run: 117 Passed: 107 Inconclusive: 0 Failed: 2 Ignored: 8)
  • link sdk/Mac [dotnet]/Release [dotnet]: Failed (Test run failed.
    Tests run: 117 Passed: 106 Inconclusive: 0 Failed: 2 Ignored: 9)
  • link sdk/Mac Catalyst [dotnet]/Debug [dotnet]: Failed (Test run failed.
    Tests run: 129 Passed: 120 Inconclusive: 0 Failed: 1 Ignored: 8)
  • link sdk/Mac Catalyst [dotnet]/Release [dotnet]: Failed (Test run failed.
    Tests run: 129 Passed: 118 Inconclusive: 0 Failed: 2 Ignored: 9)
  • link sdk/Mac Modern/Debug: Failed (Test run failed.
    Tests run: 9 Passed: 8 Inconclusive: 0 Failed: 1 Ignored: 0)
  • link sdk/Mac Modern/Release: Failed (Test run failed.
    Tests run: 9 Passed: 8 Inconclusive: 0 Failed: 1 Ignored: 0)
  • link sdk/iOS Unified 64-bits - simulator/Debug [dotnet]: Failed
  • link sdk/iOS Unified 64-bits - simulator/Release [dotnet]: Failed
  • link sdk/tvOS - simulator/Release [dotnet]: Failed
  • link sdk/tvOS - simulator/Debug: Failed
  • link sdk/tvOS - simulator/Release: Failed
  • trimmode link/Mac [dotnet]/Debug [dotnet]: Failed (Test run failed.
    Tests run: 117 Passed: 108 Inconclusive: 0 Failed: 1 Ignored: 8)
  • trimmode link/Mac [dotnet]/Release [dotnet]: Failed (Test run failed.
    Tests run: 117 Passed: 107 Inconclusive: 0 Failed: 1 Ignored: 9)
  • trimmode link/Mac Catalyst [dotnet]/Debug [dotnet]: Failed (Test run failed.
    Tests run: 129 Passed: 119 Inconclusive: 0 Failed: 2 Ignored: 8)
  • trimmode link/Mac Catalyst [dotnet]/Release [dotnet]: Failed (Test run failed.
    Tests run: 129 Passed: 119 Inconclusive: 0 Failed: 1 Ignored: 9)
  • trimmode link/iOS Unified 64-bits - simulator/Debug [dotnet]: Failed
  • trimmode link/iOS Unified 64-bits - simulator/Release [dotnet]: Failed
  • trimmode link/tvOS - simulator/Debug [dotnet]: Failed
  • trimmode link/tvOS - simulator/Release [dotnet]: Failed
  • link all/Mac Modern/Release: Failed (Test run failed.
    Tests run: 20 Passed: 18 Inconclusive: 0 Failed: 1 Ignored: 1)
  • monotouch-test/watchOS 32-bits - simulator/Debug (static registrar): TimedOut
  • monotouch-test/watchOS 32-bits - simulator/Release (all optimizations): Crashed
  • monotouch-test/watchOS 32-bits - simulator/Debug (all optimizations): Crashed

Pipeline on Agent XAMBOT-1162.Monterey'
[ObjCRuntime] Improve the debug logging in the Runtime.CoreCLR.cs file. (#14920)

Please sign in to comment.