Skip to content

Commit 905e4d1

Browse files
authored
Merge pull request libgit2#5722 from libgit2/ethomson/tlsdata_fail
Thread-local storage: handle failure cases
2 parents 3a4e08a + ebf2991 commit 905e4d1

File tree

7 files changed

+118
-33
lines changed

7 files changed

+118
-33
lines changed

include/git2/oid.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ GIT_EXTERN(int) git_oid_pathfmt(char *out, const git_oid *id);
225225
* concurrent calls of the function.
226226
*
227227
* @param oid The oid structure to format
228-
* @return the c-string
228+
* @return the c-string or NULL on failure
229229
*/
230230
GIT_EXTERN(char *) git_oid_tostr_s(const git_oid *oid);
231231

src/libgit2/errors.c

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,51 @@
1616
* New error handling
1717
********************************************/
1818

19-
static git_error g_git_oom_error = {
19+
static git_error oom_error = {
2020
"Out of memory",
2121
GIT_ERROR_NOMEMORY
2222
};
2323

24-
static git_error g_git_uninitialized_error = {
24+
static git_error uninitialized_error = {
2525
"libgit2 has not been initialized; you must call git_libgit2_init",
2626
GIT_ERROR_INVALID
2727
};
2828

29+
static git_error tlsdata_error = {
30+
"thread-local data initialization failure",
31+
GIT_ERROR
32+
};
33+
2934
static void set_error_from_buffer(int error_class)
3035
{
31-
git_error *error = &GIT_THREADSTATE->error_t;
32-
git_str *buf = &GIT_THREADSTATE->error_buf;
36+
git_threadstate *threadstate = git_threadstate_get();
37+
git_error *error;
38+
git_str *buf;
39+
40+
if (!threadstate)
41+
return;
42+
43+
error = &threadstate->error_t;
44+
buf = &threadstate->error_buf;
3345

3446
error->message = buf->ptr;
3547
error->klass = error_class;
3648

37-
GIT_THREADSTATE->last_error = error;
49+
threadstate->last_error = error;
3850
}
3951

4052
static void set_error(int error_class, char *string)
4153
{
42-
git_str *buf = &GIT_THREADSTATE->error_buf;
54+
git_threadstate *threadstate = git_threadstate_get();
55+
git_str *buf;
56+
57+
if (!threadstate)
58+
return;
59+
60+
buf = &threadstate->error_buf;
4361

4462
git_str_clear(buf);
63+
4564
if (string) {
4665
git_str_puts(buf, string);
4766
git__free(string);
@@ -52,7 +71,12 @@ static void set_error(int error_class, char *string)
5271

5372
void git_error_set_oom(void)
5473
{
55-
GIT_THREADSTATE->last_error = &g_git_oom_error;
74+
git_threadstate *threadstate = git_threadstate_get();
75+
76+
if (!threadstate)
77+
return;
78+
79+
threadstate->last_error = &oom_error;
5680
}
5781

5882
void git_error_set(int error_class, const char *fmt, ...)
@@ -69,10 +93,18 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
6993
#ifdef GIT_WIN32
7094
DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
7195
#endif
96+
97+
git_threadstate *threadstate = git_threadstate_get();
7298
int error_code = (error_class == GIT_ERROR_OS) ? errno : 0;
73-
git_str *buf = &GIT_THREADSTATE->error_buf;
99+
git_str *buf;
100+
101+
if (!threadstate)
102+
return;
103+
104+
buf = &threadstate->error_buf;
74105

75106
git_str_clear(buf);
107+
76108
if (fmt) {
77109
git_str_vprintf(buf, fmt, ap);
78110
if (error_class == GIT_ERROR_OS)
@@ -81,7 +113,7 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
81113

82114
if (error_class == GIT_ERROR_OS) {
83115
#ifdef GIT_WIN32
84-
char * win32_error = git_win32_get_error_message(win32_error_code);
116+
char *win32_error = git_win32_get_error_message(win32_error_code);
85117
if (win32_error) {
86118
git_str_puts(buf, win32_error);
87119
git__free(win32_error);
@@ -103,10 +135,16 @@ void git_error_vset(int error_class, const char *fmt, va_list ap)
103135

104136
int git_error_set_str(int error_class, const char *string)
105137
{
106-
git_str *buf = &GIT_THREADSTATE->error_buf;
138+
git_threadstate *threadstate = git_threadstate_get();
139+
git_str *buf;
107140

108141
GIT_ASSERT_ARG(string);
109142

143+
if (!threadstate)
144+
return -1;
145+
146+
buf = &threadstate->error_buf;
147+
110148
git_str_clear(buf);
111149
git_str_puts(buf, string);
112150

@@ -119,9 +157,14 @@ int git_error_set_str(int error_class, const char *string)
119157

120158
void git_error_clear(void)
121159
{
122-
if (GIT_THREADSTATE->last_error != NULL) {
160+
git_threadstate *threadstate = git_threadstate_get();
161+
162+
if (!threadstate)
163+
return;
164+
165+
if (threadstate->last_error != NULL) {
123166
set_error(0, NULL);
124-
GIT_THREADSTATE->last_error = NULL;
167+
threadstate->last_error = NULL;
125168
}
126169

127170
errno = 0;
@@ -132,31 +175,43 @@ void git_error_clear(void)
132175

133176
const git_error *git_error_last(void)
134177
{
178+
git_threadstate *threadstate;
179+
135180
/* If the library is not initialized, return a static error. */
136181
if (!git_libgit2_init_count())
137-
return &g_git_uninitialized_error;
182+
return &uninitialized_error;
183+
184+
if ((threadstate = git_threadstate_get()) == NULL)
185+
return &tlsdata_error;
138186

139-
return GIT_THREADSTATE->last_error;
187+
return threadstate->last_error;
140188
}
141189

142190
int git_error_state_capture(git_error_state *state, int error_code)
143191
{
144-
git_error *error = GIT_THREADSTATE->last_error;
145-
git_str *error_buf = &GIT_THREADSTATE->error_buf;
192+
git_threadstate *threadstate = git_threadstate_get();
193+
git_error *error;
194+
git_str *error_buf;
195+
196+
if (!threadstate)
197+
return -1;
198+
199+
error = threadstate->last_error;
200+
error_buf = &threadstate->error_buf;
146201

147202
memset(state, 0, sizeof(git_error_state));
148203

149204
if (!error_code)
150205
return 0;
151206

152207
state->error_code = error_code;
153-
state->oom = (error == &g_git_oom_error);
208+
state->oom = (error == &oom_error);
154209

155210
if (error) {
156211
state->error_msg.klass = error->klass;
157212

158213
if (state->oom)
159-
state->error_msg.message = g_git_oom_error.message;
214+
state->error_msg.message = oom_error.message;
160215
else
161216
state->error_msg.message = git_str_detach(error_buf);
162217
}

src/libgit2/indexer.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,13 @@ static int store_object(git_indexer *idx)
519519
pentry->offset = entry_start;
520520

521521
if (git_oidmap_exists(idx->pack->idx_cache, &pentry->id)) {
522-
git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->id));
522+
const char *idstr = git_oid_tostr_s(&pentry->id);
523+
524+
if (!idstr)
525+
git_error_set(GIT_ERROR_INDEXER, "failed to parse object id");
526+
else
527+
git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", idstr);
528+
523529
git__free(pentry);
524530
goto on_error;
525531
}

src/libgit2/odb.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,11 +1494,16 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
14941494

14951495
if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
14961496
git_str buf = GIT_STR_INIT;
1497+
const char *idstr;
14971498

1498-
git_str_printf(&buf, "multiple matches for prefix: %s",
1499-
git_oid_tostr_s(&full_oid));
1500-
git_str_printf(&buf, " %s",
1501-
git_oid_tostr_s(&found_full_oid));
1499+
if ((idstr = git_oid_tostr_s(&full_oid)) == NULL) {
1500+
git_str_puts(&buf, "failed to parse object id");
1501+
} else {
1502+
git_str_printf(&buf, "multiple matches for prefix: %s", idstr);
1503+
1504+
if ((idstr = git_oid_tostr_s(&found_full_oid)) != NULL)
1505+
git_str_printf(&buf, " %s", idstr);
1506+
}
15021507

15031508
error = git_odb__error_ambiguous(buf.ptr);
15041509
git_str_dispose(&buf);

src/libgit2/oid.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,13 @@ int git_oid_pathfmt(char *str, const git_oid *oid)
155155

156156
char *git_oid_tostr_s(const git_oid *oid)
157157
{
158-
char *str = GIT_THREADSTATE->oid_fmt;
158+
git_threadstate *threadstate = git_threadstate_get();
159+
char *str;
160+
161+
if (!threadstate)
162+
return NULL;
163+
164+
str = threadstate->oid_fmt;
159165
git_oid_nfmt(str, git_oid_hexsize(git_oid_type(oid)) + 1, oid);
160166
return str;
161167
}

src/libgit2/repository.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,12 +3422,18 @@ int git_repository_hashfile(
34223422

34233423
static int checkout_message(git_str *out, git_reference *old, const char *new)
34243424
{
3425+
const char *idstr;
3426+
34253427
git_str_puts(out, "checkout: moving from ");
34263428

3427-
if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC)
3429+
if (git_reference_type(old) == GIT_REFERENCE_SYMBOLIC) {
34283430
git_str_puts(out, git_reference__shorthand(git_reference_symbolic_target(old)));
3429-
else
3430-
git_str_puts(out, git_oid_tostr_s(git_reference_target(old)));
3431+
} else {
3432+
if ((idstr = git_oid_tostr_s(git_reference_target(old))) == NULL)
3433+
return -1;
3434+
3435+
git_str_puts(out, idstr);
3436+
}
34313437

34323438
git_str_puts(out, " to ");
34333439

@@ -3463,8 +3469,11 @@ static int detach(git_repository *repo, const git_oid *id, const char *new)
34633469
if ((error = git_object_peel(&peeled, object, GIT_OBJECT_COMMIT)) < 0)
34643470
goto cleanup;
34653471

3466-
if (new == NULL)
3467-
new = git_oid_tostr_s(git_object_id(peeled));
3472+
if (new == NULL &&
3473+
(new = git_oid_tostr_s(git_object_id(peeled))) == NULL) {
3474+
error = -1;
3475+
goto cleanup;
3476+
}
34683477

34693478
if ((error = checkout_message(&log_message, current, new)) < 0)
34703479
goto cleanup;
@@ -3552,6 +3561,7 @@ int git_repository_detach_head(git_repository *repo)
35523561
git_reference *old_head = NULL, *new_head = NULL, *current = NULL;
35533562
git_object *object = NULL;
35543563
git_str log_message = GIT_STR_INIT;
3564+
const char *idstr;
35553565
int error;
35563566

35573567
GIT_ASSERT_ARG(repo);
@@ -3565,7 +3575,12 @@ int git_repository_detach_head(git_repository *repo)
35653575
if ((error = git_object_lookup(&object, repo, git_reference_target(old_head), GIT_OBJECT_COMMIT)) < 0)
35663576
goto cleanup;
35673577

3568-
if ((error = checkout_message(&log_message, current, git_oid_tostr_s(git_object_id(object)))) < 0)
3578+
if ((idstr = git_oid_tostr_s(git_object_id(object))) == NULL) {
3579+
error = -1;
3580+
goto cleanup;
3581+
}
3582+
3583+
if ((error = checkout_message(&log_message, current, idstr)) < 0)
35693584
goto cleanup;
35703585

35713586
error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head),

src/libgit2/threadstate.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,4 @@ typedef struct {
1919
extern int git_threadstate_global_init(void);
2020
extern git_threadstate *git_threadstate_get(void);
2121

22-
#define GIT_THREADSTATE (git_threadstate_get())
23-
2422
#endif

0 commit comments

Comments
 (0)