Skip to content

Commit d476d02

Browse files
authored
Merge pull request libgit2#4196 from pks-t/pks/filter-segfault
filter: only close filter if it's been initialized correctly
2 parents a5781e2 + cf07db2 commit d476d02

File tree

4 files changed

+78
-13
lines changed

4 files changed

+78
-13
lines changed

src/filter.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -911,14 +911,19 @@ static int stream_list_init(
911911
last_stream);
912912

913913
if (error < 0)
914-
return error;
914+
goto out;
915915

916916
git_vector_insert(streams, filter_stream);
917917
last_stream = filter_stream;
918918
}
919919

920-
*out = last_stream;
921-
return 0;
920+
out:
921+
if (error)
922+
last_stream->close(last_stream);
923+
else
924+
*out = last_stream;
925+
926+
return error;
922927
}
923928

924929
void stream_list_free(git_vector *streams)
@@ -943,12 +948,13 @@ int git_filter_list_stream_file(
943948
git_vector filter_streams = GIT_VECTOR_INIT;
944949
git_writestream *stream_start;
945950
ssize_t readlen;
946-
int fd = -1, error;
951+
int fd = -1, error, initialized = 0;
947952

948953
if ((error = stream_list_init(
949954
&stream_start, &filter_streams, filters, target)) < 0 ||
950955
(error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0)
951956
goto done;
957+
initialized = 1;
952958

953959
if ((fd = git_futils_open_ro(abspath.ptr)) < 0) {
954960
error = fd;
@@ -960,13 +966,13 @@ int git_filter_list_stream_file(
960966
goto done;
961967
}
962968

963-
if (!readlen)
964-
error = stream_start->close(stream_start);
965-
else if (readlen < 0)
969+
if (readlen < 0)
966970
error = readlen;
967971

968-
969972
done:
973+
if (initialized)
974+
error |= stream_start->close(stream_start);
975+
970976
if (fd >= 0)
971977
p_close(fd);
972978
stream_list_free(&filter_streams);
@@ -981,20 +987,24 @@ int git_filter_list_stream_data(
981987
{
982988
git_vector filter_streams = GIT_VECTOR_INIT;
983989
git_writestream *stream_start;
984-
int error = 0, close_error;
990+
int error, initialized = 0;
985991

986992
git_buf_sanitize(data);
987993

988994
if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0)
989995
goto out;
996+
initialized = 1;
990997

991-
error = stream_start->write(stream_start, data->ptr, data->size);
998+
if ((error = stream_start->write(
999+
stream_start, data->ptr, data->size)) < 0)
1000+
goto out;
9921001

9931002
out:
994-
close_error = stream_start->close(stream_start);
1003+
if (initialized)
1004+
error |= stream_start->close(stream_start);
1005+
9951006
stream_list_free(&filter_streams);
996-
/* propagate the stream init or write error */
997-
return error < 0 ? error : close_error;
1007+
return error;
9981008
}
9991009

10001010
int git_filter_list_stream_blob(

tests/filter/custom.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ void test_filter_custom__initialize(void)
5555
"hero* bitflip reverse\n"
5656
"herofile text\n"
5757
"heroflip -reverse binary\n"
58+
"villain erroneous\n"
5859
"*.bin binary\n");
5960
}
6061

@@ -82,6 +83,11 @@ static void register_custom_filters(void)
8283
create_reverse_filter("+prereverse"),
8384
GIT_FILTER_DRIVER_PRIORITY));
8485

86+
cl_git_pass(git_filter_register(
87+
"erroneous",
88+
create_erroneous_filter("+erroneous"),
89+
GIT_FILTER_DRIVER_PRIORITY));
90+
8591
filters_registered = 1;
8692
}
8793
}
@@ -235,3 +241,18 @@ void test_filter_custom__filter_registry_failure_cases(void)
235241
cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT));
236242
cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter"));
237243
}
244+
245+
void test_filter_custom__erroneous_filter_fails(void)
246+
{
247+
git_filter_list *filters;
248+
git_buf out = GIT_BUF_INIT;
249+
git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data));
250+
251+
cl_git_pass(git_filter_list_load(
252+
&filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0));
253+
254+
cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in));
255+
256+
git_filter_list_free(filters);
257+
git_buf_free(&out);
258+
}

tests/filter/custom_helpers.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,36 @@ git_filter *create_reverse_filter(const char *attrs)
106106

107107
return filter;
108108
}
109+
110+
int erroneous_filter_stream(
111+
git_writestream **out,
112+
git_filter *self,
113+
void **payload,
114+
const git_filter_source *src,
115+
git_writestream *next)
116+
{
117+
GIT_UNUSED(out);
118+
GIT_UNUSED(self);
119+
GIT_UNUSED(payload);
120+
GIT_UNUSED(src);
121+
GIT_UNUSED(next);
122+
return -1;
123+
}
124+
125+
static void erroneous_filter_free(git_filter *f)
126+
{
127+
git__free(f);
128+
}
129+
130+
git_filter *create_erroneous_filter(const char *attrs)
131+
{
132+
git_filter *filter = git__calloc(1, sizeof(git_filter));
133+
cl_assert(filter);
134+
135+
filter->version = GIT_FILTER_VERSION;
136+
filter->attributes = attrs;
137+
filter->stream = erroneous_filter_stream;
138+
filter->shutdown = erroneous_filter_free;
139+
140+
return filter;
141+
}

tests/filter/custom_helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
extern git_filter *create_bitflip_filter(void);
44
extern git_filter *create_reverse_filter(const char *attr);
5+
extern git_filter *create_erroneous_filter(const char *attr);
56

67
extern int bitflip_filter_apply(
78
git_filter *self,

0 commit comments

Comments
 (0)