7474void
7575_non_thread_safe_removeFileAtPath (NSString *path)
7676{
77- NSError *error = nil ;
77+ NSError *_Nullable error = nil ;
7878 NSFileManager *fileManager = [NSFileManager defaultManager ];
7979 if ([fileManager removeItemAtPath: path error: &error]) {
8080 SENTRY_LOG_DEBUG (@" Successfully deleted file at %@ " , path);
8181 } else if (error.code == NSFileNoSuchFileError) {
8282 SENTRY_LOG_DEBUG (@" No file to delete at %@ " , path);
83- } else if (isErrorPathTooLong (error)) {
83+ } else if (error != NULL && isErrorPathTooLong (SENTRY_UNWRAP_NULLABLE ( NSError , error) )) {
8484 SENTRY_LOG_FATAL (@" Failed to remove file, path is too long: %@ " , path);
8585 } else {
8686 SENTRY_LOG_ERROR (@" Error occurred while deleting file at %@ because of %@ " , path, error);
@@ -158,7 +158,22 @@ - (void)createPathsWithOptions:(SentryOptions *)options
158158 SENTRY_LOG_DEBUG (@" SentryFileManager.cachePath: %@ " , cachePath);
159159
160160 self.basePath = [cachePath stringByAppendingPathComponent: @" io.sentry" ];
161- self.sentryPath = [self .basePath stringByAppendingPathComponent: [options.parsedDsn getHash ]];
161+
162+ NSString *_Nullable nullableDsnHash = [options.parsedDsn getHash ];
163+ if (nullableDsnHash == nil ) {
164+ SENTRY_LOG_FATAL (@" No DSN provided, using base path for envelopes: %@ " , self.basePath );
165+ }
166+ // We decided against changing the `sentryPath` and use a null fallback instead, because this
167+ // has been broken for a long time and the impact of changing the base path can result in
168+ // critical issues.
169+ //
170+ // Instead we silence the nullability warning and let `stringByAppendingPathComponent` handle
171+ // the null case.
172+ //
173+ // Full discussion in https://github.com/getsentry/sentry-cocoa/pull/5737
174+ self.sentryPath = [self .basePath
175+ stringByAppendingPathComponent: SENTRY_UNWRAP_NULLABLE (NSString , nullableDsnHash)];
176+
162177 self.currentSessionFilePath =
163178 [self .sentryPath stringByAppendingPathComponent: @" session.current" ];
164179 self.crashedSessionFilePath =
@@ -233,7 +248,7 @@ - (nullable NSString *)getEnvelopesPath:(NSString *)filePath
233248 return nil ;
234249 }
235250
236- NSError *error = nil ;
251+ NSError *_Nullable error = nil ;
237252 NSDictionary *dict = [[NSFileManager defaultManager ] attributesOfItemAtPath: fullPath
238253 error: &error];
239254 if (error != nil ) {
@@ -295,7 +310,7 @@ - (void)deleteOldEnvelopeItems
295310- (void )deleteAllEnvelopes
296311{
297312 [self removeFileAtPath: self .envelopesPath];
298- NSError *error;
313+ NSError *_Nullable error;
299314 if (!createDirectoryIfNotExists (self.envelopesPath , &error)) {
300315 SENTRY_LOG_ERROR (@" Couldn't create envelopes path." );
301316 }
@@ -355,7 +370,12 @@ - (void)storeTimestampLastInForeground:(NSDate *)timestamp
355370 NSString *timestampString = sentry_toIso8601String (timestamp);
356371 SENTRY_LOG_DEBUG (@" Persisting lastInForeground: %@ " , timestampString);
357372 @synchronized (self.lastInForegroundFilePath ) {
358- if (![self writeData: [timestampString dataUsingEncoding: NSUTF8StringEncoding]
373+ NSData *_Nullable nullableData = [timestampString dataUsingEncoding: NSUTF8StringEncoding];
374+ if (nullableData == nil ) {
375+ SENTRY_LOG_ERROR (@" Failed to convert lastInForeground timestamp to data." );
376+ return ;
377+ }
378+ if (![self writeData: SENTRY_UNWRAP_NULLABLE (NSData , nullableData)
359379 toPath: self .lastInForegroundFilePath]) {
360380 SENTRY_LOG_WARN (@" Failed to store timestamp of last foreground event." );
361381 }
@@ -491,7 +511,7 @@ - (NSArray *)readPreviousBreadcrumbs
491511 continue ;
492512 }
493513
494- NSError *error;
514+ NSError *_Nullable error;
495515 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData: data
496516 options: 0
497517 error: &error];
@@ -535,7 +555,14 @@ - (void)storeTimezoneOffset:(NSInteger)offset
535555 NSString *timezoneOffsetString = [NSString stringWithFormat: @" %ld " , (long )offset];
536556 SENTRY_LOG_DEBUG (@" Persisting timezone offset: %@ " , timezoneOffsetString);
537557 @synchronized (self.timezoneOffsetFilePath ) {
538- if (![self writeData: [timezoneOffsetString dataUsingEncoding: NSUTF8StringEncoding]
558+ NSData *_Nullable nullableData =
559+ [timezoneOffsetString dataUsingEncoding: NSUTF8StringEncoding];
560+ if (nullableData == nil ) {
561+ SENTRY_LOG_ERROR (@" Failed to convert timezone offset to data." );
562+ return ;
563+ }
564+
565+ if (![self writeData: SENTRY_UNWRAP_NULLABLE (NSData , nullableData)
539566 toPath: self .timezoneOffsetFilePath]) {
540567 SENTRY_LOG_WARN (@" Failed to store timezone offset." );
541568 }
@@ -613,7 +640,7 @@ - (nullable NSData *)readDataFromPath:(NSString *)path
613640
614641- (BOOL )writeData : (NSData *)data toPath : (NSString *)path
615642{
616- NSError *error;
643+ NSError *_Nullable error;
617644 if (!createDirectoryIfNotExists (self.sentryPath , &error)) {
618645 SENTRY_LOG_ERROR (@" File I/O not available at path %@ : %@ " , path, error);
619646 return NO ;
@@ -645,7 +672,7 @@ - (void)removeFileAtPath:(NSString *)path
645672 return @[];
646673 }
647674
648- NSError *error = nil ;
675+ NSError *_Nullable error = nil ;
649676 NSArray <NSString *> *storedFiles = [fileManager contentsOfDirectoryAtPath: path error: &error];
650677 if (error != nil ) {
651678 SENTRY_LOG_ERROR (@" Couldn't load files in folder %@ : %@ " , path, error);
@@ -674,13 +701,14 @@ - (BOOL)isDirectory:(NSString *)path
674701 // For iOS apps and macOS apps with sandboxing, this path will be scoped for the current
675702 // app. For macOS apps without sandboxing, this path is not scoped and will be shared
676703 // between all apps.
677- NSString *_Nullable cachesDirectory
704+ NSString *_Nullable nullableCachesDirectory
678705 = NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES )
679706 .firstObject ;
680- if (cachesDirectory == nil ) {
707+ if (nullableCachesDirectory == nil ) {
681708 SENTRY_LOG_WARN (@" No caches directory location reported." );
682709 return ;
683710 }
711+ NSString *_Nonnull cachesDirectory = (NSString *_Nonnull)nullableCachesDirectory;
684712
685713 // We need to ensure our own scoped directory so that this path is not shared between other
686714 // apps on the same system.
@@ -767,7 +795,7 @@ - (BOOL)isDirectory:(NSString *)path
767795 return nil ;
768796 }
769797
770- return [cachesDirectory stringByAppendingPathComponent: identifier];
798+ return [cachesDirectory stringByAppendingPathComponent: ( NSString *_Nonnull) identifier];
771799}
772800
773801NSString *_Nullable sentryStaticBasePath (void )
@@ -789,7 +817,12 @@ - (BOOL)isDirectory:(NSString *)path
789817void
790818removeSentryStaticBasePath (void )
791819{
792- _non_thread_safe_removeFileAtPath (sentryStaticBasePath ());
820+ NSString *_Nullable basePath = sentryStaticBasePath ();
821+ if (basePath == nil ) {
822+ SENTRY_LOG_DEBUG (@" No base path available to remove." );
823+ return ;
824+ }
825+ _non_thread_safe_removeFileAtPath ((NSString *_Nonnull)basePath);
793826}
794827#endif // defined(SENTRY_TEST) || defined(SENTRY_TEST_CI) || defined(DEBUG)
795828
@@ -808,7 +841,7 @@ - (BOOL)isDirectory:(NSString *)path
808841 SENTRY_LOG_WARN (@" No location available to write a launch profiling config." );
809842 return ;
810843 }
811- NSError *error;
844+ NSError *_Nullable error;
812845 if (!createDirectoryIfNotExists (basePath, &error)) {
813846 SENTRY_LOG_ERROR (
814847 @" Can't create base path to store launch profile config file: %@ " , error);
@@ -824,14 +857,25 @@ - (BOOL)isDirectory:(NSString *)path
824857NSDictionary <NSString *, NSNumber *> *_Nullable sentry_persistedLaunchProfileConfigurationOptions (
825858 void )
826859{
827- NSURL *url = launchProfileConfigFileURL ();
828- if (![[NSFileManager defaultManager ] fileExistsAtPath: url.path]) {
860+ NSURL *_Nullable url = launchProfileConfigFileURL ();
861+ if (url == nil ) {
862+ SENTRY_LOG_ERROR (@" Failed to construct the URL to retrieve launch profile configs." )
863+ return nil ;
864+ }
865+ NSString *_Nullable nullablePath = url.path ;
866+ if (nullablePath == nil ) {
867+ SENTRY_LOG_ERROR (@" Failed to construct the path to retrieve launch profile configs." )
868+ return nil ;
869+ }
870+ if (![[NSFileManager defaultManager ]
871+ fileExistsAtPath: SENTRY_UNWRAP_NULLABLE (NSString , nullablePath)]) {
829872 return nil ;
830873 }
831874
832- NSError *error;
833- NSDictionary <NSString *, NSNumber *> *config =
834- [NSDictionary <NSString *, NSNumber *> dictionaryWithContentsOfURL:url error: &error];
875+ NSError *_Nullable error;
876+ NSDictionary <NSString *, NSNumber *> *config = [NSDictionary <NSString *, NSNumber *>
877+ dictionaryWithContentsOfURL: SENTRY_UNWRAP_NULLABLE (NSURL , url)
878+ error: &error];
835879
836880 if (error != nil ) {
837881 SENTRY_LOG_ERROR (
@@ -845,9 +889,14 @@ - (BOOL)isDirectory:(NSString *)path
845889BOOL
846890appLaunchProfileConfigFileExists (void )
847891{
848- NSString *path = launchProfileConfigFileURL ().path ;
892+ NSURL *_Nullable url = launchProfileConfigFileURL ();
893+ if (url == nil ) {
894+ SENTRY_LOG_ERROR (@" Failed to construct the URL to check for launch profile configs." )
895+ return NO ;
896+ }
897+ NSString *_Nullable path = url.path ;
849898 if (path == nil ) {
850- SENTRY_LOG_DEBUG (@" Failed to construct the path to check for launch profile configs." )
899+ SENTRY_LOG_ERROR (@" Failed to construct the path to check for launch profile configs." )
851900 return NO ;
852901 }
853902
@@ -857,16 +906,34 @@ - (BOOL)isDirectory:(NSString *)path
857906void
858907writeAppLaunchProfilingConfigFile (NSMutableDictionary <NSString *, NSNumber *> *config)
859908{
860- NSError *error;
861- SENTRY_LOG_DEBUG (@" Writing launch profiling config file." );
862- SENTRY_CASSERT ([config writeToURL: launchProfileConfigFileURL () error: &error],
909+ NSURL *_Nullable url = launchProfileConfigFileURL ();
910+ if (url == nil ) {
911+ SENTRY_LOG_ERROR (@" Failed to construct the URL to write launch profile configs." );
912+ return ;
913+ }
914+ SENTRY_LOG_DEBUG (@" Writing launch profiling config file at url %@ " , url);
915+
916+ NSError *_Nullable error;
917+ SENTRY_CASSERT ([config writeToURL: SENTRY_UNWRAP_NULLABLE (NSURL , url) error: &error],
863918 @" Failed to write launch profile config file: %@ ." , error);
864919}
865920
866921void
867922removeAppLaunchProfilingConfigFile (void )
868923{
869- _non_thread_safe_removeFileAtPath (launchProfileConfigFileURL ().path );
924+ NSURL *_Nullable url = launchProfileConfigFileURL ();
925+ if (url == nil ) {
926+ SENTRY_LOG_ERROR (@" Failed to construct the URL to remove launch profile configs." );
927+ return ;
928+ }
929+ NSString *_Nullable path = url.path ;
930+ if (path == nil ) {
931+ SENTRY_LOG_ERROR (@" Failed to construct the path to remove launch profile configs." );
932+ return ;
933+ }
934+
935+ SENTRY_LOG_DEBUG (@" Removing launch profiling config file at path: %@ " , path);
936+ _non_thread_safe_removeFileAtPath (SENTRY_UNWRAP_NULLABLE (NSString , path));
870937}
871938#endif // SENTRY_TARGET_PROFILING_SUPPORTED
872939
@@ -940,7 +1007,7 @@ - (void)moveState:(NSString *)stateFilePath toPreviousState:(NSString *)previous
9401007 // We first need to remove the old previous state file,
9411008 // or we can't move the current state file to it.
9421009 [self removeFileAtPath: previousStateFilePath];
943- NSError *error = nil ;
1010+ NSError *_Nullable error = nil ;
9441011 if (![fileManager moveItemAtPath: stateFilePath toPath: previousStateFilePath error: &error]) {
9451012 // We don't want to log an error if the file doesn't exist.
9461013 if (nil != error && error.code != NSFileNoSuchFileError) {
0 commit comments