Merge branch 'ab/cocci-unused'
Add Coccinelle rules to detect the pattern of initializing and then finalizing a structure without using it in between at all, which happens after code restructuring and the compilers fail to recognize as an unused variable. * ab/cocci-unused: cocci: generalize "unused" rule to cover more than "strbuf" cocci: add and apply a rule to find "unused" strbufs cocci: have "coccicheck{,-pending}" depend on "coccicheck-test" cocci: add a "coccicheck-test" target and test *.cocci rules Makefile & .gitignore: ignore & clean "git.res", not "*.res" Makefile: remove mandatory "spatch" arguments from SPATCH_FLAGS
This commit is contained in:
commit
7f8d098b1b
2
.gitignore
vendored
2
.gitignore
vendored
@ -185,6 +185,7 @@
|
||||
/git-worktree
|
||||
/git-write-tree
|
||||
/git-core-*/?*
|
||||
/git.res
|
||||
/gitweb/GITWEB-BUILD-OPTIONS
|
||||
/gitweb/gitweb.cgi
|
||||
/gitweb/static/gitweb.js
|
||||
@ -225,7 +226,6 @@
|
||||
*.hcc
|
||||
*.obj
|
||||
*.lib
|
||||
*.res
|
||||
*.sln
|
||||
*.sp
|
||||
*.suo
|
||||
|
28
Makefile
28
Makefile
@ -1292,7 +1292,7 @@ SANITIZE_ADDRESS =
|
||||
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
|
||||
# usually result in less CPU usage at the cost of higher peak memory.
|
||||
# Setting it to 0 will feed all files in a single spatch invocation.
|
||||
SPATCH_FLAGS = --all-includes --patch .
|
||||
SPATCH_FLAGS = --all-includes
|
||||
SPATCH_BATCH_SIZE = 1
|
||||
|
||||
include config.mak.uname
|
||||
@ -3126,6 +3126,8 @@ check: $(GENERATED_H)
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
|
||||
|
||||
%.cocci.patch: %.cocci $(COCCI_SOURCES)
|
||||
$(QUIET_SPATCH) \
|
||||
if test $(SPATCH_BATCH_SIZE) = 0; then \
|
||||
@ -3134,7 +3136,8 @@ check: $(GENERATED_H)
|
||||
limit='-n $(SPATCH_BATCH_SIZE)'; \
|
||||
fi; \
|
||||
if ! echo $(COCCI_SOURCES) | xargs $$limit \
|
||||
$(SPATCH) --sp-file $< $(SPATCH_FLAGS) \
|
||||
$(SPATCH) $(SPATCH_FLAGS) \
|
||||
--sp-file $< --patch . \
|
||||
>$@+ 2>$@.log; \
|
||||
then \
|
||||
cat $@.log; \
|
||||
@ -3145,9 +3148,27 @@ check: $(GENERATED_H)
|
||||
then \
|
||||
echo ' ' SPATCH result: $@; \
|
||||
fi
|
||||
|
||||
COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
|
||||
$(COCCI_TEST_RES_GEN): .build/%.res : %.c
|
||||
$(COCCI_TEST_RES_GEN): .build/%.res : %.res
|
||||
$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
|
||||
$(call mkdir_p_parent_template)
|
||||
$(QUIET_SPATCH_T)$(SPATCH) $(SPATCH_FLAGS) \
|
||||
--very-quiet --no-show-diff \
|
||||
--sp-file $< -o $@ \
|
||||
$(@:.build/%.res=%.c) && \
|
||||
cmp $(@:.build/%=%) $@ || \
|
||||
git -P diff --no-index $(@:.build/%=%) $@ 2>/dev/null; \
|
||||
|
||||
.PHONY: coccicheck-test
|
||||
coccicheck-test: $(COCCI_TEST_RES_GEN)
|
||||
|
||||
coccicheck: coccicheck-test
|
||||
coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci)))
|
||||
|
||||
# See contrib/coccinelle/README
|
||||
coccicheck-pending: coccicheck-test
|
||||
coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci))
|
||||
|
||||
.PHONY: coccicheck coccicheck-pending
|
||||
@ -3415,12 +3436,13 @@ profile-clean:
|
||||
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
|
||||
|
||||
cocciclean:
|
||||
$(RM) -r .build/contrib/coccinelle
|
||||
$(RM) contrib/coccinelle/*.cocci.patch*
|
||||
|
||||
clean: profile-clean coverage-clean cocciclean
|
||||
$(RM) -r .build
|
||||
$(RM) po/git.pot po/git-core.pot
|
||||
$(RM) *.res
|
||||
$(RM) git.res
|
||||
$(RM) $(OBJECTS)
|
||||
$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(REFTABLE_TEST_LIB)
|
||||
$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
|
||||
|
@ -1109,7 +1109,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
struct fetch_head *fetch_head)
|
||||
{
|
||||
int url_len, i, rc = 0;
|
||||
struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
|
||||
struct strbuf note = STRBUF_INIT;
|
||||
const char *what, *kind;
|
||||
struct ref *rm;
|
||||
char *url;
|
||||
@ -1276,7 +1276,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
|
||||
abort:
|
||||
strbuf_release(¬e);
|
||||
strbuf_release(&err);
|
||||
free(url);
|
||||
return rc;
|
||||
}
|
||||
|
@ -375,7 +375,6 @@ static void reset_hard(const struct object_id *oid, int verbose)
|
||||
static void restore_state(const struct object_id *head,
|
||||
const struct object_id *stash)
|
||||
{
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
const char *args[] = { "stash", "apply", NULL, NULL };
|
||||
|
||||
if (is_null_oid(stash))
|
||||
@ -391,7 +390,6 @@ static void restore_state(const struct object_id *head,
|
||||
*/
|
||||
run_command_v_opt(args, RUN_GIT_CMD);
|
||||
|
||||
strbuf_release(&sb);
|
||||
refresh_cache(REFRESH_QUIET);
|
||||
}
|
||||
|
||||
@ -502,7 +500,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||
{
|
||||
struct commit *remote_head;
|
||||
struct object_id branch_head;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct strbuf bname = STRBUF_INIT;
|
||||
struct merge_remote_desc *desc;
|
||||
const char *ptr;
|
||||
@ -590,7 +587,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
|
||||
oid_to_hex(&remote_head->object.oid), remote);
|
||||
cleanup:
|
||||
free(found_ref);
|
||||
strbuf_release(&buf);
|
||||
strbuf_release(&bname);
|
||||
}
|
||||
|
||||
|
@ -727,7 +727,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||
struct string_list_item *item;
|
||||
struct string_list names = STRING_LIST_INIT_DUP;
|
||||
struct string_list rollback = STRING_LIST_INIT_NODUP;
|
||||
struct string_list existing_nonkept_packs = STRING_LIST_INIT_DUP;
|
||||
struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
|
||||
struct pack_geometry *geometry = NULL;
|
||||
@ -1117,7 +1116,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
string_list_clear(&names, 0);
|
||||
string_list_clear(&rollback, 0);
|
||||
string_list_clear(&existing_nonkept_packs, 0);
|
||||
string_list_clear(&existing_kept_packs, 0);
|
||||
clear_pack_geometry(geometry);
|
||||
|
11
contrib/coccinelle/tests/free.c
Normal file
11
contrib/coccinelle/tests/free.c
Normal file
@ -0,0 +1,11 @@
|
||||
int use_FREE_AND_NULL(int *v)
|
||||
{
|
||||
free(*v);
|
||||
*v = NULL;
|
||||
}
|
||||
|
||||
int need_no_if(int *v)
|
||||
{
|
||||
if (v)
|
||||
free(v);
|
||||
}
|
9
contrib/coccinelle/tests/free.res
Normal file
9
contrib/coccinelle/tests/free.res
Normal file
@ -0,0 +1,9 @@
|
||||
int use_FREE_AND_NULL(int *v)
|
||||
{
|
||||
FREE_AND_NULL(*v);
|
||||
}
|
||||
|
||||
int need_no_if(int *v)
|
||||
{
|
||||
free(v);
|
||||
}
|
82
contrib/coccinelle/tests/unused.c
Normal file
82
contrib/coccinelle/tests/unused.c
Normal file
@ -0,0 +1,82 @@
|
||||
void test_strbuf(void)
|
||||
{
|
||||
struct strbuf sb1 = STRBUF_INIT;
|
||||
struct strbuf sb2 = STRBUF_INIT;
|
||||
struct strbuf sb3 = STRBUF_INIT;
|
||||
struct strbuf sb4 = STRBUF_INIT;
|
||||
struct strbuf sb5;
|
||||
struct strbuf sb6 = { 0 };
|
||||
struct strbuf sb7 = STRBUF_INIT;
|
||||
struct strbuf sb8 = STRBUF_INIT;
|
||||
struct strbuf *sp1;
|
||||
struct strbuf *sp2;
|
||||
struct strbuf *sp3;
|
||||
struct strbuf *sp4 = xmalloc(sizeof(struct strbuf));
|
||||
struct strbuf *sp5 = xmalloc(sizeof(struct strbuf));
|
||||
struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
|
||||
struct strbuf *sp7;
|
||||
|
||||
strbuf_init(&sb5, 0);
|
||||
strbuf_init(sp1, 0);
|
||||
strbuf_init(sp2, 0);
|
||||
strbuf_init(sp3, 0);
|
||||
strbuf_init(sp4, 0);
|
||||
strbuf_init(sp5, 0);
|
||||
strbuf_init(sp6, 0);
|
||||
strbuf_init(sp7, 0);
|
||||
sp7 = xmalloc(sizeof(struct strbuf));
|
||||
|
||||
use_before(&sb3);
|
||||
use_as_str("%s", sb7.buf);
|
||||
use_as_str("%s", sp1->buf);
|
||||
use_as_str("%s", sp6->buf);
|
||||
pass_pp(&sp3);
|
||||
|
||||
strbuf_release(&sb1);
|
||||
strbuf_reset(&sb2);
|
||||
strbuf_release(&sb3);
|
||||
strbuf_release(&sb4);
|
||||
strbuf_release(&sb5);
|
||||
strbuf_release(&sb6);
|
||||
strbuf_release(&sb7);
|
||||
strbuf_release(sp1);
|
||||
strbuf_release(sp2);
|
||||
strbuf_release(sp3);
|
||||
strbuf_release(sp4);
|
||||
strbuf_release(sp5);
|
||||
strbuf_release(sp6);
|
||||
strbuf_release(sp7);
|
||||
|
||||
use_after(&sb4);
|
||||
|
||||
if (when_strict())
|
||||
return;
|
||||
strbuf_release(&sb8);
|
||||
}
|
||||
|
||||
void test_other(void)
|
||||
{
|
||||
struct string_list l = STRING_LIST_INIT_DUP;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
string_list_clear(&l, 0);
|
||||
string_list_clear(&sb, 0);
|
||||
}
|
||||
|
||||
void test_worktrees(void)
|
||||
{
|
||||
struct worktree **w1 = get_worktrees();
|
||||
struct worktree **w2 = get_worktrees();
|
||||
struct worktree **w3;
|
||||
struct worktree **w4;
|
||||
|
||||
w3 = get_worktrees();
|
||||
w4 = get_worktrees();
|
||||
|
||||
use_it(w4);
|
||||
|
||||
free_worktrees(w1);
|
||||
free_worktrees(w2);
|
||||
free_worktrees(w3);
|
||||
free_worktrees(w4);
|
||||
}
|
45
contrib/coccinelle/tests/unused.res
Normal file
45
contrib/coccinelle/tests/unused.res
Normal file
@ -0,0 +1,45 @@
|
||||
void test_strbuf(void)
|
||||
{
|
||||
struct strbuf sb3 = STRBUF_INIT;
|
||||
struct strbuf sb4 = STRBUF_INIT;
|
||||
struct strbuf sb7 = STRBUF_INIT;
|
||||
struct strbuf *sp1;
|
||||
struct strbuf *sp3;
|
||||
struct strbuf *sp6 = xmalloc(sizeof(struct strbuf));
|
||||
strbuf_init(sp1, 0);
|
||||
strbuf_init(sp3, 0);
|
||||
strbuf_init(sp6, 0);
|
||||
|
||||
use_before(&sb3);
|
||||
use_as_str("%s", sb7.buf);
|
||||
use_as_str("%s", sp1->buf);
|
||||
use_as_str("%s", sp6->buf);
|
||||
pass_pp(&sp3);
|
||||
|
||||
strbuf_release(&sb3);
|
||||
strbuf_release(&sb4);
|
||||
strbuf_release(&sb7);
|
||||
strbuf_release(sp1);
|
||||
strbuf_release(sp3);
|
||||
strbuf_release(sp6);
|
||||
|
||||
use_after(&sb4);
|
||||
|
||||
if (when_strict())
|
||||
return;
|
||||
}
|
||||
|
||||
void test_other(void)
|
||||
{
|
||||
}
|
||||
|
||||
void test_worktrees(void)
|
||||
{
|
||||
struct worktree **w4;
|
||||
|
||||
w4 = get_worktrees();
|
||||
|
||||
use_it(w4);
|
||||
|
||||
free_worktrees(w4);
|
||||
}
|
43
contrib/coccinelle/unused.cocci
Normal file
43
contrib/coccinelle/unused.cocci
Normal file
@ -0,0 +1,43 @@
|
||||
// This rule finds sequences of "unused" declerations and uses of a
|
||||
// variable, where "unused" is defined to include only calling the
|
||||
// equivalent of alloc, init & free functions on the variable.
|
||||
@@
|
||||
type T;
|
||||
identifier I;
|
||||
// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
|
||||
constant INIT_MACRO =~ "_INIT";
|
||||
identifier MALLOC1 =~ "^x?[mc]alloc$";
|
||||
identifier INIT_ASSIGN1 =~ "^get_worktrees$";
|
||||
identifier INIT_CALL1 =~ "^[a-z_]*_init$";
|
||||
identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$";
|
||||
identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
|
||||
@@
|
||||
|
||||
(
|
||||
- T I;
|
||||
|
|
||||
- T I = { 0 };
|
||||
|
|
||||
- T I = INIT_MACRO;
|
||||
|
|
||||
- T I = MALLOC1(...);
|
||||
|
|
||||
- T I = INIT_ASSIGN1(...);
|
||||
)
|
||||
|
||||
<... when != \( I \| &I \)
|
||||
(
|
||||
- \( INIT_CALL1 \)( \( I \| &I \), ...);
|
||||
|
|
||||
- I = \( INIT_ASSIGN1 \)(...);
|
||||
|
|
||||
- I = MALLOC1(...);
|
||||
)
|
||||
...>
|
||||
|
||||
(
|
||||
- \( REL1 \| REL2 \)( \( I \| &I \), ...);
|
||||
|
|
||||
- \( REL1 \| REL2 \)( \( &I \| I \) );
|
||||
)
|
||||
... when != \( I \| &I \)
|
@ -687,7 +687,7 @@ static int cmd_diagnose(int argc, const char **argv)
|
||||
int stdout_fd = -1, archiver_fd = -1;
|
||||
time_t now = time(NULL);
|
||||
struct tm tm;
|
||||
struct strbuf path = STRBUF_INIT, buf = STRBUF_INIT;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int res = 0;
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options,
|
||||
@ -779,7 +779,6 @@ diagnose_cleanup:
|
||||
free(argv_copy);
|
||||
strvec_clear(&archiver_args);
|
||||
strbuf_release(&zip_path);
|
||||
strbuf_release(&path);
|
||||
strbuf_release(&buf);
|
||||
|
||||
return res;
|
||||
|
2
diff.c
2
diff.c
@ -1289,7 +1289,6 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
{
|
||||
static const char *nneof = " No newline at end of file\n";
|
||||
const char *context, *reset, *set, *set_sign, *meta, *fraginfo;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
enum diff_symbol s = eds->s;
|
||||
const char *line = eds->line;
|
||||
@ -1521,7 +1520,6 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
|
||||
default:
|
||||
BUG("unknown diff symbol");
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
|
||||
|
@ -70,6 +70,7 @@ ifndef V
|
||||
QUIET_HDR = @echo ' ' HDR $(<:hcc=h);
|
||||
QUIET_RC = @echo ' ' RC $@;
|
||||
QUIET_SPATCH = @echo ' ' SPATCH $<;
|
||||
QUIET_SPATCH_T = @echo ' ' SPATCH TEST $(@:.build/%=%);
|
||||
|
||||
## Used in "Documentation/Makefile"
|
||||
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
|
||||
|
Loading…
Reference in New Issue
Block a user