From e9515a06ae50c6c677915209c85e9a3e67c47b46 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 7 Apr 2026 15:15:48 +0200 Subject: [PATCH 1/6] build: switch to sentry-cocoa submodule for managed builds Allows building sentry-cocoa with `SENTRY_CRASH_MANAGED_RUNTIME` for eliminating duplicate native exceptions on iOS. See also: - getsentry/sentry-cocoa#6193 - getsentry/sentry-dotnet#5126 --- .github/workflows/update-deps.yml | 2 +- .gitignore | 3 --- .gitmodules | 3 +++ modules/sentry-cocoa | 1 + modules/sentry-cocoa.properties | 2 -- scripts/build-sentry-cocoa.sh | 25 +++++++++++++++++-- src/Sentry.Bindings.Cocoa/ApiDefinitions.cs | 1 - .../Sentry.Bindings.Cocoa.csproj | 19 +++++++++++--- src/Sentry.Bindings.Cocoa/StructsAndEnums.cs | 1 - 9 files changed, 43 insertions(+), 14 deletions(-) create mode 160000 modules/sentry-cocoa delete mode 100644 modules/sentry-cocoa.properties diff --git a/.github/workflows/update-deps.yml b/.github/workflows/update-deps.yml index 131b8ea37e..202b8a885c 100644 --- a/.github/workflows/update-deps.yml +++ b/.github/workflows/update-deps.yml @@ -16,7 +16,7 @@ jobs: matrix: include: - name: Cocoa SDK - path: modules/sentry-cocoa.properties + path: modules/sentry-cocoa - name: Java SDK path: scripts/update-java.ps1 - name: Native SDK diff --git a/.gitignore b/.gitignore index 561954efe0..ac0360faaa 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,6 @@ test/**/*.apk .sentry-native **/EnvironmentVariables.g.cs -# Download cache for Cocoa SDK -modules/sentry-cocoa - # Local Claude Code settings that should not be committed .claude/settings.local.json diff --git a/.gitmodules b/.gitmodules index 71bd96d198..494aae20cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "modules/sentry-native"] path = modules/sentry-native url = https://github.com/getsentry/sentry-native.git +[submodule "modules/sentry-cocoa"] + path = modules/sentry-cocoa + url = https://github.com/getsentry/sentry-cocoa.git diff --git a/modules/sentry-cocoa b/modules/sentry-cocoa new file mode 160000 index 0000000000..05d3ce8332 --- /dev/null +++ b/modules/sentry-cocoa @@ -0,0 +1 @@ +Subproject commit 05d3ce8332097ff0b2347231ac66476fd7d2f4d8 diff --git a/modules/sentry-cocoa.properties b/modules/sentry-cocoa.properties deleted file mode 100644 index da9cf27949..0000000000 --- a/modules/sentry-cocoa.properties +++ /dev/null @@ -1,2 +0,0 @@ -version = 9.9.0 -repo = https://github.com/getsentry/sentry-cocoa diff --git a/scripts/build-sentry-cocoa.sh b/scripts/build-sentry-cocoa.sh index 55dbdbde6e..7ca97228d4 100755 --- a/scripts/build-sentry-cocoa.sh +++ b/scripts/build-sentry-cocoa.sh @@ -4,7 +4,28 @@ set -euo pipefail pushd "$(dirname "$0")" >/dev/null cd ../modules/sentry-cocoa -rm -rf Carthage +mkdir -p Carthage +PID_FILE="$PWD/Carthage/.build.pid" +trap 'if [[ "$(cat "$PID_FILE" 2>/dev/null)" == "$$" ]]; then rm -f "$PID_FILE"; fi' EXIT + +# Serialize concurrent invocations; parallel xcodebuilds race on DerivedData. +while ! (set -C; echo $$ > "$PID_FILE") 2>/dev/null; do + build_pid=$(cat "$PID_FILE" 2>/dev/null || true) + if [[ -n "$build_pid" ]] && ! kill -0 "$build_pid" 2>/dev/null; then + echo "Previous build did not complete (pid $build_pid); cleaning up and retrying" >&2 + rm -f "$PID_FILE" + continue + fi + sleep 2 +done + +current_sha=$(git rev-parse HEAD) +if [[ -f Carthage/.built-from-sha ]] && [[ "$(cat Carthage/.built-from-sha)" == "$current_sha" ]]; then + popd >/dev/null + exit 0 +fi + +rm -rf Carthage/output-*.xcarchive Carthage/Build-* Carthage/Headers Carthage/.built-from-sha # Grabbing the first SDK versions sdks=$(xcodebuild -showsdks) @@ -62,7 +83,7 @@ find Carthage/Build-ios/Sentry.xcframework/ios-arm64 -name '*.h' -exec cp {} Car find Carthage/Build* \( -name Headers -o -name PrivateHeaders -o -name Modules \) -exec rm -rf {} + rm -rf Carthage/output-* -cp .git/HEAD Carthage/.built-from-sha +echo "$current_sha" > Carthage/.built-from-sha echo "" popd >/dev/null diff --git a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs index cef90c1033..e1137149e8 100644 --- a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs +++ b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs @@ -11,7 +11,6 @@ using CoreGraphics; using Foundation; using ObjCRuntime; -using Sentry; using UIKit; namespace Sentry.CocoaSdk; diff --git a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj index 4d7db910ee..83796a70d4 100644 --- a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj +++ b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj @@ -9,18 +9,28 @@ .NET Bindings for the Sentry Cocoa SDK ..\..\modules\sentry-cocoa\ $(SentryCocoaCache)Sentry.framework\ + + $(NoWarn);CS0108 + + + + $([System.IO.File]::ReadAllText("$(MSBuildThisFileDirectory)../../modules/sentry-cocoa.properties")) $([System.Text.RegularExpressions.Regex]::Match($(SentryCocoaProperties), 'version\s*=\s*([^\s]+)').Groups[1].Value) $(SentryCocoaCache)Sentry-$(SentryCocoaVersion).xcframework ../../modules/sentry-cocoa.properties;../../scripts/generate-cocoa-bindings.ps1;$(SentryCocoaFrameworkHeaders)**/*.h - - $(NoWarn);CS0108 $(SentryCocoaCache)Carthage\Build-$(TargetPlatformIdentifier)\Sentry.xcframework ../../scripts/generate-cocoa-bindings.ps1;$(SentryCocoaCache)Carthage/.built-from-sha;$(SentryCocoaCache)Carthage/**/*.h + + $([MSBuild]::NormalizePath($(MSBuildThisFileDirectory), $(SentryCocoaCache).git)) + + .git + + $([System.IO.File]::ReadAllText('$(SentryCocoaGitFile)').Trim().Replace('gitdir: ', '')) @@ -97,7 +107,7 @@ + Inputs="$(SentryCocoaCache)$(SentryCocoaGitDir)\HEAD;..\..\scripts\build-sentry-cocoa.sh" Outputs="..\..\modules\sentry-cocoa\Carthage\.built-from-sha"> @@ -125,7 +135,8 @@ Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> - + + diff --git a/src/Sentry.Bindings.Cocoa/StructsAndEnums.cs b/src/Sentry.Bindings.Cocoa/StructsAndEnums.cs index d8d6b45634..23ee524f72 100644 --- a/src/Sentry.Bindings.Cocoa/StructsAndEnums.cs +++ b/src/Sentry.Bindings.Cocoa/StructsAndEnums.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using Foundation; using ObjCRuntime; -using Sentry; namespace Sentry.CocoaSdk; From 2d05ef4d2b5c8cc450fcbb889628411a670281af Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 13 Apr 2026 14:04:05 +0200 Subject: [PATCH 2/6] Add sentry-cocoa.properties checks --- src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj index 83796a70d4..96bc4b2d0c 100644 --- a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj +++ b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj @@ -8,17 +8,17 @@ true .NET Bindings for the Sentry Cocoa SDK ..\..\modules\sentry-cocoa\ + $(MSBuildThisFileDirectory)..\..\modules\sentry-cocoa.properties $(SentryCocoaCache)Sentry.framework\ $(NoWarn);CS0108 - - $([System.IO.File]::ReadAllText("$(MSBuildThisFileDirectory)../../modules/sentry-cocoa.properties")) - $([System.Text.RegularExpressions.Regex]::Match($(SentryCocoaProperties), 'version\s*=\s*([^\s]+)').Groups[1].Value) + + $([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(SentryCocoaProperties)')), 'version\s*=\s*([^\s]+)').Groups[1].Value) $(SentryCocoaCache)Sentry-$(SentryCocoaVersion).xcframework - ../../modules/sentry-cocoa.properties;../../scripts/generate-cocoa-bindings.ps1;$(SentryCocoaFrameworkHeaders)**/*.h + $(SentryCocoaProperties);../../scripts/generate-cocoa-bindings.ps1;$(SentryCocoaFrameworkHeaders)**/*.h @@ -68,7 +68,7 @@ + Condition="$([MSBuild]::IsOSPlatform('OSX')) And Exists('$(SentryCocoaProperties)') And !Exists('$(SentryCocoaCache).git') And !Exists('$(SentryCocoaFramework)')"> From bd1d09b05137502ea60369867b5cefdcb2abcbe1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 13 Apr 2026 17:17:42 +0200 Subject: [PATCH 3/6] Close TOCTOU race in build-sentry-cocoa.sh stale lock reap Switch from a noclobber PID file to a directory lock with a pid file inside. The atomic mkdir gates acquisition; stale reap renames the dir to a unique name before rm -rf so two concurrent reapers can't both proceed to own the lock. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/build-sentry-cocoa.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/build-sentry-cocoa.sh b/scripts/build-sentry-cocoa.sh index 7ca97228d4..71c97b4db6 100755 --- a/scripts/build-sentry-cocoa.sh +++ b/scripts/build-sentry-cocoa.sh @@ -5,19 +5,23 @@ pushd "$(dirname "$0")" >/dev/null cd ../modules/sentry-cocoa mkdir -p Carthage -PID_FILE="$PWD/Carthage/.build.pid" -trap 'if [[ "$(cat "$PID_FILE" 2>/dev/null)" == "$$" ]]; then rm -f "$PID_FILE"; fi' EXIT +LOCK_DIR="$PWD/Carthage/.build.lock" +trap 'if [[ "$(cat "$LOCK_DIR/pid" 2>/dev/null)" == "$$" ]]; then rm -rf "$LOCK_DIR"; fi' EXIT # Serialize concurrent invocations; parallel xcodebuilds race on DerivedData. -while ! (set -C; echo $$ > "$PID_FILE") 2>/dev/null; do - build_pid=$(cat "$PID_FILE" 2>/dev/null || true) +while ! mkdir "$LOCK_DIR" 2>/dev/null; do + build_pid=$(cat "$LOCK_DIR/pid" 2>/dev/null || true) if [[ -n "$build_pid" ]] && ! kill -0 "$build_pid" 2>/dev/null; then echo "Previous build did not complete (pid $build_pid); cleaning up and retrying" >&2 - rm -f "$PID_FILE" + # Atomically claim the stale dir via rename + if mv "$LOCK_DIR" "$LOCK_DIR.stale.$$" 2>/dev/null; then + rm -rf "$LOCK_DIR.stale.$$" + fi continue fi sleep 2 done +echo $$ > "$LOCK_DIR/pid" current_sha=$(git rev-parse HEAD) if [[ -f Carthage/.built-from-sha ]] && [[ "$(cat Carthage/.built-from-sha)" == "$current_sha" ]]; then From acf4165756fd1bc08a53b7c2da44eb2f32a29eba Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 13 Apr 2026 17:40:55 +0200 Subject: [PATCH 4/6] switch back to pid file with atomic ln --- scripts/build-sentry-cocoa.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/build-sentry-cocoa.sh b/scripts/build-sentry-cocoa.sh index 71c97b4db6..6e18143f1a 100755 --- a/scripts/build-sentry-cocoa.sh +++ b/scripts/build-sentry-cocoa.sh @@ -5,23 +5,24 @@ pushd "$(dirname "$0")" >/dev/null cd ../modules/sentry-cocoa mkdir -p Carthage -LOCK_DIR="$PWD/Carthage/.build.lock" -trap 'if [[ "$(cat "$LOCK_DIR/pid" 2>/dev/null)" == "$$" ]]; then rm -rf "$LOCK_DIR"; fi' EXIT +PID_FILE="$PWD/Carthage/.build.pid" +trap 'if [[ "$(cat "$PID_FILE" 2>/dev/null)" == "$$" ]]; then rm -f "$PID_FILE"; fi' EXIT # Serialize concurrent invocations; parallel xcodebuilds race on DerivedData. -while ! mkdir "$LOCK_DIR" 2>/dev/null; do - build_pid=$(cat "$LOCK_DIR/pid" 2>/dev/null || true) +TMP_FILE=$(mktemp "$PID_FILE.tmp.XXXXXX") +echo $$ > "$TMP_FILE" +while ! ln "$TMP_FILE" "$PID_FILE" 2>/dev/null; do + build_pid=$(cat "$PID_FILE" 2>/dev/null || true) if [[ -n "$build_pid" ]] && ! kill -0 "$build_pid" 2>/dev/null; then echo "Previous build did not complete (pid $build_pid); cleaning up and retrying" >&2 - # Atomically claim the stale dir via rename - if mv "$LOCK_DIR" "$LOCK_DIR.stale.$$" 2>/dev/null; then - rm -rf "$LOCK_DIR.stale.$$" + if mv "$PID_FILE" "$PID_FILE.stale.$$" 2>/dev/null; then + rm -f "$PID_FILE.stale.$$" fi continue fi sleep 2 done -echo $$ > "$LOCK_DIR/pid" +rm -f "$TMP_FILE" current_sha=$(git rev-parse HEAD) if [[ -f Carthage/.built-from-sha ]] && [[ "$(cat Carthage/.built-from-sha)" == "$current_sha" ]]; then From 580f42bd457f8ab01a5359e72fb55b6ee34df83f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 14 Apr 2026 09:15:22 +0200 Subject: [PATCH 5/6] Bump modules/sentry-cocoa to match rebased baseline at 9.9.0 --- modules/sentry-cocoa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sentry-cocoa b/modules/sentry-cocoa index 05d3ce8332..d459ff99b1 160000 --- a/modules/sentry-cocoa +++ b/modules/sentry-cocoa @@ -1 +1 @@ -Subproject commit 05d3ce8332097ff0b2347231ac66476fd7d2f4d8 +Subproject commit d459ff99b1912c9603c9e607e030b4b98e2e199a From a8ec9cefa82c950864c18bf4cbd251f53a6acb9b Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 14 Apr 2026 19:26:35 +0200 Subject: [PATCH 6/6] Bump back to 9.10.0 --- modules/sentry-cocoa | 2 +- src/Sentry.Bindings.Cocoa/ApiDefinitions.cs | 33 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/modules/sentry-cocoa b/modules/sentry-cocoa index d459ff99b1..3a22ecd00a 160000 --- a/modules/sentry-cocoa +++ b/modules/sentry-cocoa @@ -1 +1 @@ -Subproject commit d459ff99b1912c9603c9e607e030b4b98e2e199a +Subproject commit 3a22ecd00ad1398747bfd587e44df82716908dd3 diff --git a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs index e1137149e8..9a56e35d80 100644 --- a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs +++ b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs @@ -158,6 +158,10 @@ interface SentryBaggage [NullAllowed, Export("replayId", ArgumentSemantic.Strong)] string ReplayId { get; set; } + // @property (readonly, nonatomic) NSString * _Nullable orgId; + [NullAllowed, Export("orgId")] + string OrgId { get; } + // -(instancetype _Nonnull)initWithTraceId:(SentryId * _Nonnull)traceId publicKey:(NSString * _Nonnull)publicKey releaseName:(NSString * _Nullable)releaseName environment:(NSString * _Nullable)environment transaction:(NSString * _Nullable)transaction sampleRate:(NSString * _Nullable)sampleRate sampled:(NSString * _Nullable)sampled replayId:(NSString * _Nullable)replayId; [Export("initWithTraceId:publicKey:releaseName:environment:transaction:sampleRate:sampled:replayId:")] NativeHandle Constructor(SentryId traceId, string publicKey, [NullAllowed] string releaseName, [NullAllowed] string environment, [NullAllowed] string transaction, [NullAllowed] string sampleRate, [NullAllowed] string sampled, [NullAllowed] string replayId); @@ -166,6 +170,10 @@ interface SentryBaggage [Export("initWithTraceId:publicKey:releaseName:environment:transaction:sampleRate:sampleRand:sampled:replayId:")] NativeHandle Constructor(SentryId traceId, string publicKey, [NullAllowed] string releaseName, [NullAllowed] string environment, [NullAllowed] string transaction, [NullAllowed] string sampleRate, [NullAllowed] string sampleRand, [NullAllowed] string sampled, [NullAllowed] string replayId); + // -(instancetype _Nonnull)initWithTraceId:(SentryId * _Nonnull)traceId publicKey:(NSString * _Nonnull)publicKey releaseName:(NSString * _Nullable)releaseName environment:(NSString * _Nullable)environment transaction:(NSString * _Nullable)transaction sampleRate:(NSString * _Nullable)sampleRate sampleRand:(NSString * _Nullable)sampleRand sampled:(NSString * _Nullable)sampled replayId:(NSString * _Nullable)replayId orgId:(NSString * _Nullable)orgId; + [Export("initWithTraceId:publicKey:releaseName:environment:transaction:sampleRate:sampleRand:sampled:replayId:orgId:")] + NativeHandle Constructor(SentryId traceId, string publicKey, [NullAllowed] string releaseName, [NullAllowed] string environment, [NullAllowed] string transaction, [NullAllowed] string sampleRate, [NullAllowed] string sampleRand, [NullAllowed] string sampled, [NullAllowed] string replayId, [NullAllowed] string orgId); + // -(NSString * _Nonnull)toHTTPHeaderWithOriginalBaggage:(NSDictionary * _Nullable)originalBaggage; [Export("toHTTPHeaderWithOriginalBaggage:")] string ToHTTPHeaderWithOriginalBaggage([NullAllowed] NSDictionary originalBaggage); @@ -1368,6 +1376,10 @@ interface SentryTraceContext : SentrySerializable [NullAllowed, Export("replayId")] string ReplayId { get; } + // @property (readonly, nonatomic) NSString * _Nullable orgId; + [NullAllowed, Export("orgId")] + string OrgId { get; } + // -(SentryBaggage * _Nonnull)toBaggage; [Export("toBaggage")] SentryBaggage ToBaggage(); @@ -1656,6 +1668,11 @@ interface PrivateSentrySDKOnly [Static] [Export("setLogOutput:")] void SetLogOutput(Action output); + + // +(void)ignoreNextSignal:(int)signum; + [Static] + [Export("ignoreNextSignal:")] + void IgnoreNextSignal(int signum); } // @interface SentryOptions : NSObject @@ -1987,6 +2004,18 @@ interface SentryOptions [Export("spotlightUrl")] string SpotlightUrl { get; set; } + // @property (nonatomic) BOOL strictTraceContinuation; + [Export("strictTraceContinuation")] + bool StrictTraceContinuation { get; set; } + + // @property (copy, nonatomic) NSString * _Nullable orgId; + [NullAllowed, Export("orgId")] + string OrgId { get; set; } + + // @property (readonly, copy, nonatomic) NSString * _Nullable effectiveOrgId; + [NullAllowed, Export("effectiveOrgId")] + string EffectiveOrgId { get; } + // @property (nonatomic, strong) SentryExperimentalOptions * _Nonnull experimental; [Export("experimental", ArgumentSemantic.Strong)] SentryExperimentalOptions Experimental { get; set; } @@ -2129,6 +2158,10 @@ interface SentryDsn // -(NSURL * _Nonnull)getEnvelopeEndpoint __attribute__((warn_unused_result(""))); [Export("getEnvelopeEndpoint")] NSUrl EnvelopeEndpoint { get; } + + // @property (readonly, copy, nonatomic) NSString * _Nullable orgId; + [NullAllowed, Export("orgId")] + string OrgId { get; } } // @interface SentryExperimentalOptions : NSObject