react-native-stallion 2.3.0-alpha.5 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@
7
7
 
8
8
  static char g_marker_path[512];
9
9
  static char g_mount_marker_path[512];
10
+ static struct sigaction g_previous_handlers[32]; // Store previous handlers for chaining
10
11
 
11
12
  // Async-signal-safe function to check if mount marker exists
12
13
  static int is_mounted() {
@@ -36,11 +37,28 @@ static void write_crash_marker_json(int signal, int mounted) {
36
37
  }
37
38
  }
38
39
 
39
- static void stallion_signal_handler(int sig) {
40
+ static void stallion_signal_handler(int sig, siginfo_t *info, void *context) {
40
41
  // Read mount state at crash time (async-signal-safe)
41
42
  int mounted = is_mounted();
42
43
  // Write JSON marker with crash info and autoRollback flag
43
44
  write_crash_marker_json(sig, mounted);
45
+
46
+ // Chain to previous handler if it exists and is valid (bubble up)
47
+ if (sig >= 0 && sig < 32) {
48
+ struct sigaction *prev = &g_previous_handlers[sig];
49
+ if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN && prev->sa_handler != NULL) {
50
+ // Prevent infinite loop - don't call ourselves
51
+ if (prev->sa_sigaction != stallion_signal_handler) {
52
+ if (prev->sa_flags & SA_SIGINFO) {
53
+ prev->sa_sigaction(sig, info, context);
54
+ } else if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN) {
55
+ prev->sa_handler(sig);
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ // Restore default and raise to proceed with crash
44
62
  signal(sig, SIG_DFL);
45
63
  raise(sig);
46
64
  }
@@ -54,9 +72,20 @@ Java_com_stallion_utils_StallionExceptionHandler_initNativeSignalHandler(
54
72
  snprintf(g_mount_marker_path, sizeof(g_mount_marker_path), "%s/%s", path, "stallion_mount.marker");
55
73
  env->ReleaseStringUTFChars(filesDir, path);
56
74
 
57
- signal(SIGABRT, stallion_signal_handler);
58
- signal(SIGSEGV, stallion_signal_handler);
59
- signal(SIGILL, stallion_signal_handler);
60
- signal(SIGBUS, stallion_signal_handler);
61
- signal(SIGFPE, stallion_signal_handler);
75
+ // Use sigaction instead of signal for better handler chaining
76
+ struct sigaction action;
77
+ sigemptyset(&action.sa_mask);
78
+ action.sa_flags = SA_SIGINFO;
79
+ action.sa_sigaction = stallion_signal_handler;
80
+
81
+ int signals[] = {SIGABRT, SIGSEGV, SIGILL, SIGBUS, SIGFPE};
82
+ int signalCount = sizeof(signals) / sizeof(signals[0]);
83
+
84
+ for (int i = 0; i < signalCount; i++) {
85
+ int sig = signals[i];
86
+ // Store previous handler before installing ours (for chaining)
87
+ sigaction(sig, NULL, &g_previous_handlers[sig]);
88
+ // Now install our handler
89
+ sigaction(sig, &action, NULL);
90
+ }
62
91
  }
@@ -9,51 +9,61 @@ import com.stallion.storage.StallionStateManager;
9
9
 
10
10
  import org.json.JSONObject;
11
11
 
12
+ import java.util.concurrent.atomic.AtomicBoolean;
13
+
12
14
  public class StallionExceptionHandler {
13
15
 
14
16
  private static Thread.UncaughtExceptionHandler _androidUncaughtExceptionHandler;
15
17
  private static Thread _exceptionThread;
16
18
  private static Throwable _exceptionThrowable;
17
- private static boolean isErrorBoundaryInitialized = false;
18
- private static boolean isNativeSignalsInitialized = false;
19
- private static boolean hasProcessedNativeCrashMarker = false;
19
+ private static final AtomicBoolean isErrorBoundaryInitialized = new AtomicBoolean(false);
20
+ private static final AtomicBoolean isNativeSignalsInitialized = new AtomicBoolean(false);
21
+ private static final AtomicBoolean hasProcessedNativeCrashMarker = new AtomicBoolean(false);
22
+ private static final AtomicBoolean isRollbackPerformed = new AtomicBoolean(false);
20
23
 
21
24
  public static void initErrorBoundary() {
22
- if (isErrorBoundaryInitialized) {
25
+ // Use compareAndSet to atomically check and set initialization flag
26
+ if (!isErrorBoundaryInitialized.compareAndSet(false, true)) {
23
27
  return; // Prevent multiple initializations
24
28
  }
25
- isErrorBoundaryInitialized = true;
29
+
30
+ // Reset rollback flag when initializing exception handler
31
+ isRollbackPerformed.set(false);
26
32
 
27
33
  _androidUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
28
34
  Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
29
35
  _exceptionThread = thread;
30
36
  _exceptionThrowable = throwable;
31
37
 
32
- // Safely trim the stack trace string
33
- String stackTraceString = Log.getStackTraceString(throwable);
34
- stackTraceString = stackTraceString.length() > 900
35
- ? stackTraceString.substring(0, 900) + "..."
36
- : stackTraceString;
38
+ try {
39
+ // Safely trim the stack trace string
40
+ String stackTraceString = Log.getStackTraceString(throwable);
41
+ stackTraceString = stackTraceString.length() > 900
42
+ ? stackTraceString.substring(0, 900) + "..."
43
+ : stackTraceString;
37
44
 
38
- StallionStateManager stateManager = StallionStateManager.getInstance();
39
- StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState();
45
+ StallionStateManager stateManager = StallionStateManager.getInstance();
46
+ StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState();
40
47
 
41
- if (switchState == StallionMetaConstants.SwitchState.PROD) {
42
- handleProdState(stackTraceString, stateManager);
43
- } else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
44
- handleStageState(stackTraceString, stateManager);
45
- } else {
48
+ if (switchState == StallionMetaConstants.SwitchState.PROD) {
49
+ handleProdState(stackTraceString, stateManager);
50
+ } else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
51
+ handleStageState(stackTraceString, stateManager);
52
+ } else {
53
+ continueExceptionFlow();
54
+ }
55
+ } catch (Exception e) {
56
+ // If anything goes wrong in our handler, ensure we still chain to previous handler
46
57
  continueExceptionFlow();
47
58
  }
48
59
  });
49
60
 
50
61
  // Initialize native signal handler once and process any prior crash marker
51
62
  try {
52
- if (!isNativeSignalsInitialized) {
63
+ if (isNativeSignalsInitialized.compareAndSet(false, true)) {
53
64
  System.loadLibrary("stallion-crash");
54
65
  String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
55
66
  initNativeSignalHandler(filesDir);
56
- isNativeSignalsInitialized = true;
57
67
  }
58
68
  processNativeCrashMarkerIfPresent();
59
69
  } catch (Throwable ignored) {}
@@ -78,14 +88,30 @@ public class StallionExceptionHandler {
78
88
  boolean isAutoRollback = !stateManager.getIsMounted();
79
89
  String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot();
80
90
 
81
- // Emit exception event
82
- emitException(stackTraceString, currentHash, isAutoRollback, true);
91
+ // Only prevent multiple executions for auto rollback cases
92
+ // Launch crashes (when mounted) can continue to be registered
93
+ if (isAutoRollback) {
94
+ // Use compareAndSet to atomically check and set the flag
95
+ if (!isRollbackPerformed.compareAndSet(false, true)) {
96
+ // Flag was already true, skip duplicate rollback
97
+ continueExceptionFlow();
98
+ return;
99
+ }
100
+ }
101
+
102
+ // Emit exception event (wrap in try-catch to ensure chaining happens)
103
+ try {
104
+ emitException(stackTraceString, currentHash, isAutoRollback, true);
105
+ } catch (Exception ignored) { }
83
106
 
84
107
  // Perform rollback if auto-rollback is enabled
85
108
  if (isAutoRollback) {
86
- StallionSlotManager.rollbackProd(true, stackTraceString);
109
+ try {
110
+ StallionSlotManager.rollbackProd(true, stackTraceString);
111
+ } catch (Exception ignored) { }
87
112
  }
88
113
 
114
+ // Always chain to previous handler, even if rollback or emit failed
89
115
  continueExceptionFlow();
90
116
  }
91
117
 
@@ -93,13 +119,29 @@ public class StallionExceptionHandler {
93
119
  boolean isAutoRollback = !stateManager.getIsMounted();
94
120
  String currentStageHash = stateManager.stallionMeta.getStageNewHash();
95
121
 
96
- // Emit exception event
97
- emitException(stackTraceString, currentStageHash, isAutoRollback, false);
122
+ // Only prevent multiple executions for auto rollback cases
123
+ // Launch crashes (when mounted) can continue to be registered
124
+ if (isAutoRollback) {
125
+ // Use compareAndSet to atomically check and set the flag
126
+ if (!isRollbackPerformed.compareAndSet(false, true)) {
127
+ // Flag was already true, skip duplicate rollback
128
+ continueExceptionFlow();
129
+ return;
130
+ }
131
+ }
132
+
133
+ // Emit exception event (wrap in try-catch to ensure chaining happens)
134
+ try {
135
+ emitException(stackTraceString, currentStageHash, isAutoRollback, false);
136
+ } catch (Exception ignored) { }
98
137
 
99
138
  if(isAutoRollback) {
100
- StallionSlotManager.rollbackStage();
139
+ try {
140
+ StallionSlotManager.rollbackStage();
141
+ } catch (Exception ignored) { }
101
142
  }
102
143
 
144
+ // Always chain to previous handler, even if rollback or emit failed
103
145
  continueExceptionFlow();
104
146
  }
105
147
 
@@ -111,7 +153,7 @@ public class StallionExceptionHandler {
111
153
 
112
154
  private static void processNativeCrashMarkerIfPresent() {
113
155
  try {
114
- if (hasProcessedNativeCrashMarker) { return; }
156
+ if (hasProcessedNativeCrashMarker.get()) { return; }
115
157
  String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
116
158
  java.io.File marker = new java.io.File(filesDir + "/stallion_crash.marker");
117
159
  if (marker.exists()) {
@@ -149,22 +191,36 @@ public class StallionExceptionHandler {
149
191
  if (switchState == StallionMetaConstants.SwitchState.PROD) {
150
192
  String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot();
151
193
  // Use isAutoRollback from previous crash, not current session state
152
- emitException(stackTraceString, currentHash, isAutoRollback, true);
194
+ try {
195
+ emitException(stackTraceString, currentHash, isAutoRollback, true);
196
+ } catch (Exception ignored) { }
153
197
  if (isAutoRollback) {
154
- StallionSlotManager.rollbackProd(true, stackTraceString);
198
+ // Only prevent multiple executions for auto rollback cases
199
+ if (isRollbackPerformed.compareAndSet(false, true)) {
200
+ try {
201
+ StallionSlotManager.rollbackProd(true, stackTraceString);
202
+ } catch (Exception ignored) { }
203
+ }
155
204
  }
156
205
  } else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
157
206
  String currentStageHash = stateManager.stallionMeta.getStageNewHash();
158
207
  // Use isAutoRollback from previous crash, not current session state
159
- emitException(stackTraceString, currentStageHash, isAutoRollback, false);
208
+ try {
209
+ emitException(stackTraceString, currentStageHash, isAutoRollback, false);
210
+ } catch (Exception ignored) { }
160
211
  if (isAutoRollback) {
161
- StallionSlotManager.rollbackStage();
212
+ // Only prevent multiple executions for auto rollback cases
213
+ if (isRollbackPerformed.compareAndSet(false, true)) {
214
+ try {
215
+ StallionSlotManager.rollbackStage();
216
+ } catch (Exception ignored) { }
217
+ }
162
218
  }
163
219
  }
164
220
 
165
221
  // delete marker
166
222
  StallionFileManager.deleteFileOrFolderSilently(marker);
167
- hasProcessedNativeCrashMarker = true;
223
+ hasProcessedNativeCrashMarker.set(true);
168
224
  }
169
225
  } catch (Exception ignored) {}
170
226
  }
@@ -12,57 +12,55 @@
12
12
  #import "StallionMeta.h"
13
13
  #import "StallionMetaConstants.h"
14
14
  #import "StallionObjConstants.h"
15
+ #import "StallionFileManager.h"
15
16
  #import <signal.h>
16
- #import <execinfo.h>
17
+ #import <unistd.h>
18
+ #import <fcntl.h>
17
19
  #import <React/RCTLog.h>
18
20
  #import <React/RCTUtils.h>
19
- #include <exception>
20
- #include <cxxabi.h>
21
- #include <string>
21
+ #include <atomic>
22
22
 
23
23
  // Forward declarations
24
24
  void handleException(NSException *exception);
25
25
  void handleSignal(int signal, siginfo_t *info, void *context);
26
26
  static void performStallionRollback(NSString *errorString);
27
27
  static void setupSignalHandlers(void);
28
- void handleCppTerminate(void);
28
+ static void processNativeCrashMarkerIfPresent(void);
29
+
30
+ // Async-signal-safe crash marker storage
31
+ static char g_marker_path[512];
32
+ static char g_mount_marker_path[512];
29
33
 
30
34
  @implementation StallionExceptionHandler
31
35
 
32
36
  NSUncaughtExceptionHandler *_defaultExceptionHandler;
33
- std::terminate_handler _defaultTerminateHandler;
34
- BOOL exceptionAlertDismissed = FALSE;
35
- static BOOL rollbackPerformed = FALSE;
36
- static BOOL isInitialized = FALSE;
37
+ static std::atomic<bool> exceptionAlertDismissed(false);
38
+ static std::atomic<bool> exceptionAlertShowing(false);
39
+ static std::atomic<bool> rollbackPerformed(false);
40
+ static std::atomic<bool> hasProcessedNativeCrashMarker(false);
37
41
  static struct sigaction _previousHandlers[32]; // Store previous handlers for chaining
38
42
 
39
43
  + (void)initExceptionHandler {
40
- // Prevent multiple initializations
41
- if (isInitialized) {
42
- return;
43
- }
44
- isInitialized = TRUE;
45
-
46
- // Reset rollback flag when initializing exception handler
47
- [self resetRollbackFlag];
48
-
49
- // Store and set Objective-C exception handler
50
- if (!_defaultExceptionHandler) {
51
- _defaultExceptionHandler = NSGetUncaughtExceptionHandler();
52
- }
53
- NSSetUncaughtExceptionHandler(&handleException);
54
-
55
- // Store and set C++ terminate handler
56
- if (!_defaultTerminateHandler) {
57
- _defaultTerminateHandler = std::get_terminate();
58
- }
59
- std::set_terminate(handleCppTerminate);
60
-
61
- // Setup signal handlers using sigaction with chaining
62
- setupSignalHandlers();
63
-
64
- // Initialize JavaScript exception handler
65
- [self initJavaScriptExceptionHandler];
44
+ static dispatch_once_t onceToken;
45
+ dispatch_once(&onceToken, ^{
46
+ // Reset rollback flag when initializing exception handler
47
+ [self resetRollbackFlag];
48
+
49
+ // Store and set Objective-C exception handler
50
+ if (!_defaultExceptionHandler) {
51
+ _defaultExceptionHandler = NSGetUncaughtExceptionHandler();
52
+ }
53
+ NSSetUncaughtExceptionHandler(&handleException);
54
+
55
+ // Setup signal handlers using sigaction with chaining
56
+ setupSignalHandlers();
57
+
58
+ // Initialize JavaScript exception handler
59
+ [self initJavaScriptExceptionHandler];
60
+
61
+ // Process any crash marker from previous session
62
+ processNativeCrashMarkerIfPresent();
63
+ });
66
64
  }
67
65
 
68
66
  + (void)initJavaScriptExceptionHandler {
@@ -77,7 +75,7 @@ static struct sigaction _previousHandlers[32]; // Store previous handlers for ch
77
75
  }
78
76
 
79
77
  + (void)resetRollbackFlag {
80
- rollbackPerformed = FALSE;
78
+ rollbackPerformed.store(false);
81
79
  }
82
80
 
83
81
  @end
@@ -93,14 +91,13 @@ static void performStallionRollback(NSString *errorString) {
93
91
 
94
92
  // Only prevent multiple executions for auto rollback cases
95
93
  // Launch crashes (when mounted) can continue to be registered
96
- if (rollbackPerformed && isAutoRollback) {
97
- NSLog(@"Auto rollback already performed, skipping duplicate rollback attempt");
98
- return;
99
- }
100
-
101
- // Set rollback flag only for auto rollback cases
102
94
  if (isAutoRollback) {
103
- rollbackPerformed = TRUE;
95
+ // Use compare-and-swap to atomically check and set the flag
96
+ bool expected = false;
97
+ if (!rollbackPerformed.compare_exchange_strong(expected, true)) {
98
+ // Flag was already true, skip duplicate rollback
99
+ return;
100
+ }
104
101
  }
105
102
 
106
103
  if (errorString.length > 900) {
@@ -121,19 +118,24 @@ static void performStallionRollback(NSString *errorString) {
121
118
  }
122
119
 
123
120
  } else if (meta.switchState == SwitchStateStage) {
121
+ NSString *currentStageHash = meta.stageNewHash ?: @"";
124
122
 
125
- if(isAutoRollback) {
126
- [StallionSlotManager rollbackStage];
127
- }
128
-
123
+ // Emit exception event before rollback (consistent with PROD and Android)
129
124
  [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event
130
125
  eventPayload:@{
131
126
  @"meta": errorString,
132
- StallionObjConstants.release_hash_key: meta.stageNewHash,
127
+ StallionObjConstants.release_hash_key: currentStageHash,
133
128
  StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
134
129
  }];
130
+
131
+ if(isAutoRollback) {
132
+ [StallionSlotManager rollbackStage];
133
+ }
135
134
 
136
- if(!exceptionAlertDismissed) {
135
+ // Check if alert is already showing (atomic check to prevent duplicates)
136
+ bool expectedShowing = false;
137
+ if (exceptionAlertShowing.compare_exchange_strong(expectedShowing, true)) {
138
+ // We successfully claimed the right to show the alert
137
139
  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Stallion Exception Handler"
138
140
  message:[NSString stringWithFormat:@"%@\n%@",
139
141
  @"A crash occurred in the app. Build was rolled back. Check crash report below. Continue crash to invoke other exception handlers. \n \n",
@@ -143,7 +145,8 @@ static void performStallionRollback(NSString *errorString) {
143
145
  [alert addAction:[UIAlertAction actionWithTitle:@"Continue Crash"
144
146
  style:UIAlertActionStyleDefault
145
147
  handler:^(UIAlertAction *action) {
146
- exceptionAlertDismissed = TRUE;
148
+ // Set flag to true only when button is pressed
149
+ exceptionAlertDismissed.store(true);
147
150
  }]];
148
151
 
149
152
  UIApplication *app = [UIApplication sharedApplication];
@@ -153,7 +156,8 @@ static void performStallionRollback(NSString *errorString) {
153
156
  [rootViewController presentViewController:alert animated:YES completion:nil];
154
157
  });
155
158
 
156
- while (exceptionAlertDismissed == FALSE) {
159
+ // Wait for user to press the button (exceptionAlertDismissed becomes true)
160
+ while (!exceptionAlertDismissed.load()) {
157
161
  [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
158
162
  }
159
163
  }
@@ -162,10 +166,47 @@ static void performStallionRollback(NSString *errorString) {
162
166
 
163
167
  #pragma mark - Signal Handler Setup
164
168
 
169
+ // Async-signal-safe function to check if mount marker exists
170
+ static int is_mounted_safe(void) {
171
+ int fd = open(g_mount_marker_path, O_RDONLY);
172
+ if (fd >= 0) {
173
+ close(fd);
174
+ return 1; // Mounted
175
+ }
176
+ return 0; // Not mounted
177
+ }
178
+
179
+ // Async-signal-safe JSON writing (minimal JSON for crash marker)
180
+ static void write_crash_marker_json_safe(int signal, int mounted) {
181
+ int fd = open(g_marker_path, O_CREAT | O_WRONLY | O_TRUNC, 0600);
182
+ if (fd >= 0) {
183
+ // Write JSON: {"signal":X,"isAutoRollback":true/false,"crashLog":"signal=X\n"}
184
+ // isAutoRollback = !mounted (auto rollback if not mounted)
185
+ int autoRollback = !mounted;
186
+ char json[512];
187
+ int len = snprintf(json, sizeof(json),
188
+ "{\"signal\":%d,\"isAutoRollback\":%s,\"crashLog\":\"signal=%d\\n\"}",
189
+ signal, autoRollback ? "true" : "false", signal);
190
+ if (len > 0 && len < (int)sizeof(json)) {
191
+ (void)write(fd, json, len);
192
+ }
193
+ close(fd);
194
+ }
195
+ }
196
+
165
197
  static void setupSignalHandlers(void) {
198
+ // Initialize marker paths from StallionStateManager
199
+ StallionStateManager *stateManager = [StallionStateManager sharedInstance];
200
+ NSString *filesDir = stateManager.stallionConfig.filesDirectory;
201
+ if (filesDir) {
202
+ const char *path = [filesDir UTF8String];
203
+ snprintf(g_marker_path, sizeof(g_marker_path), "%s/%s", path, "stallion_crash.marker");
204
+ snprintf(g_mount_marker_path, sizeof(g_mount_marker_path), "%s/%s", path, "stallion_mount.marker");
205
+ }
206
+
166
207
  struct sigaction action;
167
208
  sigemptyset(&action.sa_mask);
168
- action.sa_flags = SA_SIGINFO | SA_ONSTACK;
209
+ action.sa_flags = SA_SIGINFO;
169
210
  action.sa_sigaction = handleSignal;
170
211
 
171
212
  // List of signals to catch - comprehensive coverage
@@ -206,28 +247,15 @@ void handleException(NSException *exception) {
206
247
  }
207
248
 
208
249
  void handleSignal(int signalVal, siginfo_t *info, void *context) {
209
- void *callstack[128];
210
- int frames = backtrace(callstack, 128);
211
- char **symbols = backtrace_symbols(callstack, frames);
212
250
 
213
- NSMutableString *stackTrace = [NSMutableString stringWithFormat:@"Signal %d was raised.\n", signalVal];
214
-
215
- // Add signal info if available
216
- if (info) {
217
- [stackTrace appendFormat:@"Signal Code: %d\n", info->si_code];
218
- if (info->si_addr) {
219
- [stackTrace appendFormat:@"Fault Address: %p\n", info->si_addr];
220
- }
251
+ if (!rollbackPerformed.load()) {
252
+ // Async-signal-safe operations only
253
+ // Read mount state at crash time (async-signal-safe)
254
+ int mounted = is_mounted_safe();
255
+ // Write JSON marker with crash info and autoRollback flag
256
+ write_crash_marker_json_safe(signalVal, mounted);
221
257
  }
222
258
 
223
- [stackTrace appendString:@"Stack trace:\n"];
224
- for (int i = 0; i < frames; ++i) {
225
- [stackTrace appendFormat:@"%s\n", symbols[i]];
226
- }
227
- free(symbols);
228
-
229
- performStallionRollback(stackTrace);
230
-
231
259
  // Chain to previous handler if it exists and is valid (bubble up)
232
260
  if (signalVal >= 0 && signalVal < 32) {
233
261
  struct sigaction *prev = &_previousHandlers[signalVal];
@@ -248,46 +276,104 @@ void handleSignal(int signalVal, siginfo_t *info, void *context) {
248
276
  raise(signalVal);
249
277
  }
250
278
 
251
- void handleCppTerminate(void) {
252
- std::exception_ptr ex = std::current_exception();
253
- NSString *errorString = @"C++ terminate() called";
254
-
255
- if (ex) {
256
- try {
257
- std::rethrow_exception(ex);
258
- } catch (const std::exception &e) {
259
- const char *name = abi::__cxa_demangle(typeid(e).name(), 0, 0, 0);
260
- errorString = [NSString stringWithFormat:@"C++ Exception: %s - %s",
261
- name ? name : typeid(e).name(), e.what()];
262
- if (name) free((void*)name);
263
- } catch (const std::string &s) {
264
- errorString = [NSString stringWithFormat:@"C++ Exception (string): %s", s.c_str()];
265
- } catch (const char *s) {
266
- errorString = [NSString stringWithFormat:@"C++ Exception (char*): %s", s];
267
- } catch (...) {
268
- errorString = @"C++ Exception: Unknown type";
279
+ #pragma mark - Crash Marker Processing
280
+
281
+ static void processNativeCrashMarkerIfPresent(void) {
282
+ @try {
283
+ if (hasProcessedNativeCrashMarker.load()) {
284
+ return;
269
285
  }
270
- }
271
-
272
- // Get stack trace
273
- void *callstack[128];
274
- int frames = backtrace(callstack, 128);
275
- char **symbols = backtrace_symbols(callstack, frames);
276
-
277
- NSMutableString *fullError = [NSMutableString stringWithString:errorString];
278
- [fullError appendString:@"\nStack trace:\n"];
279
- for (int i = 0; i < frames; ++i) {
280
- [fullError appendFormat:@"%s\n", symbols[i]];
281
- }
282
- free(symbols);
283
-
284
- performStallionRollback(fullError);
285
-
286
- // Chain to default terminate handler
287
- if (_defaultTerminateHandler) {
288
- _defaultTerminateHandler();
289
- } else {
290
- abort();
291
- }
286
+
287
+ StallionStateManager *stateManager = [StallionStateManager sharedInstance];
288
+ NSString *filesDir = stateManager.stallionConfig.filesDirectory;
289
+ NSString *markerPath = [NSString stringWithFormat:@"%@/stallion_crash.marker", filesDir];
290
+
291
+ NSFileManager *fileManager = [NSFileManager defaultManager];
292
+ if ([fileManager fileExistsAtPath:markerPath]) {
293
+ NSError *error = nil;
294
+ NSString *jsonContent = [NSString stringWithContentsOfFile:markerPath
295
+ encoding:NSUTF8StringEncoding
296
+ error:&error];
297
+
298
+ if (jsonContent && !error) {
299
+ NSString *stackTraceString = @"";
300
+ BOOL isAutoRollback = NO;
301
+
302
+ @try {
303
+ // Parse JSON from previous crash
304
+ NSData *jsonData = [jsonContent dataUsingEncoding:NSUTF8StringEncoding];
305
+ NSDictionary *crashMarker = [NSJSONSerialization JSONObjectWithData:jsonData
306
+ options:0
307
+ error:&error];
308
+ if (crashMarker && !error) {
309
+ // Extract crash log and autoRollback flag from marker
310
+ stackTraceString = crashMarker[@"crashLog"] ?: @"";
311
+ // Use the autoRollback flag that was determined at crash time (previous session)
312
+ isAutoRollback = [crashMarker[@"isAutoRollback"] boolValue];
313
+ }
314
+ } @catch (NSException *e) {
315
+ // Fallback for old format (non-JSON)
316
+ stackTraceString = jsonContent;
317
+ // Default to true for old format (conservative approach)
318
+ isAutoRollback = YES;
319
+ }
320
+
321
+ if (stackTraceString.length > 900) {
322
+ stackTraceString = [stackTraceString substringToIndex:900];
323
+ }
324
+
325
+ StallionMeta *meta = stateManager.stallionMeta;
326
+ SwitchState switchState = meta.switchState;
327
+
328
+ if (switchState == SwitchStateProd) {
329
+ NSString *currentHash = [meta getActiveReleaseHash] ?: @"";
330
+ // Use isAutoRollback from previous crash, not current session state
331
+ @try {
332
+ [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_prod_event
333
+ eventPayload:@{
334
+ @"meta": stackTraceString,
335
+ StallionObjConstants.release_hash_key: currentHash,
336
+ StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
337
+ }];
338
+ } @catch (NSException *e) { }
339
+
340
+ if (isAutoRollback) {
341
+ // Only prevent multiple executions for auto rollback cases
342
+ bool expected = false;
343
+ if (rollbackPerformed.compare_exchange_strong(expected, true)) {
344
+ @try {
345
+ [StallionSlotManager rollbackProdWithAutoRollback:YES errorString:stackTraceString];
346
+ } @catch (NSException *e) { }
347
+ }
348
+ }
349
+ } else if (switchState == SwitchStateStage) {
350
+ NSString *currentStageHash = meta.stageNewHash ?: @"";
351
+ // Use isAutoRollback from previous crash, not current session state
352
+ @try {
353
+ [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event
354
+ eventPayload:@{
355
+ @"meta": stackTraceString,
356
+ StallionObjConstants.release_hash_key: currentStageHash,
357
+ StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false"
358
+ }];
359
+ } @catch (NSException *e) { }
360
+
361
+ if (isAutoRollback) {
362
+ // Only prevent multiple executions for auto rollback cases
363
+ bool expected = false;
364
+ if (rollbackPerformed.compare_exchange_strong(expected, true)) {
365
+ @try {
366
+ [StallionSlotManager rollbackStage];
367
+ } @catch (NSException *e) { }
368
+ }
369
+ }
370
+ }
371
+
372
+ // Delete marker
373
+ [StallionFileManager deleteFileOrFolderSilently:markerPath];
374
+ hasProcessedNativeCrashMarker.store(true);
375
+ }
376
+ }
377
+ } @catch (NSException *e) { }
292
378
  }
293
379
 
@@ -74,7 +74,7 @@
74
74
  NSString *newSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.new_folder_slot];
75
75
  NSString *stableSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.stable_folder_slot];
76
76
 
77
- [StallionFileManager copyFileOrDirectoryFrom:newSlotPath to:stableSlotPath];
77
+ [StallionFileManager moveFileFrom:newSlotPath to:stableSlotPath];
78
78
 
79
79
  NSString *newReleaseHash = stateManager.stallionMeta.prodNewHash;
80
80
  [stateManager.stallionMeta setProdStableHash:newReleaseHash];
@@ -44,6 +44,9 @@ static StallionStateManager *_instance = nil;
44
44
  _isMounted = NO;
45
45
  _pendingReleaseUrl = @"";
46
46
  _pendingReleaseHash = @"";
47
+
48
+ // Reset mount state on initialization (ensures mount marker file is deleted for new session)
49
+ [self setIsMounted:NO];
47
50
  }
48
51
  return self;
49
52
  }
@@ -70,6 +73,32 @@ static StallionStateManager *_instance = nil;
70
73
  [self syncStallionMeta];
71
74
  }
72
75
 
76
+ - (void)setIsMounted:(BOOL)isMounted {
77
+ _isMounted = isMounted;
78
+ // Write mount state to a simple file that signal handler can read (async-signal-safe)
79
+ NSString *filesDir = self.stallionConfig.filesDirectory;
80
+ NSString *mountMarkerPath = [NSString stringWithFormat:@"%@/stallion_mount.marker", filesDir];
81
+ NSFileManager *fileManager = [NSFileManager defaultManager];
82
+
83
+ if (isMounted) {
84
+ // Create file to indicate mounted (file existence = mounted)
85
+ @try {
86
+ [fileManager createFileAtPath:mountMarkerPath contents:nil attributes:nil];
87
+ } @catch (NSException *e) {
88
+ // Silently ignore errors
89
+ }
90
+ } else {
91
+ // Delete file to indicate not mounted (no file = not mounted)
92
+ @try {
93
+ if ([fileManager fileExistsAtPath:mountMarkerPath]) {
94
+ [fileManager removeItemAtPath:mountMarkerPath error:nil];
95
+ }
96
+ } @catch (NSException *e) {
97
+ // Silently ignore errors
98
+ }
99
+ }
100
+ }
101
+
73
102
  #pragma mark - Local Storage Methods
74
103
 
75
104
  - (NSString *)getStringForKey:(NSString *)key defaultValue:(NSString *)defaultValue {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-stallion",
3
- "version": "2.3.0-alpha.5",
3
+ "version": "2.3.0",
4
4
  "description": "Offical React Native SDK for Stallion",
5
5
  "main": "index",
6
6
  "types": "types/index.d.ts",
@@ -11,7 +11,8 @@ class ErrorBoundary extends Component {
11
11
  constructor(props) {
12
12
  super(props);
13
13
  this.state = {
14
- errorText: null
14
+ errorText: null,
15
+ originalError: null
15
16
  };
16
17
  this.continueCrash = this.continueCrash.bind(this);
17
18
  }
@@ -40,11 +41,6 @@ class ErrorBoundary extends Component {
40
41
  // Mark that a crash has occurred
41
42
  setCrashOccurred();
42
43
 
43
- // Always populate state with error information
44
- this.setState({
45
- errorText: errorString
46
- });
47
-
48
44
  // Get meta to determine behavior
49
45
  const meta = await getStallionMetaNative();
50
46
 
@@ -53,10 +49,22 @@ class ErrorBoundary extends Component {
53
49
  requestAnimationFrame(() => {
54
50
  throw error;
55
51
  });
52
+ } else {
53
+ // Store both error string and original error for STAGE mode
54
+ this.setState({
55
+ errorText: errorString,
56
+ originalError: error
57
+ });
56
58
  }
57
59
  }
58
60
  continueCrash() {
59
- throw new Error(this.state.errorText || '');
61
+ // Re-throw original error if available to preserve full context (stack trace, name, etc.)
62
+ // Fallback to new error with error text if original is not available
63
+ if (this.state.originalError) {
64
+ throw this.state.originalError;
65
+ } else {
66
+ throw new Error(this.state.errorText || '');
67
+ }
60
68
  }
61
69
  render() {
62
70
  if (this.state.errorText) {
@@ -1 +1 @@
1
- {"version":3,"names":["React","Component","View","StyleSheet","Text","ScrollView","SafeAreaView","Header","ButtonFullWidth","getStallionMetaNative","setCrashOccurred","HEADER_TITLE","STALLION_EB_BTN_TXT","STALLION_EB_INFO","STD_MARGIN","COLORS","SWITCH_STATES","ErrorBoundary","constructor","props","state","errorText","continueCrash","bind","componentDidCatch","error","errorInfo","errorParts","name","push","message","cause","String","stack","componentStack","errorString","length","join","console","setState","meta","switchState","STAGE","requestAnimationFrame","Error","render","createElement","style","styles","ebContainer","title","ebContentContainer","ebInfoTextContainer","ebInfoText","buttonText","onPress","ebScrollContainer","contentContainerStyle","ebScrollContentContainer","ebErrorText","children","create","flex","flexDirection","justifyContent","alignItems","paddingHorizontal","width","marginVertical","flexGrow","textAlign","backgroundColor","black7","color","white"],"sourceRoot":"../../../../src","sources":["main/utils/ErrorBoundary.tsx"],"mappings":"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"}
1
+ {"version":3,"names":["React","Component","View","StyleSheet","Text","ScrollView","SafeAreaView","Header","ButtonFullWidth","getStallionMetaNative","setCrashOccurred","HEADER_TITLE","STALLION_EB_BTN_TXT","STALLION_EB_INFO","STD_MARGIN","COLORS","SWITCH_STATES","ErrorBoundary","constructor","props","state","errorText","originalError","continueCrash","bind","componentDidCatch","error","errorInfo","errorParts","name","push","message","cause","String","stack","componentStack","errorString","length","join","console","meta","switchState","STAGE","requestAnimationFrame","setState","Error","render","createElement","style","styles","ebContainer","title","ebContentContainer","ebInfoTextContainer","ebInfoText","buttonText","onPress","ebScrollContainer","contentContainerStyle","ebScrollContentContainer","ebErrorText","children","create","flex","flexDirection","justifyContent","alignItems","paddingHorizontal","width","marginVertical","flexGrow","textAlign","backgroundColor","black7","color","white"],"sourceRoot":"../../../../src","sources":["main/utils/ErrorBoundary.tsx"],"mappings":"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"}
@@ -3,6 +3,7 @@ interface IErrorBoundaryProps {
3
3
  }
4
4
  interface IErrorBoundaryState {
5
5
  errorText?: string | null;
6
+ originalError?: Error | null;
6
7
  }
7
8
  declare class ErrorBoundary extends Component<IErrorBoundaryProps, IErrorBoundaryState> {
8
9
  constructor(props: IErrorBoundaryProps);
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../../src/main/utils/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBzC,UAAU,mBAAmB;CAAG;AAChC,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,cAAM,aAAc,SAAQ,SAAS,CACnC,mBAAmB,EACnB,mBAAmB,CACpB;gBACa,KAAK,EAAE,mBAAmB;IAQhC,iBAAiB,CACrB,KAAK,EAAE,KAAK,EACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,GAC1B,OAAO,CAAC,IAAI,CAAC;IA+ChB,aAAa;IAGb,MAAM;CAyBP;AAED,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../../../src/main/utils/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBzC,UAAU,mBAAmB;CAAG;AAChC,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAED,cAAM,aAAc,SAAQ,SAAS,CACnC,mBAAmB,EACnB,mBAAmB,CACpB;gBACa,KAAK,EAAE,mBAAmB;IAShC,iBAAiB,CACrB,KAAK,EAAE,KAAK,EACZ,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,GAC1B,OAAO,CAAC,IAAI,CAAC;IAgDhB,aAAa;IASb,MAAM;CAyBP;AAED,eAAe,aAAa,CAAC"}