summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2017-07-05 10:55:11 +0200
committerGitHub <noreply@github.com>2017-07-05 10:55:11 +0200
commit6f63a01302355077af2459c96a17e299c32b2960 (patch)
treec0c6ed6e20f8dc26b436e9c193a962dbd09ffcb7 /core
parent5a48b428fd349411456b785a5cb9a6ee0d5b1506 (diff)
parent211c4518903d82068c061943064824ac5595fd38 (diff)
Merge pull request #8943 from RandomShaper/fix-error-handling
Implement well-defined handling of unrecoverable errors
Diffstat (limited to 'core')
-rw-r--r--core/dvector.h17
-rw-r--r--core/error_macros.h54
-rw-r--r--core/hash_map.h3
-rw-r--r--core/list.h14
-rw-r--r--core/map.h6
-rw-r--r--core/object.h10
-rw-r--r--core/vector.h11
-rw-r--r--core/vmap.h6
8 files changed, 76 insertions, 45 deletions
diff --git a/core/dvector.h b/core/dvector.h
index 4584a300f9..66af42f7e2 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -409,14 +409,9 @@ public:
if (p_to < 0) {
p_to = size() + p_to;
}
- if (p_from < 0 || p_from >= size()) {
- PoolVector<T> &aux = *((PoolVector<T> *)0); // nullreturn
- ERR_FAIL_COND_V(p_from < 0 || p_from >= size(), aux)
- }
- if (p_to < 0 || p_to >= size()) {
- PoolVector<T> &aux = *((PoolVector<T> *)0); // nullreturn
- ERR_FAIL_COND_V(p_to < 0 || p_to >= size(), aux)
- }
+
+ CRASH_BAD_INDEX(p_from, size());
+ CRASH_BAD_INDEX(p_to, size());
PoolVector<T> slice;
int span = 1 + p_to - p_from;
@@ -506,13 +501,9 @@ void PoolVector<T>::push_back(const T &p_val) {
template <class T>
const T PoolVector<T>::operator[](int p_index) const {
- if (p_index < 0 || p_index >= size()) {
- T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
- }
+ CRASH_BAD_INDEX(p_index, size());
Read r = read();
-
return r[p_index];
}
diff --git a/core/error_macros.h b/core/error_macros.h
index 00fced3586..6c803951a1 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -115,6 +115,19 @@ extern bool _err_error_exists;
#define FUNCTION_STR __FUNCTION__
#endif
+// Don't use this directly; instead, use any of the CRASH_* macros
+#ifdef _MSC_VER
+#define GENERATE_TRAP \
+ __debugbreak(); \
+ /* Avoid warning about control paths */ \
+ for (;;) { \
+ }
+#else
+#define GENERATE_TRAP __builtin_trap();
+#endif
+
+// (*): See https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for
+
#define ERR_FAIL_INDEX(m_index, m_size) \
do { \
if ((m_index) < 0 || (m_index) >= (m_size)) { \
@@ -122,12 +135,12 @@ extern bool _err_error_exists;
return; \
} else \
_err_error_exists = false; \
- } while (0);
+ } while (0); // (*)
/** An index has failed if m_index<0 or m_index >=m_size, the function exists.
- * This function returns an error value, if returning Error, please select the most
- * appropriate error condition from error_macros.h
- */
+* This function returns an error value, if returning Error, please select the most
+* appropriate error condition from error_macros.h
+*/
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
do { \
@@ -136,7 +149,18 @@ extern bool _err_error_exists;
return m_retval; \
} else \
_err_error_exists = false; \
- } while (0);
+ } while (0); // (*)
+
+/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
+* We'll return a null reference and try to keep running.
+*/
+#define CRASH_BAD_INDEX(m_index, m_size) \
+ do { \
+ if ((m_index) < 0 || (m_index) >= (m_size)) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Index " _STR(m_index) " out of size (" _STR(m_size) ")."); \
+ GENERATE_TRAP \
+ } \
+ } while (0); // (*)
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the function will exit.
@@ -173,6 +197,17 @@ extern bool _err_error_exists;
_err_error_exists = false; \
}
+/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
+ */
+
+#define CRASH_COND(m_cond) \
+ { \
+ if (m_cond) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true."); \
+ GENERATE_TRAP \
+ } \
+ }
+
/** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
* the function will exit.
* This function returns an error value, if returning Error, please select the most
@@ -234,6 +269,15 @@ extern bool _err_error_exists;
return m_value; \
}
+/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
+ */
+
+#define CRASH_NOW() \
+ { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed."); \
+ GENERATE_TRAP \
+ }
+
/** Print an error string.
*/
diff --git a/core/hash_map.h b/core/hash_map.h
index 49701188ab..45e7b82d24 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -473,8 +473,7 @@ public:
if (!e) {
e = create_entry(p_key);
- if (!e)
- return *(TData *)NULL; /* panic! */
+ CRASH_COND(!e);
check_hash_table(); // perform mantenience routine
}
diff --git a/core/list.h b/core/list.h
index 4390cb65fc..df69b1dc40 100644
--- a/core/list.h
+++ b/core/list.h
@@ -398,10 +398,7 @@ public:
T &operator[](int p_index) {
- if (p_index < 0 || p_index >= size()) {
- T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
- }
+ CRASH_BAD_INDEX(p_index, size());
Element *I = front();
int c = 0;
@@ -415,15 +412,12 @@ public:
c++;
}
- ERR_FAIL_V(*((T *)0)); // bug!!
+ CRASH_NOW(); // bug!!
}
const T &operator[](int p_index) const {
- if (p_index < 0 || p_index >= size()) {
- T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
- }
+ CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
int c = 0;
@@ -437,7 +431,7 @@ public:
c++;
}
- ERR_FAIL_V(*((T *)0)); // bug!
+ CRASH_NOW(); // bug!!
}
void move_to_back(Element *p_I) {
diff --git a/core/map.h b/core/map.h
index acf1d608d8..ef0f75fc9b 100644
--- a/core/map.h
+++ b/core/map.h
@@ -599,9 +599,9 @@ public:
const V &operator[](const K &p_key) const {
- ERR_FAIL_COND_V(!_data._root, *(V *)NULL); // crash on purpose
+ CRASH_COND(!_data._root);
const Element *e = find(p_key);
- ERR_FAIL_COND_V(!e, *(V *)NULL); // crash on purpose
+ CRASH_COND(!e);
return e->_value;
}
V &operator[](const K &p_key) {
@@ -613,7 +613,7 @@ public:
if (!e)
e = insert(p_key, V());
- ERR_FAIL_COND_V(!e, *(V *)NULL); // crash on purpose
+ CRASH_COND(!e);
return e->_value;
}
diff --git a/core/object.h b/core/object.h
index dec4949c8d..f87705c48b 100644
--- a/core/object.h
+++ b/core/object.h
@@ -533,6 +533,12 @@ public:
void add_change_receptor(Object *p_receptor);
void remove_change_receptor(Object *p_receptor);
+// TODO: ensure 'this' is never NULL since it's UB, but by now, avoid warning flood
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-bool-conversion"
+#endif
+
template <class T>
T *cast_to() {
@@ -563,6 +569,10 @@ public:
#endif
}
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
enum {
NOTIFICATION_POSTINITIALIZE = 0,
diff --git a/core/vector.h b/core/vector.h
index fe1c1b05dd..5eed8dce96 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -134,10 +134,7 @@ public:
inline T &operator[](int p_index) {
- if (p_index < 0 || p_index >= size()) {
- T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
- }
+ CRASH_BAD_INDEX(p_index, size());
_copy_on_write(); // wants to write, so copy on write.
@@ -146,10 +143,8 @@ public:
inline const T &operator[](int p_index) const {
- if (p_index < 0 || p_index >= size()) {
- const T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(p_index < 0 || p_index >= size(), aux);
- }
+ CRASH_BAD_INDEX(p_index, size());
+
// no cow needed, since it's reading
return _get_data()[p_index];
}
diff --git a/core/vmap.h b/core/vmap.h
index ad07973308..66f935f58d 100644
--- a/core/vmap.h
+++ b/core/vmap.h
@@ -180,10 +180,8 @@ public:
inline const V &operator[](const T &p_key) const {
int pos = _find_exact(p_key);
- if (pos < 0) {
- const T &aux = *((T *)0); //nullreturn
- ERR_FAIL_COND_V(pos < 1, aux);
- }
+
+ CRASH_COND(pos < 0);
return _data[pos].value;
}