浏览代码

Make error handling more convenient

By adding some PRAY_* macros that encapsulate both the check and the returning of a null reference (UB).
Plus transient avoidance of the flood of warnings emitted by Clang when checking 'this' for NULL.
Plus explanation about the do-while(0) loop in some error macros.
Pedro J. Estébanez 8 年之前
父节点
当前提交
e9b7640f84
共有 8 个文件被更改,包括 66 次插入34 次删除
  1. 1 5
      core/dvector.h
  2. 42 2
      core/error_macros.h
  3. 1 2
      core/hash_map.h
  4. 4 10
      core/list.h
  5. 3 3
      core/map.h
  6. 10 0
      core/object.h
  7. 3 8
      core/vector.h
  8. 2 4
      core/vmap.h

+ 1 - 5
core/dvector.h

@@ -311,13 +311,9 @@ void DVector<T>::push_back(const T &p_val) {
 template <class T>
 template <class T>
 const T DVector<T>::operator[](int p_index) const {
 const T DVector<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);
-	}
+	PRAY_BAD_INDEX(p_index, size(), T);
 
 
 	Read r = read();
 	Read r = read();
-
 	return r[p_index];
 	return r[p_index];
 }
 }
 
 

+ 42 - 2
core/error_macros.h

@@ -114,6 +114,8 @@ extern bool _err_error_exists;
 #define FUNCTION_STR __FUNCTION__
 #define FUNCTION_STR __FUNCTION__
 #endif
 #endif
 
 
+// (*): See https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for
+
 #define ERR_FAIL_INDEX(m_index, m_size)                                                                                    \
 #define ERR_FAIL_INDEX(m_index, m_size)                                                                                    \
 	do {                                                                                                                   \
 	do {                                                                                                                   \
 		if ((m_index) < 0 || (m_index) >= (m_size)) {                                                                      \
 		if ((m_index) < 0 || (m_index) >= (m_size)) {                                                                      \
@@ -121,7 +123,7 @@ extern bool _err_error_exists;
 			return;                                                                                                        \
 			return;                                                                                                        \
 		} else                                                                                                             \
 		} else                                                                                                             \
 			_err_error_exists = false;                                                                                     \
 			_err_error_exists = false;                                                                                     \
-	} while (0);
+	} while (0); // (*)
 
 
 /** An index has failed if m_index<0 or m_index >=m_size, the function exists.
 /** 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
   * This function returns an error value, if returning Error, please select the most
@@ -135,7 +137,20 @@ extern bool _err_error_exists;
 			return m_retval;                                                                                               \
 			return m_retval;                                                                                               \
 		} else                                                                                                             \
 		} else                                                                                                             \
 			_err_error_exists = false;                                                                                     \
 			_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 do UB by returning a null reference and pray that we wont't crash.
+	*/
+#define PRAY_BAD_INDEX(m_index, m_size, m_type)                                                                                    \
+	do {                                                                                                                           \
+		if ((m_index) < 0 || (m_index) >= (m_size)) {                                                                              \
+			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "SEVERE: Index " _STR(m_index) " out of size (" _STR(m_size) ")."); \
+			m_type *n = (m_type *)0; /* two-step to avoid warning */                                                               \
+			return *n;                                                                                                             \
+		} else                                                                                                                     \
+			_err_error_exists = false;                                                                                             \
+	} while (0); // (*)
 
 
 /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
 /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
   * the function will exit.
   * the function will exit.
@@ -187,6 +202,20 @@ extern bool _err_error_exists;
 			_err_error_exists = false;                                                                                               \
 			_err_error_exists = false;                                                                                               \
 	}
 	}
 
 
+/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
+  *  We'll do UB by returning a null reference and pray that we wont't crash.
+  */
+
+#define PRAY_COND(m_cond, m_type)                                                                                  \
+	{                                                                                                              \
+		if (m_cond) {                                                                                              \
+			_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "SEVERE: Condition ' " _STR(m_cond) " ' is true."); \
+			m_type *n = (m_type *)0; /* two-step to avoid warning */                                               \
+			return *n;                                                                                             \
+		} else                                                                                                     \
+			_err_error_exists = false;                                                                             \
+	}
+
 /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
 /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert().
  * the loop will skip to the next iteration.
  * the loop will skip to the next iteration.
  */
  */
@@ -233,6 +262,17 @@ extern bool _err_error_exists;
 		return m_value;                                                                                           \
 		return m_value;                                                                                           \
 	}
 	}
 
 
+/** Use this one if there is no sensible fallback, that is, the error is unrecoverable.
+  *  We'll do UB by returning a null reference and pray that we wont't crash.
+  */
+
+#define PRAY(m_type)                                                                           \
+	{                                                                                          \
+		_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "SEVERE: Method/Function Failed."); \
+		m_type *n = (m_type *)0; /* two-step to avoid warning */                               \
+		return *n;                                                                             \
+	}
+
 /** Print an error string.
 /** Print an error string.
  */
  */
 
 

+ 1 - 2
core/hash_map.h

@@ -465,8 +465,7 @@ public:
 		if (!e) {
 		if (!e) {
 
 
 			e = create_entry(p_key);
 			e = create_entry(p_key);
-			if (!e)
-				return *(TData *)NULL; /* panic! */
+			PRAY_COND(!e, TData);
 			check_hash_table(); // perform mantenience routine
 			check_hash_table(); // perform mantenience routine
 		}
 		}
 
 

+ 4 - 10
core/list.h

@@ -398,10 +398,7 @@ public:
 
 
 	T &operator[](int p_index) {
 	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);
-		}
+		PRAY_BAD_INDEX(p_index, size(), T);
 
 
 		Element *I = front();
 		Element *I = front();
 		int c = 0;
 		int c = 0;
@@ -415,15 +412,12 @@ public:
 			c++;
 			c++;
 		}
 		}
 
 
-		ERR_FAIL_V(*((T *)0)); // bug!!
+		PRAY(T); // bug!!
 	}
 	}
 
 
 	const T &operator[](int p_index) const {
 	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);
-		}
+		PRAY_BAD_INDEX(p_index, size(), T);
 
 
 		const Element *I = front();
 		const Element *I = front();
 		int c = 0;
 		int c = 0;
@@ -437,7 +431,7 @@ public:
 			c++;
 			c++;
 		}
 		}
 
 
-		ERR_FAIL_V(*((T *)0)); // bug!
+		PRAY(T); // bug!!
 	}
 	}
 
 
 	void move_to_back(Element *p_I) {
 	void move_to_back(Element *p_I) {

+ 3 - 3
core/map.h

@@ -599,9 +599,9 @@ public:
 
 
 	const V &operator[](const K &p_key) const {
 	const V &operator[](const K &p_key) const {
 
 
-		ERR_FAIL_COND_V(!_data._root, *(V *)NULL); // crash on purpose
+		PRAY_COND(!_data._root, V);
 		const Element *e = find(p_key);
 		const Element *e = find(p_key);
-		ERR_FAIL_COND_V(!e, *(V *)NULL); // crash on purpose
+		PRAY_COND(!e, V);
 		return e->_value;
 		return e->_value;
 	}
 	}
 	V &operator[](const K &p_key) {
 	V &operator[](const K &p_key) {
@@ -613,7 +613,7 @@ public:
 		if (!e)
 		if (!e)
 			e = insert(p_key, V());
 			e = insert(p_key, V());
 
 
-		ERR_FAIL_COND_V(!e, *(V *)NULL); // crash on purpose
+		PRAY_COND(!e, V);
 		return e->_value;
 		return e->_value;
 	}
 	}
 
 

+ 10 - 0
core/object.h

@@ -509,6 +509,12 @@ public:
 	void add_change_receptor(Object *p_receptor);
 	void add_change_receptor(Object *p_receptor);
 	void remove_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>
 	template <class T>
 	T *cast_to() {
 	T *cast_to() {
 
 
@@ -539,6 +545,10 @@ public:
 #endif
 #endif
 	}
 	}
 
 
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
 	enum {
 	enum {
 
 
 		NOTIFICATION_POSTINITIALIZE = 0,
 		NOTIFICATION_POSTINITIALIZE = 0,

+ 3 - 8
core/vector.h

@@ -133,10 +133,7 @@ public:
 
 
 	inline T &operator[](int p_index) {
 	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);
-		}
+		PRAY_BAD_INDEX(p_index, size(), T);
 
 
 		_copy_on_write(); // wants to write, so copy on write.
 		_copy_on_write(); // wants to write, so copy on write.
 
 
@@ -145,10 +142,8 @@ public:
 
 
 	inline const T &operator[](int p_index) const {
 	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);
-		}
+		PRAY_BAD_INDEX(p_index, size(), T);
+
 		// no cow needed, since it's reading
 		// no cow needed, since it's reading
 		return _get_data()[p_index];
 		return _get_data()[p_index];
 	}
 	}

+ 2 - 4
core/vmap.h

@@ -180,10 +180,8 @@ public:
 	inline const V &operator[](const T &p_key) const {
 	inline const V &operator[](const T &p_key) const {
 
 
 		int pos = _find_exact(p_key);
 		int pos = _find_exact(p_key);
-		if (pos < 0) {
-			const T &aux = *((T *)0); //nullreturn
-			ERR_FAIL_COND_V(pos < 1, aux);
-		}
+
+		PRAY_COND(pos < 0, V);
 
 
 		return _data[pos].value;
 		return _data[pos].value;
 	}
 	}