Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to enable/disable EXC_BAD_ACCESS suppression #3998

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a1b0cb6
Initial commit for exposing iOS native before send & crashed last run
aritchie Feb 11, 2025
1a8474e
Initial feature set is working
aritchie Feb 11, 2025
c36be94
Format code
getsentry-bot Feb 11, 2025
cd074d4
Update CHANGELOG.md
aritchie Feb 11, 2025
17790c7
Merge branch '2102-ios_beforesend_oncrashedlastrun' of https://github…
aritchie Feb 11, 2025
70a677d
Merge signal abort code before user based BeforeSend
aritchie Feb 12, 2025
4a6462c
Move native BeforeSend & OnCrashedLastRun events to SentryOptions - O…
aritchie Feb 14, 2025
91145ab
Always run NativeOptions.BeforeSend so sig aborts can be filtered
aritchie Feb 14, 2025
fd48026
Update SentrySdk.cs
aritchie Feb 14, 2025
1b3dfdd
Merge branch 'main' into 2102-ios_beforesend_oncrashedlastrun
aritchie Feb 18, 2025
c29a785
Update CHANGELOG.md
aritchie Feb 18, 2025
50a5554
Format code
getsentry-bot Feb 18, 2025
63e3f55
WIP - removing serialization mechanics as they cause a native crash d…
aritchie Feb 18, 2025
5c06eb5
Transferring transformed sentryevent back to original native event in…
aritchie Feb 21, 2025
18a1079
Merge branch 'main' into 2102-ios_beforesend_oncrashedlastrun
aritchie Feb 21, 2025
000b324
Remove unnecessary hacks
aritchie Feb 21, 2025
bdfe3a9
Format code
getsentry-bot Feb 21, 2025
bf4d33d
Add missing bindable option for native iOS sentryoptions
aritchie Feb 21, 2025
52f0699
Update SentrySdk.cs
aritchie Feb 24, 2025
dab118e
Update SentrySdk.cs
aritchie Feb 24, 2025
1f721b8
Update CHANGELOG.md
aritchie Feb 24, 2025
4830f8e
Update CHANGELOG.md
aritchie Feb 24, 2025
b8b08cc
Unit tests mapping checks to/from native iOS
aritchie Feb 24, 2025
a46bd43
Format code
getsentry-bot Feb 24, 2025
5dca9e2
Update NativeSerializationTests.cs
aritchie Feb 24, 2025
00cbc04
Revert "Add missing bindable option for native iOS sentryoptions"
aritchie Feb 24, 2025
d2776e1
Remove iOS native event suppress configuration
aritchie Feb 24, 2025
4be3abb
Ability to suppress native errors
aritchie Feb 24, 2025
fc85bce
Update CHANGELOG.md
aritchie Feb 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features

- Using SentryOptions.SuppressSegfaults, users can now block duplicate errors from native due to dotnet NullReferenceExceptions - Defaults to false ([#3998](https://github.com/getsentry/sentry-dotnet/pull/3998))
- Native iOS events are now exposed to the dotnet layer for users to hook through SentryOptions.BeforeSend and SentryOptions.OnCrashedLastRun ([#2102](https://github.com/getsentry/sentry-dotnet/pull/3958))
- Serilog scope properties are now sent with Sentry events ([#3976](https://github.com/getsentry/sentry-dotnet/pull/3976))
- The sample seed used for sampling decisions is now propagated, for use in downstream custom trace samplers ([#3951](https://github.com/getsentry/sentry-dotnet/pull/3951))

Expand All @@ -25,6 +27,8 @@
- Native SIGSEGV errors resulting from managed NullReferenceExceptions are now suppressed on Android ([#3903](https://github.com/getsentry/sentry-dotnet/pull/3903))
- OTel activities that are marked as not recorded are no longer sent to Sentry ([#3890](https://github.com/getsentry/sentry-dotnet/pull/3890))
- Fixed envelopes with oversized attachments getting stuck in __processing ([#3938](https://github.com/getsentry/sentry-dotnet/pull/3938))
- Unknown stack frames in profiles on .NET 8+ ([#3942](https://github.com/getsentry/sentry-dotnet/pull/3942))
- Deduplicate profiling stack frames ([#3941](https://github.com/getsentry/sentry-dotnet/pull/3941))
- OperatingSystem will now return macOS as OS name instead of 'Darwin' as well as the proper version. ([#2710](https://github.com/getsentry/sentry-dotnet/pull/3956))
- Ignore null value on CocoaScopeObserver.SetTag ([#3948](https://github.com/getsentry/sentry-dotnet/pull/3948))
- Deduplicate profiling stack frames ([#3969](https://github.com/getsentry/sentry-dotnet/pull/3969))
Expand Down
11 changes: 11 additions & 0 deletions samples/Sentry.Samples.Ios/AppDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ public override bool FinishedLaunching(UIApplication application, NSDictionary l
options.Native.EnableAppHangTracking = true;

options.CacheDirectoryPath = Path.GetTempPath();

options.SetBeforeSend((evt, _) =>
{
evt.SetTag("dotnet-iOS-Native-Before", "Hello World");
return evt;
});

options.OnCrashedLastRun = e =>
{
Console.WriteLine(e);
};
});

// create a new window instance based on the screen size
Expand Down
2 changes: 1 addition & 1 deletion samples/Sentry.Samples.Ios/Sentry.Samples.Ios.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0-ios18.0</TargetFramework>
<TargetFramework>net9.0-ios</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
Expand Down
1 change: 0 additions & 1 deletion src/Sentry.Bindings.Cocoa/ApiDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ namespace Sentry.CocoaSdk;

// typedef SentryEvent * _Nullable (^SentryBeforeSendEventCallback)(SentryEvent * _Nonnull);
[Internal]
[return: NullAllowed]
delegate SentryEvent SentryBeforeSendEventCallback (SentryEvent @event);

// typedef id<SentrySpan> _Nullable (^SentryBeforeSendSpanCallback)(id<SentrySpan> _Nonnull);
Expand Down
24 changes: 24 additions & 0 deletions src/Sentry/Internal/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,30 @@ public static void Deconstruct(this JsonProperty jsonProperty, out string name,
return double.Parse(json.ToString()!, CultureInfo.InvariantCulture);
}

/// <summary>
/// Safety value to deal with native serialization - allows datetimeoffset to come in as a long or string value
/// </summary>
/// <param name="json"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public static DateTimeOffset? GetSafeDateTimeOffset(this JsonElement json, string propertyName)
{
DateTimeOffset? result = null;
var dtRaw = json.GetPropertyOrNull(propertyName);
if (dtRaw != null)
{
if (dtRaw.Value.ValueKind == JsonValueKind.Number)
{
result = DateTimeOffset.FromUnixTimeSeconds(dtRaw.Value.GetInt64());
}
else
{
result = dtRaw.Value.GetDateTimeOffset();
}
}
return result;
}

public static long? GetHexAsLong(this JsonElement json)
{
// If the address is in json as a number, we can just use it.
Expand Down
2 changes: 2 additions & 0 deletions src/Sentry/Platforms/Cocoa/BindableSentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class NativeOptions
public bool? EnableUIViewControllerTracing { get; set; }
public bool? EnableUserInteractionTracing { get; set; }
public bool? EnableTracing { get; set; }
public bool? SuppressSegfaults { get; set; }

public void ApplyTo(SentryOptions.NativeOptions options)
{
Expand All @@ -47,6 +48,7 @@ public void ApplyTo(SentryOptions.NativeOptions options)
options.EnableUIViewControllerTracing = EnableUIViewControllerTracing ?? options.EnableUIViewControllerTracing;
options.EnableUserInteractionTracing = EnableUserInteractionTracing ?? options.EnableUserInteractionTracing;
options.EnableTracing = EnableTracing ?? options.EnableTracing;
options.SuppressSegfaults = SuppressSegfaults ?? options.SuppressSegfaults;
}
}
}
141 changes: 141 additions & 0 deletions src/Sentry/Platforms/Cocoa/Extensions/CocoaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,24 @@ public static NSDictionary<NSString, NSObject> ToNSDictionary<TValue>(
d.Keys.ToArray());
}

public static NSDictionary<NSString, NSString> ToNSDictionaryStrings(
this IEnumerable<KeyValuePair<string, string>> dict)
{
var d = new Dictionary<NSString, NSString>();
foreach (var item in dict)
{
if (item.Value != null)
{
d.Add((NSString)item.Key, new NSString(item.Value));
}
}

return NSDictionary<NSString, NSString>
.FromObjectsAndKeys(
d.Values.ToArray(),
d.Keys.ToArray());
}

public static NSDictionary<NSString, NSObject>? ToNullableNSDictionary<TValue>(
this ICollection<KeyValuePair<string, TValue>> dict) =>
dict.Count == 0 ? null : dict.ToNSDictionary();
Expand Down Expand Up @@ -224,4 +242,127 @@ public static object ToObject(this NSNumber n)
$"NSNumber \"{n.StringValue}\" has an unknown ObjCType \"{n.ObjCType}\" (Class: \"{n.Class.Name}\")")
};
}

public static void CopyToCocoaSentryEvent(this SentryEvent managed, CocoaSdk.SentryEvent native)
{
// we only support a subset of mutated data to be passed back to the native SDK at this time
native.ServerName = managed.ServerName;
native.Dist = managed.Distribution;
native.Logger = managed.Logger;
native.ReleaseName = managed.Release;
native.Environment = managed.Environment;
native.Platform = managed.Platform!;
native.Transaction = managed.TransactionName!;
native.Message = managed.Message?.ToCocoaSentryMessage();
native.Tags = managed.Tags?.ToNSDictionaryStrings();
native.Extra = managed.Extra?.ToNSDictionary();
native.Breadcrumbs = managed.Breadcrumbs?.Select(x => x.ToCocoaBreadcrumb()).ToArray();
native.User = managed.User?.ToCocoaUser();

if (managed.Level != null)
{
native.Level = managed.Level.Value.ToCocoaSentryLevel();
}

if (managed.Exception != null)
{
native.Error = new NSError(new NSString(managed.Exception.ToString()), IntPtr.Zero);
}
}

public static SentryEvent? ToSentryEvent(this CocoaSdk.SentryEvent sentryEvent)
{
using var stream = sentryEvent.ToJsonStream();
if (stream == null)
return null;

using var json = JsonDocument.Parse(stream);
var exception = sentryEvent.Error == null ? null : new NSErrorException(sentryEvent.Error);
var ev = SentryEvent.FromJson(json.RootElement, exception);
return ev;
}

public static CocoaSdk.SentryMessage ToCocoaSentryMessage(this SentryMessage msg)
{
var native = new CocoaSdk.SentryMessage(msg.Formatted ?? string.Empty);
native.Params = msg.Params?.Select(x => x.ToString()!).ToArray() ?? new string[0];

return native;
}

// not tested or needed yet - leaving for future just in case
// public static CocoaSdk.SentryThread ToCocoaSentryThread(this SentryThread thread)
// {
// var id = NSNumber.FromInt32(thread.Id ?? 0);
// var native = new CocoaSdk.SentryThread(id);
// native.Crashed = thread.Crashed;
// native.Current = thread.Current;
// native.Name = thread.Name;
// native.Stacktrace = thread.Stacktrace?.ToCocoaSentryStackTrace();
// // native.IsMain = not in dotnet
// return native;
// }
//
// public static CocoaSdk.SentryRequest ToCocoaSentryRequest(this SentryRequest request)
// {
// var native = new CocoaSdk.SentryRequest();
// native.Cookies = request.Cookies;
// native.Headers = request.Headers?.ToNSDictionaryStrings();
// native.Method = request.Method;
// native.QueryString = request.QueryString;
// native.Url = request.Url;
//
// // native.BodySize does not exist in dotnet
// return native;
// }
//

// public static CocoaSdk.SentryException ToCocoaSentryException(this SentryException ex)
// {
// var native = new CocoaSdk.SentryException(ex.Value ?? string.Empty, ex.Type ?? string.Empty);
// native.Module = ex.Module;
// native.Mechanism = ex.Mechanism?.ToCocoaSentryMechanism();
// native.Stacktrace = ex.Stacktrace?.ToCocoaSentryStackTrace();
// // not part of native - ex.ThreadId;
// return native;
// }
//
// public static CocoaSdk.SentryStacktrace ToCocoaSentryStackTrace(this SentryStackTrace stackTrace)
// {
// var frames = stackTrace.Frames?.Select(x => x.ToCocoaSentryFrame()).ToArray() ?? new CocoaSdk.SentryFrame[0];
// var native = new CocoaSdk.SentryStacktrace(frames, new NSDictionary<NSString, NSString>());
// // native.Register & native.Snapshot missing in dotnet
// return native;
// }
//
// public static CocoaSdk.SentryFrame ToCocoaSentryFrame(this SentryStackFrame frame)
// {
// var native = new CocoaSdk.SentryFrame();
// native.Module = frame.Module;
// native.Package = frame.Package;
// native.InstructionAddress = frame.InstructionAddress?.ToString();
// native.Function = frame.Function;
// native.Platform = frame.Platform;
// native.ColumnNumber = frame.ColumnNumber;
// native.FileName = frame.FileName;
// native.InApp = frame.InApp;
// native.ImageAddress = frame.ImageAddress?.ToString();
// native.LineNumber = frame.LineNumber;
// native.SymbolAddress = frame.SymbolAddress?.ToString();
//
// // native.StackStart = doesn't exist in dotnet
// return native;
// }
//
// public static CocoaSdk.SentryMechanism ToCocoaSentryMechanism(this Mechanism mechanism)
// {
// var native = new CocoaSdk.SentryMechanism(mechanism.Type);
// native.Synthetic = mechanism.Synthetic;
// native.Handled = mechanism.Handled;
// native.Desc = mechanism.Description;
// native.HelpLink = mechanism.HelpLink;
// native.Data = mechanism.Data?.ToNSDictionary();
// // TODO: Meta does not currently translate in dotnet - native.Meta = null;
// return native;
// }
}
45 changes: 0 additions & 45 deletions src/Sentry/Platforms/Cocoa/Extensions/SentryEventExtensions.cs

This file was deleted.

15 changes: 15 additions & 0 deletions src/Sentry/Platforms/Cocoa/SentryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,21 @@ internal NativeOptions(SentryOptions options)
/// </remarks>
public NSUrlSessionDelegate? UrlSessionDelegate { get; set; } = null;

/// <summary>
/// <para>
/// Whether to suppress capturing SIGSEGV (Segfault) errors in the Native SDK.
/// </para>
/// <para>
/// When managed code results in a NullReferenceException, this also causes a SIGSEGV (Segfault). Duplicate
/// events (one managed and one native) can be prevented by suppressing native Segfaults, which may be
/// convenient.
/// </para>
/// <para>
/// Enabling this may prevent the capture of Segfault originating from native (not managed) code... so it may
/// prevent the capture of genuine native Segfault errors.
/// </para>
/// </summary>
public bool SuppressSegfaults { get; set; } = false;

// ---------- Other ----------

Expand Down
Loading
Loading