Skip to content

Commit 4d3392d

Browse files
authored
Merge pull request libgit2#5214 from pks-t/pks/diff-iterator-allocation-fixes
Memory allocation fixes for diff generator
2 parents 39028eb + 699de9c commit 4d3392d

File tree

2 files changed

+130
-79
lines changed

2 files changed

+130
-79
lines changed

src/diff_generate.c

Lines changed: 122 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,29 +1262,31 @@ int git_diff__from_iterators(
12621262
return error;
12631263
}
12641264

1265-
#define DIFF_FROM_ITERATORS(MAKE_FIRST, FLAGS_FIRST, MAKE_SECOND, FLAGS_SECOND) do { \
1266-
git_iterator *a = NULL, *b = NULL; \
1267-
char *pfx = (opts && !(opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) ? \
1268-
git_pathspec_prefix(&opts->pathspec) : NULL; \
1269-
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT, \
1270-
b_opts = GIT_ITERATOR_OPTIONS_INIT; \
1271-
a_opts.flags = FLAGS_FIRST; \
1272-
a_opts.start = pfx; \
1273-
a_opts.end = pfx; \
1274-
b_opts.flags = FLAGS_SECOND; \
1275-
b_opts.start = pfx; \
1276-
b_opts.end = pfx; \
1277-
GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
1278-
if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) { \
1279-
a_opts.pathlist.strings = opts->pathspec.strings; \
1280-
a_opts.pathlist.count = opts->pathspec.count; \
1281-
b_opts.pathlist.strings = opts->pathspec.strings; \
1282-
b_opts.pathlist.count = opts->pathspec.count; \
1283-
} \
1284-
if (!error && !(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
1285-
error = git_diff__from_iterators(&diff, repo, a, b, opts); \
1286-
git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
1287-
} while (0)
1265+
static int diff_prepare_iterator_opts(char **prefix, git_iterator_options *a, int aflags,
1266+
git_iterator_options *b, int bflags,
1267+
const git_diff_options *opts)
1268+
{
1269+
GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
1270+
1271+
*prefix = NULL;
1272+
1273+
if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) {
1274+
a->pathlist.strings = opts->pathspec.strings;
1275+
a->pathlist.count = opts->pathspec.count;
1276+
b->pathlist.strings = opts->pathspec.strings;
1277+
b->pathlist.count = opts->pathspec.count;
1278+
} else if (opts) {
1279+
*prefix = git_pathspec_prefix(&opts->pathspec);
1280+
GIT_ERROR_CHECK_ALLOC(prefix);
1281+
}
1282+
1283+
a->flags = aflags;
1284+
b->flags = bflags;
1285+
a->start = b->start = *prefix;
1286+
a->end = b->end = *prefix;
1287+
1288+
return 0;
1289+
}
12881290

12891291
int git_diff_tree_to_tree(
12901292
git_diff **out,
@@ -1293,8 +1295,12 @@ int git_diff_tree_to_tree(
12931295
git_tree *new_tree,
12941296
const git_diff_options *opts)
12951297
{
1296-
git_diff *diff = NULL;
12971298
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
1299+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1300+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1301+
git_iterator *a = NULL, *b = NULL;
1302+
git_diff *diff = NULL;
1303+
char *prefix = NULL;
12981304
int error = 0;
12991305

13001306
assert(out && repo);
@@ -1308,13 +1314,19 @@ int git_diff_tree_to_tree(
13081314
if (opts && (opts->flags & GIT_DIFF_IGNORE_CASE) != 0)
13091315
iflag = GIT_ITERATOR_IGNORE_CASE;
13101316

1311-
DIFF_FROM_ITERATORS(
1312-
git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1313-
git_iterator_for_tree(&b, new_tree, &b_opts), iflag
1314-
);
1317+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
1318+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1319+
(error = git_iterator_for_tree(&b, new_tree, &b_opts)) < 0 ||
1320+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1321+
goto out;
13151322

1316-
if (!error)
1317-
*out = diff;
1323+
*out = diff;
1324+
diff = NULL;
1325+
out:
1326+
git_iterator_free(a);
1327+
git_iterator_free(b);
1328+
git_diff_free(diff);
1329+
git__free(prefix);
13181330

13191331
return error;
13201332
}
@@ -1337,9 +1349,13 @@ int git_diff_tree_to_index(
13371349
git_index *index,
13381350
const git_diff_options *opts)
13391351
{
1340-
git_diff *diff = NULL;
13411352
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE |
13421353
GIT_ITERATOR_INCLUDE_CONFLICTS;
1354+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1355+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1356+
git_iterator *a = NULL, *b = NULL;
1357+
git_diff *diff = NULL;
1358+
char *prefix = NULL;
13431359
bool index_ignore_case = false;
13441360
int error = 0;
13451361

@@ -1352,17 +1368,23 @@ int git_diff_tree_to_index(
13521368

13531369
index_ignore_case = index->ignore_case;
13541370

1355-
DIFF_FROM_ITERATORS(
1356-
git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1357-
git_iterator_for_index(&b, repo, index, &b_opts), iflag
1358-
);
1371+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
1372+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1373+
(error = git_iterator_for_index(&b, repo, index, &b_opts)) < 0 ||
1374+
(error = git_diff__from_iterators(&diff, repo, a, b, opts) < 0))
1375+
goto out;
13591376

13601377
/* if index is in case-insensitive order, re-sort deltas to match */
1361-
if (!error && index_ignore_case)
1378+
if (index_ignore_case)
13621379
git_diff__set_ignore_case(diff, true);
13631380

1364-
if (!error)
1365-
*out = diff;
1381+
*out = diff;
1382+
diff = NULL;
1383+
out:
1384+
git_iterator_free(a);
1385+
git_iterator_free(b);
1386+
git_diff_free(diff);
1387+
git__free(prefix);
13661388

13671389
return error;
13681390
}
@@ -1373,7 +1395,11 @@ int git_diff_index_to_workdir(
13731395
git_index *index,
13741396
const git_diff_options *opts)
13751397
{
1398+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1399+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1400+
git_iterator *a = NULL, *b = NULL;
13761401
git_diff *diff = NULL;
1402+
char *prefix = NULL;
13771403
int error = 0;
13781404

13791405
assert(out && repo);
@@ -1383,20 +1409,24 @@ int git_diff_index_to_workdir(
13831409
if (!index && (error = diff_load_index(&index, repo)) < 0)
13841410
return error;
13851411

1386-
DIFF_FROM_ITERATORS(
1387-
git_iterator_for_index(&a, repo, index, &a_opts),
1388-
GIT_ITERATOR_INCLUDE_CONFLICTS,
1389-
1390-
git_iterator_for_workdir(&b, repo, index, NULL, &b_opts),
1391-
GIT_ITERATOR_DONT_AUTOEXPAND
1392-
);
1393-
1394-
if (!error && (diff->opts.flags & GIT_DIFF_UPDATE_INDEX) != 0 &&
1395-
((git_diff_generated *)diff)->index_updated)
1396-
error = git_index_write(index);
1397-
1398-
if (!error)
1399-
*out = diff;
1412+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_INCLUDE_CONFLICTS,
1413+
&b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts)) < 0 ||
1414+
(error = git_iterator_for_index(&a, repo, index, &a_opts)) < 0 ||
1415+
(error = git_iterator_for_workdir(&b, repo, index, NULL, &b_opts)) < 0 ||
1416+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1417+
goto out;
1418+
1419+
if ((diff->opts.flags & GIT_DIFF_UPDATE_INDEX) && ((git_diff_generated *)diff)->index_updated)
1420+
if ((error = git_index_write(index)) < 0)
1421+
goto out;
1422+
1423+
*out = diff;
1424+
diff = NULL;
1425+
out:
1426+
git_iterator_free(a);
1427+
git_iterator_free(b);
1428+
git_diff_free(diff);
1429+
git__free(prefix);
14001430

14011431
return error;
14021432
}
@@ -1407,24 +1437,33 @@ int git_diff_tree_to_workdir(
14071437
git_tree *old_tree,
14081438
const git_diff_options *opts)
14091439
{
1440+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1441+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1442+
git_iterator *a = NULL, *b = NULL;
14101443
git_diff *diff = NULL;
1444+
char *prefix = NULL;
14111445
git_index *index;
1412-
int error = 0;
1446+
int error;
14131447

14141448
assert(out && repo);
14151449

14161450
*out = NULL;
14171451

1418-
if ((error = git_repository_index__weakptr(&index, repo)))
1419-
return error;
1420-
1421-
DIFF_FROM_ITERATORS(
1422-
git_iterator_for_tree(&a, old_tree, &a_opts), 0,
1423-
git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts), GIT_ITERATOR_DONT_AUTOEXPAND
1424-
);
1425-
1426-
if (!error)
1427-
*out = diff;
1452+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, 0,
1453+
&b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts) < 0) ||
1454+
(error = git_repository_index__weakptr(&index, repo)) < 0 ||
1455+
(error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
1456+
(error = git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts)) < 0 ||
1457+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1458+
goto out;
1459+
1460+
*out = diff;
1461+
diff = NULL;
1462+
out:
1463+
git_iterator_free(a);
1464+
git_iterator_free(b);
1465+
git_diff_free(diff);
1466+
git__free(prefix);
14281467

14291468
return error;
14301469
}
@@ -1468,24 +1507,35 @@ int git_diff_index_to_index(
14681507
git_index *new_index,
14691508
const git_diff_options *opts)
14701509
{
1471-
git_diff *diff;
1472-
int error = 0;
1510+
git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
1511+
b_opts = GIT_ITERATOR_OPTIONS_INIT;
1512+
git_iterator *a = NULL, *b = NULL;
1513+
git_diff *diff = NULL;
1514+
char *prefix = NULL;
1515+
int error;
14731516

14741517
assert(out && old_index && new_index);
14751518

14761519
*out = NULL;
14771520

1478-
DIFF_FROM_ITERATORS(
1479-
git_iterator_for_index(&a, repo, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
1480-
git_iterator_for_index(&b, repo, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
1481-
);
1521+
if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_DONT_IGNORE_CASE,
1522+
&b_opts, GIT_ITERATOR_DONT_IGNORE_CASE, opts) < 0) ||
1523+
(error = git_iterator_for_index(&a, repo, old_index, &a_opts)) < 0 ||
1524+
(error = git_iterator_for_index(&b, repo, new_index, &b_opts)) < 0 ||
1525+
(error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
1526+
goto out;
14821527

14831528
/* if index is in case-insensitive order, re-sort deltas to match */
1484-
if (!error && (old_index->ignore_case || new_index->ignore_case))
1529+
if (old_index->ignore_case || new_index->ignore_case)
14851530
git_diff__set_ignore_case(diff, true);
14861531

1487-
if (!error)
1488-
*out = diff;
1532+
*out = diff;
1533+
diff = NULL;
1534+
out:
1535+
git_iterator_free(a);
1536+
git_iterator_free(b);
1537+
git_diff_free(diff);
1538+
git__free(prefix);
14891539

14901540
return error;
14911541
}

src/iterator.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -543,28 +543,29 @@ static int tree_iterator_frame_init(
543543
new_frame = git_array_alloc(iter->frames);
544544
GIT_ERROR_CHECK_ALLOC(new_frame);
545545

546-
memset(new_frame, 0, sizeof(tree_iterator_frame));
547-
548546
if ((error = git_tree_dup(&dup, tree)) < 0)
549547
goto done;
550548

551549
memset(new_frame, 0x0, sizeof(tree_iterator_frame));
552550
new_frame->tree = dup;
553551

554552
if (frame_entry &&
555-
(error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
553+
(error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
556554
goto done;
557555

558556
cmp = iterator__ignore_case(&iter->base) ?
559557
tree_iterator_entry_sort_icase : NULL;
560558

561-
if ((error = git_vector_init(
562-
&new_frame->entries, dup->entries.size, cmp)) < 0)
559+
if ((error = git_vector_init(&new_frame->entries,
560+
dup->entries.size, cmp)) < 0)
563561
goto done;
564562

565563
git_array_foreach(dup->entries, i, tree_entry) {
566-
new_entry = git_pool_malloc(&iter->entry_pool, 1);
567-
GIT_ERROR_CHECK_ALLOC(new_entry);
564+
if ((new_entry = git_pool_malloc(&iter->entry_pool, 1)) == NULL) {
565+
git_error_set_oom();
566+
error = -1;
567+
goto done;
568+
}
568569

569570
new_entry->tree_entry = tree_entry;
570571
new_entry->parent_path = new_frame->path.ptr;

0 commit comments

Comments
 (0)