Commit 3618a2aa by Edward Thomson

errors: never return a NULL error

Callers want to be able to simply call `git_error_last()->message`,
not have to worry about whether `git_error_last()` returns NULL or not.
parent 9a9f2201
...@@ -118,10 +118,15 @@ typedef enum { ...@@ -118,10 +118,15 @@ typedef enum {
* Return the last `git_error` object that was generated for the * Return the last `git_error` object that was generated for the
* current thread. * current thread.
* *
* The default behaviour of this function is to return NULL if no previous error has occurred. * This function will never return NULL.
* However, libgit2's error strings are not cleared aggressively, so a prior *
* (unrelated) error may be returned. This can be avoided by only calling * Callers should not rely on this to determine whether an error has
* this function if the prior call to a libgit2 API returned an error. * occurred. For error checking, callers should examine the return
* codes of libgit2 functions.
*
* This call can only reliably report error messages when an error
* has occurred. (It may contain stale information if it is called
* after a different function that succeeds.)
* *
* @return A git_error object. * @return A git_error object.
*/ */
......
...@@ -28,7 +28,12 @@ static git_error uninitialized_error = { ...@@ -28,7 +28,12 @@ static git_error uninitialized_error = {
static git_error tlsdata_error = { static git_error tlsdata_error = {
"thread-local data initialization failure", "thread-local data initialization failure",
GIT_ERROR GIT_ERROR_THREAD
};
static git_error no_error = {
"no error",
GIT_ERROR_NONE
}; };
static void set_error_from_buffer(int error_class) static void set_error_from_buffer(int error_class)
...@@ -184,6 +189,9 @@ const git_error *git_error_last(void) ...@@ -184,6 +189,9 @@ const git_error *git_error_last(void)
if ((threadstate = git_threadstate_get()) == NULL) if ((threadstate = git_threadstate_get()) == NULL)
return &tlsdata_error; return &tlsdata_error;
if (!threadstate->last_error)
return &no_error;
return threadstate->last_error; return threadstate->last_error;
} }
......
...@@ -111,7 +111,7 @@ void test_config_include__missing(void) ...@@ -111,7 +111,7 @@ void test_config_include__missing(void)
git_error_clear(); git_error_clear();
cl_git_pass(git_config_open_ondisk(&cfg, "including")); cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_assert(git_error_last() == NULL); cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", buf.ptr); cl_assert_equal_s("baz", buf.ptr);
...@@ -126,7 +126,7 @@ void test_config_include__missing_homedir(void) ...@@ -126,7 +126,7 @@ void test_config_include__missing_homedir(void)
git_error_clear(); git_error_clear();
cl_git_pass(git_config_open_ondisk(&cfg, "including")); cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_assert(git_error_last() == NULL); cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", buf.ptr); cl_assert_equal_s("baz", buf.ptr);
......
...@@ -40,7 +40,7 @@ void test_grafts_shallow__clears_errors(void) ...@@ -40,7 +40,7 @@ void test_grafts_shallow__clears_errors(void)
{ {
g_repo = cl_git_sandbox_init("testrepo.git"); g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
cl_assert_equal_p(NULL, git_error_last()); cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
} }
void test_grafts_shallow__shallow_oids(void) void test_grafts_shallow__shallow_oids(void)
......
...@@ -35,5 +35,5 @@ void test_repo_shallow__clears_errors(void) ...@@ -35,5 +35,5 @@ void test_repo_shallow__clears_errors(void)
{ {
g_repo = cl_git_sandbox_init("testrepo.git"); g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo)); cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
cl_assert_equal_p(NULL, git_error_last()); cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
} }
...@@ -92,7 +92,8 @@ void test_assert__argument_with_void_return_type(void) ...@@ -92,7 +92,8 @@ void test_assert__argument_with_void_return_type(void)
git_error_clear(); git_error_clear();
cl_assert_equal_p(foo, fn_returns_string(foo)); cl_assert_equal_p(foo, fn_returns_string(foo));
cl_assert_equal_p(NULL, git_error_last()); cl_assert_equal_i(GIT_ERROR_NONE, git_error_last()->klass);
cl_assert_equal_s("no error", git_error_last()->message);
} }
void test_assert__internal(void) void test_assert__internal(void)
......
...@@ -5,7 +5,10 @@ void test_errors__public_api(void) ...@@ -5,7 +5,10 @@ void test_errors__public_api(void)
char *str_in_error; char *str_in_error;
git_error_clear(); git_error_clear();
cl_assert(git_error_last() == NULL);
cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_set_oom(); git_error_set_oom();
...@@ -23,7 +26,9 @@ void test_errors__public_api(void) ...@@ -23,7 +26,9 @@ void test_errors__public_api(void)
cl_assert(str_in_error != NULL); cl_assert(str_in_error != NULL);
git_error_clear(); git_error_clear();
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
} }
#include "common.h" #include "common.h"
...@@ -35,7 +40,9 @@ void test_errors__new_school(void) ...@@ -35,7 +40,9 @@ void test_errors__new_school(void)
char *str_in_error; char *str_in_error;
git_error_clear(); git_error_clear();
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_set_oom(); /* internal fn */ git_error_set_oom(); /* internal fn */
...@@ -53,7 +60,9 @@ void test_errors__new_school(void) ...@@ -53,7 +60,9 @@ void test_errors__new_school(void)
cl_assert(str_in_error != NULL); cl_assert(str_in_error != NULL);
git_error_clear(); git_error_clear();
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
do { do {
struct stat st; struct stat st;
...@@ -91,7 +100,9 @@ void test_errors__restore(void) ...@@ -91,7 +100,9 @@ void test_errors__restore(void)
git_error_state err_state = {0}; git_error_state err_state = {0};
git_error_clear(); git_error_clear();
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
cl_assert_equal_i(0, git_error_state_capture(&err_state, 0)); cl_assert_equal_i(0, git_error_state_capture(&err_state, 0));
...@@ -100,7 +111,9 @@ void test_errors__restore(void) ...@@ -100,7 +111,9 @@ void test_errors__restore(void)
git_error_set(42, "Foo: %s", "bar"); git_error_set(42, "Foo: %s", "bar");
cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1));
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_set(99, "Bar: %s", "foo"); git_error_set(99, "Bar: %s", "foo");
...@@ -128,7 +141,9 @@ void test_errors__free_state(void) ...@@ -128,7 +141,9 @@ void test_errors__free_state(void)
git_error_state_restore(&err_state); git_error_state_restore(&err_state);
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
} }
void test_errors__restore_oom(void) void test_errors__restore_oom(void)
...@@ -144,7 +159,9 @@ void test_errors__restore_oom(void) ...@@ -144,7 +159,9 @@ void test_errors__restore_oom(void)
cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1)); cl_assert_equal_i(-1, git_error_state_capture(&err_state, -1));
cl_assert(git_error_last() == NULL); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
cl_assert_equal_i(GIT_ERROR_NOMEMORY, err_state.error_msg.klass); cl_assert_equal_i(GIT_ERROR_NOMEMORY, err_state.error_msg.klass);
cl_assert_equal_s("Out of memory", err_state.error_msg.message); cl_assert_equal_s("Out of memory", err_state.error_msg.message);
...@@ -204,11 +221,15 @@ void test_errors__integer_overflow_sets_oom(void) ...@@ -204,11 +221,15 @@ void test_errors__integer_overflow_sets_oom(void)
git_error_clear(); git_error_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX-1, 1)); cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX-1, 1));
cl_assert_equal_p(NULL, git_error_last()); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_clear(); git_error_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, 42, 69)); cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, 42, 69));
cl_assert_equal_p(NULL, git_error_last()); cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GIT_ERROR_NONE);
cl_assert(strcmp(git_error_last()->message, "no error") == 0);
git_error_clear(); git_error_clear();
cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX)); cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment