Skip to content

Commit ae33103

Browse files
authored
Allow overriding of the default failure handler (#3793)
1 parent 330a55f commit ae33103

File tree

7 files changed

+139
-29
lines changed

7 files changed

+139
-29
lines changed

Firestore/Source/API/FIRFirestore.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include "Firestore/core/src/firebase/firestore/util/async_queue.h"
4747
#include "Firestore/core/src/firebase/firestore/util/error_apple.h"
4848
#include "Firestore/core/src/firebase/firestore/util/executor_libdispatch.h"
49+
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
50+
#include "Firestore/core/src/firebase/firestore/util/hard_assert_apple.h"
4951
#include "Firestore/core/src/firebase/firestore/util/log.h"
5052
#include "Firestore/core/src/firebase/firestore/util/status.h"
5153
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
@@ -57,7 +59,9 @@
5759
using firebase::firestore::api::ThrowInvalidArgument;
5860
using firebase::firestore::auth::CredentialsProvider;
5961
using firebase::firestore::model::DatabaseId;
62+
using firebase::firestore::util::ObjcFailureHandler;
6063
using firebase::firestore::util::AsyncQueue;
64+
using firebase::firestore::util::SetFailureHandler;
6165

6266
NS_ASSUME_NONNULL_BEGIN
6367

@@ -75,6 +79,12 @@ @implementation FIRFirestore {
7579
__weak id<FSTFirestoreInstanceRegistry> _registry;
7680
}
7781

82+
+ (void)initialize {
83+
if (self == [FIRFirestore class]) {
84+
SetFailureHandler(ObjcFailureHandler);
85+
}
86+
}
87+
7888
+ (instancetype)firestore {
7989
FIRApp *app = [FIRApp defaultApp];
8090
if (!app) {

Firestore/core/src/firebase/firestore/util/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ cc_select(
6767
cc_library(
6868
firebase_firestore_util_base_stdio
6969
SOURCES
70-
hard_assert_stdio.cc
70+
hard_assert.cc
7171
hard_assert.h
7272
log.h
7373
log_stdio.cc
@@ -84,7 +84,9 @@ cc_library(
8484
cc_library(
8585
firebase_firestore_util_base_apple
8686
SOURCES
87+
hard_assert.cc
8788
hard_assert.h
89+
hard_assert_apple.h
8890
hard_assert_apple.mm
8991
log.h
9092
log_apple.mm

Firestore/core/src/firebase/firestore/util/hard_assert_stdio.cc renamed to Firestore/core/src/firebase/firestore/util/hard_assert.cc

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@
2626
namespace firebase {
2727
namespace firestore {
2828
namespace util {
29-
namespace internal {
3029

31-
void Fail(const char* file,
32-
const char* func,
33-
const int line,
34-
const std::string& message) {
30+
ABSL_ATTRIBUTE_NORETURN void DefaultFailureHandler(const char* file,
31+
const char* func,
32+
const int line,
33+
const std::string& message) {
3534
std::string failure =
3635
StringFormat("ASSERT: %s(%s) %s: %s", file, line, func, message);
3736

@@ -44,6 +43,29 @@ void Fail(const char* file,
4443
#endif
4544
}
4645

46+
namespace {
47+
FailureHandler failure_handler = DefaultFailureHandler;
48+
} // namespace
49+
50+
FailureHandler SetFailureHandler(FailureHandler callback) {
51+
FailureHandler previous = failure_handler;
52+
failure_handler = callback;
53+
return previous;
54+
}
55+
56+
namespace internal {
57+
58+
void Fail(const char* file,
59+
const char* func,
60+
const int line,
61+
const std::string& message) {
62+
failure_handler(file, func, line, message);
63+
64+
// It's expected that the failure handler above does not return. But if it
65+
// does, just terminate.
66+
std::terminate();
67+
}
68+
4769
void Fail(const char* file,
4870
const char* func,
4971
const int line,

Firestore/core/src/firebase/firestore/util/hard_assert.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,35 @@
101101
namespace firebase {
102102
namespace firestore {
103103
namespace util {
104+
105+
using FailureHandler = void (*)(const char* file,
106+
const char* func,
107+
const int line,
108+
const std::string& failure_message);
109+
110+
/**
111+
* Overrides the default failure handler.
112+
*
113+
* The default essentially just calls std::terminate. While reasonable for C++,
114+
* this isn't optimal for platforms that merely use the C++ core as their
115+
* implementation and would otherwise be expected to throw a platform specific
116+
* exception.
117+
*
118+
* @param callback A function that will handle the failure. This function is
119+
* not expected to return. (If it does, std::terminate() will be called
120+
* immediately after it does so.)
121+
* @return A pointer to the previous failure handler.
122+
*/
123+
FailureHandler SetFailureHandler(FailureHandler callback);
124+
125+
/**
126+
* Default failure handler. This should typically not be called directly.
127+
*/
128+
ABSL_ATTRIBUTE_NORETURN void DefaultFailureHandler(const char* file,
129+
const char* func,
130+
const int line,
131+
const std::string& message);
132+
104133
namespace internal {
105134

106135
// A no-return helper function. To raise an assertion, use Macro instead.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2019 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_APPLE_H_
18+
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_APPLE_H_
19+
20+
#include <string>
21+
22+
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
23+
#include "absl/base/attributes.h"
24+
25+
namespace firebase {
26+
namespace firestore {
27+
namespace util {
28+
29+
/**
30+
* Default failure handler for ObjC/Swift. Typically shouldn't be used
31+
* directly.
32+
*/
33+
ABSL_ATTRIBUTE_NORETURN void ObjcFailureHandler(const char* file,
34+
const char* func,
35+
const int line,
36+
const std::string& message);
37+
38+
} // namespace util
39+
} // namespace firestore
40+
} // namespace firebase
41+
42+
#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_HARD_ASSERT_APPLE_H_

Firestore/core/src/firebase/firestore/util/hard_assert_apple.mm

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,20 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
17+
#include "Firestore/core/src/firebase/firestore/util/hard_assert_apple.h"
1818

1919
#import <Foundation/Foundation.h>
2020

21-
#include <string>
22-
2321
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
2422

2523
namespace firebase {
2624
namespace firestore {
2725
namespace util {
28-
namespace internal {
2926

30-
void Fail(const char* file,
31-
const char* func,
32-
const int line,
33-
const std::string& message) {
27+
ABSL_ATTRIBUTE_NORETURN void ObjcFailureHandler(const char* file,
28+
const char* func,
29+
const int line,
30+
const std::string& message) {
3431
[[NSAssertionHandler currentHandler]
3532
handleFailureInFunction:MakeNSString(func)
3633
file:MakeNSString(file)
@@ -40,21 +37,6 @@ void Fail(const char* file,
4037
abort();
4138
}
4239

43-
void Fail(const char* file,
44-
const char* func,
45-
const int line,
46-
const std::string& message,
47-
const char* condition) {
48-
std::string failure;
49-
if (message.empty()) {
50-
failure = condition;
51-
} else {
52-
failure = StringFormat("%s (expected %s)", message, condition);
53-
}
54-
Fail(file, func, line, failure);
55-
}
56-
57-
} // namespace internal
5840
} // namespace util
5941
} // namespace firestore
6042
} // namespace firebase

Firestore/core/test/firebase/firestore/util/hard_assert_test.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,29 @@ TEST(HardAssertTest, WithMessage) {
4747
EXPECT_ANY_THROW(AssertWithMessage(false));
4848
}
4949

50+
TEST(HardAssertTest, NonDefaultFailureHandler) {
51+
// Used to ensure the original failure handler is restored.
52+
class FailureHandlerRestorer {
53+
public:
54+
explicit FailureHandlerRestorer(FailureHandler orig) : orig_(orig) {
55+
}
56+
~FailureHandlerRestorer() {
57+
SetFailureHandler(orig_);
58+
}
59+
60+
private:
61+
FailureHandler orig_;
62+
};
63+
64+
struct FakeException {};
65+
FailureHandler prev =
66+
SetFailureHandler([](const char*, const char*, const int,
67+
const std::string&) { throw FakeException(); });
68+
FailureHandlerRestorer _(prev);
69+
70+
EXPECT_THROW(Assert(false), FakeException);
71+
}
72+
5073
} // namespace util
5174
} // namespace firestore
5275
} // namespace firebase

0 commit comments

Comments
 (0)