aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sparse.c234
-rw-r--r--validation/context-dynamic.c14
-rw-r--r--validation/context-named.c72
-rw-r--r--validation/context-statement.c17
-rw-r--r--validation/context.c90
5 files changed, 307 insertions, 120 deletions
diff --git a/sparse.c b/sparse.c
index fcd7487..c01e8cd 100644
--- a/sparse.c
+++ b/sparse.c
@@ -42,7 +42,8 @@ static const char *context_name(struct context *context)
return unnamed_context;
}
-static void context_add(struct context_check_list **ccl, const char *name, int offs, int offs_false)
+static void context_add(struct context_check_list **ccl, const char *name,
+ int offs, int offs_false)
{
struct context_check *check, *found = NULL;
@@ -63,16 +64,19 @@ static void context_add(struct context_check_list **ccl, const char *name, int o
found->val_false += offs_false;
}
-static int imbalance(struct entrypoint *ep, struct position pos, const char *name, const char *why)
+#define IMBALANCE_IN "context imbalance in '%s': "
+#define DEFAULT_CONTEXT_DESCR " default context: "
+
+static void get_context_string(char **buf, const char **name)
{
- if (Wcontext) {
- struct symbol *sym = ep->name;
- if (strcmp(name, unnamed_context))
- warning(pos, "context imbalance in '%s' - %s (%s)", show_ident(sym->ident), why, name);
- else
- warning(pos, "context imbalance in '%s' - %s", show_ident(sym->ident), why);
+ if (strcmp(*name, unnamed_context)) {
+ *buf = malloc(strlen(*name) + 16);
+ sprintf(*buf, " context '%s': ", *name);
+ *name = *buf;
+ } else {
+ *name = DEFAULT_CONTEXT_DESCR;
+ *buf = NULL;
}
- return -1;
}
static int context_list_check(struct entrypoint *ep, struct position pos,
@@ -81,6 +85,8 @@ static int context_list_check(struct entrypoint *ep, struct position pos,
{
struct context_check *c1, *c2;
int cur, tgt;
+ const char *name;
+ char *buf;
/* make sure the loop below checks all */
FOR_EACH_PTR(ccl_target, c1) {
@@ -98,15 +104,131 @@ static int context_list_check(struct entrypoint *ep, struct position pos,
break;
} END_FOR_EACH_PTR(c2);
+ if (cur == tgt || !Wcontext)
+ continue;
+
if (cur > tgt)
- return imbalance(ep, pos, c1->name, "wrong count at exit");
+ warning(pos, IMBALANCE_IN "wrong count at exit",
+ show_ident(ep->name->ident));
else if (cur < tgt)
- return imbalance(ep, pos, c1->name, "unexpected unlock");
+ warning(pos, IMBALANCE_IN "unexpected unlock",
+ show_ident(ep->name->ident));
+
+ name = c1->name;
+ get_context_string(&buf, &name);
+
+ info(pos, "%swanted %d, got %d",
+ name, tgt, cur);
+
+ free(buf);
+
+ return -1;
} END_FOR_EACH_PTR(c1);
return 0;
}
+static int handle_call(struct entrypoint *ep, struct basic_block *bb,
+ struct instruction *insn,
+ struct context_check_list *combined)
+{
+ struct context *ctx;
+ struct context_check *c;
+ const char *name, *call, *cmp;
+ char *buf;
+ int val, ok;
+
+ if (!insn->func || !insn->func->sym ||
+ insn->func->type != PSEUDO_SYM)
+ return 0;
+
+ /*
+ * Check all contexts the function wants.
+ */
+ FOR_EACH_PTR(insn->func->sym->ctype.contexts, ctx) {
+ name = context_name(ctx);
+ val = 0;
+
+ FOR_EACH_PTR(combined, c) {
+ if (strcmp(c->name, name) == 0) {
+ val = c->val;
+ break;
+ }
+ } END_FOR_EACH_PTR(c);
+
+ if (ctx->exact) {
+ ok = ctx->in == val;
+ cmp = "";
+ } else {
+ ok = ctx->in <= val;
+ cmp = ">= ";
+ }
+
+ if (!ok && Wcontext) {
+ get_context_string(&buf, &name);
+ call = strdup(show_ident(insn->func->ident));
+
+ warning(insn->pos, "context problem in '%s': "
+ "'%s' expected different context",
+ show_ident(ep->name->ident), call);
+
+ info(insn->pos, "%swanted %s%d, got %d",
+ name, cmp, ctx->in, val);
+
+ free((void *)call);
+ free(buf);
+
+ return -1;
+ }
+ } END_FOR_EACH_PTR (ctx);
+
+ return 0;
+}
+
+static int handle_context(struct entrypoint *ep, struct basic_block *bb,
+ struct instruction *insn,
+ struct context_check_list **combined)
+{
+ struct context_check *c;
+ const char *name;
+ char *buf;
+ int val, ok;
+
+ val = 0;
+
+ name = unnamed_context;
+ if (insn->context_expr)
+ name = show_ident(insn->context_expr->symbol_name);
+
+ FOR_EACH_PTR(*combined, c) {
+ if (strcmp(c->name, name) == 0) {
+ val = c->val;
+ break;
+ }
+ } END_FOR_EACH_PTR(c);
+
+ ok = insn->required <= val;
+
+ if (!ok && Wcontext) {
+ get_context_string(&buf, &name);
+
+ warning(insn->pos,
+ IMBALANCE_IN
+ "__context__ statement expected different context",
+ show_ident(ep->name->ident));
+
+ info(insn->pos, "%swanted >= %d, got %d",
+ name, insn->required, val);
+
+ free(buf);
+ return -1;
+ }
+
+ context_add(combined, name, insn->increment, insn->inc_false);
+
+ return 0;
+}
+
static int check_bb_context(struct entrypoint *ep, struct basic_block *bb,
struct context_check_list *ccl_in,
struct context_check_list *ccl_target,
@@ -116,16 +238,21 @@ static int check_bb_context(struct entrypoint *ep, struct basic_block *bb,
struct context_check *c;
struct instruction *insn;
struct multijmp *mj;
- struct context *ctx;
- const char *name;
- int ok, val;
- /* recurse in once to catch bad loops */
+ /*
+ * recurse in once to catch bad loops,
+ * bb->context is initialised to -1.
+ */
if (bb->context > 0)
return 0;
-
bb->context++;
+ /*
+ * We're starting with a completely new local list of contexts, so
+ * initialise it according to what we got from the parent block.
+ * That may use either the 'false' or the 'true' part of the context
+ * for the conditional_context() attribute.
+ */
FOR_EACH_PTR(ccl_in, c) {
if (in_false)
context_add(&combined, c->name, c->val_false, c->val_false);
@@ -133,76 +260,37 @@ static int check_bb_context(struct entrypoint *ep, struct basic_block *bb,
context_add(&combined, c->name, c->val, c->val);
} END_FOR_EACH_PTR(c);
+ /*
+ * Now walk the instructions for this block, recursing into any
+ * instructions that have children. We need to have the right
+ * order so we cannot iterate bb->children instead.
+ */
FOR_EACH_PTR(bb->insns, insn) {
- if (!insn->bb)
- continue;
switch (insn->opcode) {
case OP_INLINED_CALL:
case OP_CALL:
- if (!insn->func || !insn->func->sym || insn->func->type != PSEUDO_SYM)
- break;
- FOR_EACH_PTR(insn->func->sym->ctype.contexts, ctx) {
- name = context_name(ctx);
- val = 0;
-
- FOR_EACH_PTR(combined, c) {
- if (strcmp(c->name, name) == 0) {
- val = c->val;
- break;
- }
- } END_FOR_EACH_PTR(c);
-
- if (ctx->exact)
- ok = ctx->in == val;
- else
- ok = ctx->in <= val;
-
- if (!ok) {
- const char *call = strdup(show_ident(insn->func->ident));
- warning(insn->pos, "context problem in '%s' - function '%s' expected different context",
- show_ident(ep->name->ident), call);
- free((void *)call);
- return -1;
- }
- } END_FOR_EACH_PTR (ctx);
+ if (handle_call(ep, bb, insn, combined))
+ return -1;
break;
case OP_CONTEXT:
- val = 0;
-
- name = unnamed_context;
- if (insn->context_expr)
- name = show_ident(insn->context_expr->symbol_name);
-
- FOR_EACH_PTR(combined, c) {
- if (strcmp(c->name, name) == 0) {
- val = c->val;
- break;
- }
- } END_FOR_EACH_PTR(c);
-
- ok = insn->required <= val;
-
- if (!ok) {
- name = strdup(name);
- imbalance(ep, insn->pos, name, "__context__ statement expected different lock context");
- free((void *)name);
+ if (handle_context(ep, bb, insn, &combined))
return -1;
- }
-
- context_add(&combined, name, insn->increment, insn->inc_false);
break;
case OP_BR:
if (insn->bb_true)
- if (check_bb_context(ep, insn->bb_true, combined, ccl_target, 0))
+ if (check_bb_context(ep, insn->bb_true,
+ combined, ccl_target, 0))
return -1;
if (insn->bb_false)
- if (check_bb_context(ep, insn->bb_false, combined, ccl_target, 1))
+ if (check_bb_context(ep, insn->bb_false,
+ combined, ccl_target, 1))
return -1;
break;
case OP_SWITCH:
case OP_COMPUTEDGOTO:
FOR_EACH_PTR(insn->multijmp_list, mj) {
- if (check_bb_context(ep, mj->target, combined, ccl_target, 0))
+ if (check_bb_context(ep, mj->target,
+ combined, ccl_target, 0))
return -1;
} END_FOR_EACH_PTR(mj);
break;
@@ -212,16 +300,10 @@ static int check_bb_context(struct entrypoint *ep, struct basic_block *bb,
insn = last_instruction(bb->insns);
if (!insn)
return 0;
+
if (insn->opcode == OP_RET)
return context_list_check(ep, insn->pos, combined, ccl_target);
- FOR_EACH_PTR(bb->insns, insn) {
- if (!insn->bb)
- continue;
- switch (insn->opcode) {
- }
- } END_FOR_EACH_PTR(insn);
-
/* contents will be freed once we return out of recursion */
free_ptr_list(&combined);
diff --git a/validation/context-dynamic.c b/validation/context-dynamic.c
index e3bbb98..5e172f0 100644
--- a/validation/context-dynamic.c
+++ b/validation/context-dynamic.c
@@ -151,11 +151,21 @@ static int good_switch(void)
r();
}
+static void bad_lock1(void)
+{
+ r();
+ a();
+}
+
/*
* check-name: Check -Wcontext with lock trylocks
*
* check-error-start
-context-dynamic.c:83:6: warning: context problem in 'bad_trylock1' - function 'r' expected different context
-context-dynamic.c:133:6: warning: context problem in 'bad_trylock2' - function 'r' expected different context
+context-dynamic.c:83:6: warning: context problem in 'bad_trylock1': 'r' expected different context
+context-dynamic.c:83:6: context 'A': wanted >= 1, got 0
+context-dynamic.c:133:6: warning: context problem in 'bad_trylock2': 'r' expected different context
+context-dynamic.c:133:6: context 'A': wanted >= 1, got 0
+context-dynamic.c:156:6: warning: context problem in 'bad_lock1': 'r' expected different context
+context-dynamic.c:156:6: context 'A': wanted >= 1, got 0
* check-error-end
*/
diff --git a/validation/context-named.c b/validation/context-named.c
index 806d736..58310e9 100644
--- a/validation/context-named.c
+++ b/validation/context-named.c
@@ -501,29 +501,53 @@ static void good_mixed_with_if(void)
* check-name: Check -Wcontext with lock names
*
* check-error-start
-context-named.c:86:3: warning: context imbalance in 'warn_lock1' - wrong count at exit (TEST)
-context-named.c:93:3: warning: context imbalance in 'warn_lock2' - wrong count at exit (TEST)
-context-named.c:100:3: warning: context imbalance in 'warn_lock3' - wrong count at exit (TEST)
-context-named.c:105:3: warning: context problem in 'warn_unlock1' - function 'r' expected different context
-context-named.c:112:3: warning: context problem in 'warn_unlock2' - function 'r' expected different context
-context-named.c:152:9: warning: context imbalance in 'warn_if1' - wrong count at exit (TEST)
-context-named.c:162:9: warning: context imbalance in 'warn_if2' - wrong count at exit (TEST)
-context-named.c:218:4: warning: context imbalance in 'warn_while1' - wrong count at exit (TEST)
-context-named.c:225:4: warning: context problem in 'warn_while2' - function 'r' expected different context
-context-named.c:235:4: warning: context imbalance in 'warn_while3' - wrong count at exit (TEST)
-context-named.c:295:5: warning: context imbalance in 'warn_goto1' - wrong count at exit (TEST)
-context-named.c:305:6: warning: context imbalance in 'warn_goto2' - wrong count at exit (TEST)
-context-named.c:315:6: warning: context problem in 'warn_goto3' - function 'r' expected different context
-context-named.c:321:7: warning: context imbalance in 'warn_multiple1' - wrong count at exit (TEST)
-context-named.c:327:6: warning: context imbalance in 'warn_multiple2' - wrong count at exit (TEST2)
-context-named.c:333:6: warning: context problem in 'warn_mixed1' - function 'r' expected different context
-context-named.c:343:6: warning: context problem in 'warn_mixed2' - function 'r' expected different context
-context-named.c:353:6: warning: context problem in 'warn_mixed3' - function 'r' expected different context
-context-named.c:364:6: warning: context imbalance in 'warn_mixed4' - wrong count at exit (TEST2)
-context-named.c:434:14: warning: context problem in 'warn_fn' - function 'need_lock' expected different context
-context-named.c:441:15: warning: context problem in 'warn_fn2' - function 'need_lock2' expected different context
-context-named.c:456:20: warning: context problem in 'warn_exact_fn1' - function 'need_lock_exact' expected different context
-context-named.c:464:20: warning: context problem in 'warn_exact_fn2' - function 'need_lock_exact' expected different context
-context-named.c:475:15: warning: context problem in 'warn_fn3' - function 'need_lock3' expected different context
+context-named.c:86:3: warning: context imbalance in 'warn_lock1': wrong count at exit
+context-named.c:86:3: context 'TEST': wanted 0, got 1
+context-named.c:93:3: warning: context imbalance in 'warn_lock2': wrong count at exit
+context-named.c:93:3: context 'TEST': wanted 0, got 1
+context-named.c:100:3: warning: context imbalance in 'warn_lock3': wrong count at exit
+context-named.c:100:3: context 'TEST': wanted 0, got 1
+context-named.c:105:3: warning: context problem in 'warn_unlock1': 'r' expected different context
+context-named.c:105:3: context 'TEST': wanted >= 1, got 0
+context-named.c:112:3: warning: context problem in 'warn_unlock2': 'r' expected different context
+context-named.c:112:3: context 'TEST': wanted >= 1, got 0
+context-named.c:152:9: warning: context imbalance in 'warn_if1': wrong count at exit
+context-named.c:152:9: context 'TEST': wanted 0, got 1
+context-named.c:162:9: warning: context imbalance in 'warn_if2': wrong count at exit
+context-named.c:162:9: context 'TEST': wanted 0, got 1
+context-named.c:218:4: warning: context imbalance in 'warn_while1': wrong count at exit
+context-named.c:218:4: context 'TEST': wanted 0, got 1
+context-named.c:225:4: warning: context problem in 'warn_while2': 'r' expected different context
+context-named.c:225:4: context 'TEST': wanted >= 1, got 0
+context-named.c:235:4: warning: context imbalance in 'warn_while3': wrong count at exit
+context-named.c:235:4: context 'TEST': wanted 0, got 1
+context-named.c:295:5: warning: context imbalance in 'warn_goto1': wrong count at exit
+context-named.c:295:5: context 'TEST': wanted 0, got 1
+context-named.c:305:6: warning: context imbalance in 'warn_goto2': wrong count at exit
+context-named.c:305:6: context 'TEST': wanted 0, got 1
+context-named.c:315:6: warning: context problem in 'warn_goto3': 'r' expected different context
+context-named.c:315:6: context 'TEST': wanted >= 1, got 0
+context-named.c:321:7: warning: context imbalance in 'warn_multiple1': wrong count at exit
+context-named.c:321:7: context 'TEST': wanted 0, got 1
+context-named.c:327:6: warning: context imbalance in 'warn_multiple2': wrong count at exit
+context-named.c:327:6: context 'TEST2': wanted 0, got 1
+context-named.c:333:6: warning: context problem in 'warn_mixed1': 'r' expected different context
+context-named.c:333:6: context 'TEST': wanted >= 1, got 0
+context-named.c:343:6: warning: context problem in 'warn_mixed2': 'r' expected different context
+context-named.c:343:6: context 'TEST': wanted >= 1, got 0
+context-named.c:353:6: warning: context problem in 'warn_mixed3': 'r' expected different context
+context-named.c:353:6: context 'TEST': wanted >= 1, got 0
+context-named.c:364:6: warning: context imbalance in 'warn_mixed4': wrong count at exit
+context-named.c:364:6: context 'TEST2': wanted 0, got 1
+context-named.c:434:14: warning: context problem in 'warn_fn': 'need_lock' expected different context
+context-named.c:434:14: context 'TEST': wanted >= 1, got 0
+context-named.c:441:15: warning: context problem in 'warn_fn2': 'need_lock2' expected different context
+context-named.c:441:15: context 'TEST': wanted >= 1, got 0
+context-named.c:456:20: warning: context problem in 'warn_exact_fn1': 'need_lock_exact' expected different context
+context-named.c:456:20: context 'TEST': wanted 1, got 2
+context-named.c:464:20: warning: context problem in 'warn_exact_fn2': 'need_lock_exact' expected different context
+context-named.c:464:20: context 'TEST': wanted 1, got 0
+context-named.c:475:15: warning: context problem in 'warn_fn3': 'need_lock3' expected different context
+context-named.c:475:15: context 'TEST': wanted >= 1, got 0
* check-error-end
*/
diff --git a/validation/context-statement.c b/validation/context-statement.c
index ec26fef..fd79a6a 100644
--- a/validation/context-statement.c
+++ b/validation/context-statement.c
@@ -47,12 +47,23 @@ static void bad_macro2(void)
m();
}
+static void bad_macro3(void)
+{
+ r();
+ a();
+}
+
/*
* check-name: Check __context__ statement with required context
*
* check-error-start
-context-statement.c:16:8: warning: context imbalance in 'bad_arr' - unexpected unlock (LOCK)
-context-statement.c:38:5: warning: context imbalance in 'bad_macro1' - __context__ statement expected different lock context (LOCK)
-context-statement.c:47:5: warning: context imbalance in 'bad_macro2' - __context__ statement expected different lock context (LOCK)
+context-statement.c:16:8: warning: context imbalance in 'bad_arr': unexpected unlock
+context-statement.c:16:8: context 'LOCK': wanted 0, got -1
+context-statement.c:38:5: warning: context imbalance in 'bad_macro1': __context__ statement expected different context
+context-statement.c:38:5: context 'LOCK': wanted >= 1, got 0
+context-statement.c:47:5: warning: context imbalance in 'bad_macro2': __context__ statement expected different context
+context-statement.c:47:5: context 'LOCK': wanted >= 1, got 0
+context-statement.c:53:5: warning: context imbalance in 'bad_macro3': __context__ statement expected different context
+context-statement.c:53:5: context 'LOCK': wanted >= 0, got -1
* check-error-end
*/
diff --git a/validation/context.c b/validation/context.c
index df337e5..4250e95 100644
--- a/validation/context.c
+++ b/validation/context.c
@@ -325,24 +325,84 @@ static void warn_odd_looping(void)
r();
}
+static void warn_huge_switch(void)
+{
+ a();
+
+ switch(condition) {
+ case 1:
+ r();
+ break;
+ case 2:
+ r();
+ break;
+ case 3:
+ r();
+ break;
+ case 4:
+ r();
+ break;
+ case 5:
+ r();
+ break;
+ case 11:
+ r();
+ break;
+ case 12:
+ r();
+ break;
+ case 13:
+ r();
+ break;
+ case 14:
+ r();
+ case 15:
+ r();
+ break;
+ case 16:
+ r();
+ break;
+ case 17:
+ r();
+ break;
+ }
+}
+
/*
* check-name: Check -Wcontext
*
* check-error-start
-context.c:71:3: warning: context imbalance in 'warn_lock1' - wrong count at exit
-context.c:78:3: warning: context imbalance in 'warn_lock2' - wrong count at exit
-context.c:85:3: warning: context imbalance in 'warn_lock3' - wrong count at exit
-context.c:90:3: warning: context problem in 'warn_unlock1' - function 'r' expected different context
-context.c:97:3: warning: context problem in 'warn_unlock2' - function 'r' expected different context
-context.c:137:9: warning: context imbalance in 'warn_if1' - wrong count at exit
-context.c:147:9: warning: context imbalance in 'warn_if2' - wrong count at exit
-context.c:203:4: warning: context imbalance in 'warn_while1' - wrong count at exit
-context.c:210:4: warning: context problem in 'warn_while2' - function 'r' expected different context
-context.c:220:4: warning: context imbalance in 'warn_while3' - wrong count at exit
-context.c:280:5: warning: context imbalance in 'warn_goto1' - wrong count at exit
-context.c:290:6: warning: context imbalance in 'warn_goto2' - wrong count at exit
-context.c:300:6: warning: context problem in 'warn_goto3' - function 'r' expected different context
-context.c:315:6: warning: context problem in 'warn_cond_lock1' - function 'r' expected different context
-context.c:325:10: warning: context problem in 'warn_odd_looping' - function 'r' expected different context
+context.c:71:3: warning: context imbalance in 'warn_lock1': wrong count at exit
+context.c:71:3: default context: wanted 0, got 1
+context.c:78:3: warning: context imbalance in 'warn_lock2': wrong count at exit
+context.c:78:3: default context: wanted 0, got 1
+context.c:85:3: warning: context imbalance in 'warn_lock3': wrong count at exit
+context.c:85:3: default context: wanted 0, got 1
+context.c:90:3: warning: context problem in 'warn_unlock1': 'r' expected different context
+context.c:90:3: default context: wanted >= 1, got 0
+context.c:97:3: warning: context problem in 'warn_unlock2': 'r' expected different context
+context.c:97:3: default context: wanted >= 1, got 0
+context.c:137:9: warning: context imbalance in 'warn_if1': wrong count at exit
+context.c:137:9: default context: wanted 0, got 1
+context.c:147:9: warning: context imbalance in 'warn_if2': wrong count at exit
+context.c:147:9: default context: wanted 0, got 1
+context.c:203:4: warning: context imbalance in 'warn_while1': wrong count at exit
+context.c:203:4: default context: wanted 0, got 1
+context.c:210:4: warning: context problem in 'warn_while2': 'r' expected different context
+context.c:210:4: default context: wanted >= 1, got 0
+context.c:220:4: warning: context imbalance in 'warn_while3': wrong count at exit
+context.c:220:4: default context: wanted 0, got 1
+context.c:280:5: warning: context imbalance in 'warn_goto1': wrong count at exit
+context.c:280:5: default context: wanted 0, got 1
+context.c:290:6: warning: context imbalance in 'warn_goto2': wrong count at exit
+context.c:290:6: default context: wanted 0, got 1
+context.c:300:6: warning: context problem in 'warn_goto3': 'r' expected different context
+context.c:300:6: default context: wanted >= 1, got 0
+context.c:315:6: warning: context problem in 'warn_cond_lock1': 'r' expected different context
+context.c:315:6: default context: wanted >= 1, got 0
+context.c:325:10: warning: context problem in 'warn_odd_looping': 'r' expected different context
+context.c:325:10: default context: wanted >= 1, got 0
+context.c:360:10: warning: context problem in 'warn_huge_switch': 'r' expected different context
+context.c:360:10: default context: wanted >= 1, got 0
* check-error-end
*/