Commit ef4857c2 by Edward Thomson

errors: tighten up git_error_state OOMs a bit more

When an error state is an OOM, make sure that we treat is specially
and do not try to free it.
parent 854b701c
...@@ -440,14 +440,14 @@ int git_clone( ...@@ -440,14 +440,14 @@ int git_clone(
if (error != 0) { if (error != 0) {
git_error_state last_error = {0}; git_error_state last_error = {0};
giterr_capture(&last_error, error); giterr_state_capture(&last_error, error);
git_repository_free(repo); git_repository_free(repo);
repo = NULL; repo = NULL;
(void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags);
giterr_restore(&last_error); giterr_state_restore(&last_error);
} }
*out = repo; *out = repo;
......
...@@ -142,19 +142,24 @@ void giterr_system_set(int code); ...@@ -142,19 +142,24 @@ void giterr_system_set(int code);
*/ */
typedef struct { typedef struct {
int error_code; int error_code;
unsigned int oom : 1;
git_error error_msg; git_error error_msg;
} git_error_state; } git_error_state;
/** /**
* Capture current error state to restore later, returning error code. * Capture current error state to restore later, returning error code.
* If `error_code` is zero, this does nothing and returns zero. * If `error_code` is zero, this does not clear the current error state.
* You must either restore this error state, or free it.
*/ */
int giterr_capture(git_error_state *state, int error_code); extern int giterr_state_capture(git_error_state *state, int error_code);
/** /**
* Restore error state to a previous value, returning saved error code. * Restore error state to a previous value, returning saved error code.
*/ */
int giterr_restore(git_error_state *state); extern int giterr_state_restore(git_error_state *state);
/** Free an error state. */
extern void giterr_state_free(git_error_state *state);
/** /**
* Check a versioned structure for validity * Check a versioned structure for validity
......
...@@ -131,53 +131,65 @@ void giterr_clear(void) ...@@ -131,53 +131,65 @@ void giterr_clear(void)
#endif #endif
} }
static int giterr_detach(git_error *cpy) const git_error *giterr_last(void)
{
return GIT_GLOBAL->last_error;
}
int giterr_state_capture(git_error_state *state, int error_code)
{ {
git_error *error = GIT_GLOBAL->last_error; git_error *error = GIT_GLOBAL->last_error;
git_buf *buf = &GIT_GLOBAL->error_buf; git_buf *error_buf = &GIT_GLOBAL->error_buf;
memset(state, 0, sizeof(git_error_state));
assert(cpy); if (!error_code)
return 0;
if (!error) state->error_code = error_code;
return -1; state->oom = (error == &g_git_oom_error);
cpy->message = git_buf_detach(buf); if (error) {
cpy->klass = error->klass; state->error_msg.klass = error->klass;
if (error != &g_git_oom_error) { if (state->oom)
error->message = NULL; state->error_msg.message = g_git_oom_error.message;
else
state->error_msg.message = git_buf_detach(error_buf);
} }
giterr_clear();
return 0; giterr_clear();
return error_code;
} }
const git_error *giterr_last(void) int giterr_state_restore(git_error_state *state)
{ {
return GIT_GLOBAL->last_error; int ret = 0;
}
int giterr_capture(git_error_state *state, int error_code) giterr_clear();
{
state->error_code = error_code;
if (error_code)
giterr_detach(&state->error_msg);
return error_code;
}
int giterr_restore(git_error_state *state) if (state && state->error_msg.message) {
{ if (state->oom)
if (state && state->error_code && state->error_msg.message) {
if (state->error_msg.message == g_git_oom_error.message) {
giterr_set_oom(); giterr_set_oom();
} else { else
set_error(state->error_msg.klass, state->error_msg.message); set_error(state->error_msg.klass, state->error_msg.message);
ret = state->error_code;
memset(state, 0, sizeof(git_error_state));
} }
}
else
giterr_clear();
return state ? state->error_code : 0; return ret;
}
void giterr_state_free(git_error_state *state)
{
if (!state)
return;
if (!state->oom)
git__free(state->error_msg.message);
memset(state, 0, sizeof(git_error_state));
} }
int giterr_system_last(void) int giterr_system_last(void)
......
...@@ -1286,13 +1286,13 @@ int git_index_add_bypath(git_index *index, const char *path) ...@@ -1286,13 +1286,13 @@ int git_index_add_bypath(git_index *index, const char *path)
git_submodule *sm; git_submodule *sm;
git_error_state err; git_error_state err;
giterr_capture(&err, ret); giterr_state_capture(&err, ret);
ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
if (ret == GIT_ENOTFOUND) if (ret == GIT_ENOTFOUND)
return giterr_restore(&err); return giterr_state_restore(&err);
git__free(err.error_msg.message); giterr_state_free(&err);
/* /*
* EEXISTS means that there is a repository at that path, but it's not known * EEXISTS means that there is a repository at that path, but it's not known
......
...@@ -1120,7 +1120,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ...@@ -1120,7 +1120,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
if (error < 0) { if (error < 0) {
git_error_state last_error = { 0 }; git_error_state last_error = { 0 };
giterr_capture(&last_error, error); giterr_state_capture(&last_error, error);
/* these callbacks may clear the error message */ /* these callbacks may clear the error message */
fs_iterator__free_frame(ff); fs_iterator__free_frame(ff);
...@@ -1128,7 +1128,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ...@@ -1128,7 +1128,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
/* next time return value we skipped to */ /* next time return value we skipped to */
fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
return giterr_restore(&last_error); return giterr_state_restore(&last_error);
} }
if (ff->entries.length == 0) { if (ff->entries.length == 0) {
......
...@@ -93,23 +93,44 @@ void test_core_errors__restore(void) ...@@ -93,23 +93,44 @@ void test_core_errors__restore(void)
giterr_clear(); giterr_clear();
cl_assert(giterr_last() == NULL); cl_assert(giterr_last() == NULL);
cl_assert_equal_i(0, giterr_capture(&err_state, 0)); cl_assert_equal_i(0, giterr_state_capture(&err_state, 0));
memset(&err_state, 0x0, sizeof(git_error_state)); memset(&err_state, 0x0, sizeof(git_error_state));
giterr_set(42, "Foo: %s", "bar"); giterr_set(42, "Foo: %s", "bar");
cl_assert_equal_i(-1, giterr_capture(&err_state, -1)); cl_assert_equal_i(-1, giterr_state_capture(&err_state, -1));
cl_assert(giterr_last() == NULL); cl_assert(giterr_last() == NULL);
giterr_set(99, "Bar: %s", "foo"); giterr_set(99, "Bar: %s", "foo");
giterr_restore(&err_state); giterr_state_restore(&err_state);
cl_assert_equal_i(42, giterr_last()->klass); cl_assert_equal_i(42, giterr_last()->klass);
cl_assert_equal_s("Foo: bar", giterr_last()->message); cl_assert_equal_s("Foo: bar", giterr_last()->message);
} }
void test_core_errors__free_state(void)
{
git_error_state err_state = {0};
giterr_clear();
giterr_set(42, "Foo: %s", "bar");
cl_assert_equal_i(-1, giterr_state_capture(&err_state, -1));
giterr_set(99, "Bar: %s", "foo");
giterr_state_free(&err_state);
cl_assert_equal_i(99, giterr_last()->klass);
cl_assert_equal_s("Bar: foo", giterr_last()->message);
giterr_state_restore(&err_state);
cl_assert(giterr_last() == NULL);
}
void test_core_errors__restore_oom(void) void test_core_errors__restore_oom(void)
{ {
git_error_state err_state = {0}; git_error_state err_state = {0};
...@@ -121,11 +142,13 @@ void test_core_errors__restore_oom(void) ...@@ -121,11 +142,13 @@ void test_core_errors__restore_oom(void)
oom_error = giterr_last(); oom_error = giterr_last();
cl_assert(oom_error); cl_assert(oom_error);
cl_assert_equal_i(-1, giterr_capture(&err_state, -1)); cl_assert_equal_i(-1, giterr_state_capture(&err_state, -1));
cl_assert(giterr_last() == NULL); cl_assert(giterr_last() == NULL);
cl_assert_equal_i(GITERR_NOMEMORY, err_state.error_msg.klass);
cl_assert_equal_s("Out of memory", err_state.error_msg.message);
giterr_restore(&err_state); giterr_state_restore(&err_state);
cl_assert(giterr_last()->klass == GITERR_NOMEMORY); cl_assert(giterr_last()->klass == GITERR_NOMEMORY);
cl_assert_(giterr_last() == oom_error, "static oom error not restored"); cl_assert_(giterr_last() == oom_error, "static oom error not restored");
......
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