* [PATCH 1/5] add __exact_context__
2008-04-27 11:31 [PATCH 0/5] more sparse context tracking improvements Johannes Berg
@ 2008-04-27 11:31 ` Johannes Berg
2008-04-27 11:31 ` [PATCH 2/5] allow context() attribute on variables Johannes Berg
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 11:31 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
[-- Attachment #1: 002-exact-context.patch --]
[-- Type: text/plain, Size: 7234 bytes --]
We also need a statement to indicate that an exact context is
required, most notably the next patch will require it so that
it can translate attributes on variables into statements.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
ident-list.h | 1
linearize.c | 1
linearize.h | 2 -
parse.c | 20 ++++++++++++-
parse.h | 1
sparse.1 | 2 -
sparse.c | 14 ++++++---
validation/context-exact.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 101 insertions(+), 7 deletions(-)
--- sparse.orig/ident-list.h 2008-04-26 23:09:00.000000000 +0200
+++ sparse/ident-list.h 2008-04-26 23:09:05.000000000 +0200
@@ -96,6 +96,7 @@ __IDENT(__PRETTY_FUNCTION___ident, "__PR
/* Sparse commands */
IDENT_RESERVED(__context__);
+IDENT_RESERVED(__exact_context__);
IDENT_RESERVED(__range__);
/* Magic function names we recognize */
--- sparse.orig/linearize.c 2008-04-26 23:09:00.000000000 +0200
+++ sparse/linearize.c 2008-04-26 23:09:05.000000000 +0200
@@ -1681,6 +1681,7 @@ static pseudo_t linearize_context(struct
value = expr->value;
insn->required = value;
+ insn->exact = stmt->exact;
insn->context_expr = stmt->context;
add_one_insn(ep, insn);
--- sparse.orig/parse.c 2008-04-26 23:09:04.000000000 +0200
+++ sparse/parse.c 2008-04-26 23:09:05.000000000 +0200
@@ -52,6 +52,7 @@ static struct token *parse_while_stateme
static struct token *parse_do_statement(struct token *token, struct statement *stmt);
static struct token *parse_goto_statement(struct token *token, struct statement *stmt);
static struct token *parse_context_statement(struct token *token, struct statement *stmt);
+static struct token *parse_exact_context_statement(struct token *token, struct statement *stmt);
static struct token *parse_range_statement(struct token *token, struct statement *stmt);
static struct token *parse_asm_statement(struct token *token, struct statement *stmt);
static struct token *toplevel_asm_declaration(struct token *token, struct symbol_list **list);
@@ -149,6 +150,10 @@ static struct symbol_op __context___op =
.statement = parse_context_statement,
};
+static struct symbol_op __exact_context___op = {
+ .statement = parse_exact_context_statement,
+};
+
static struct symbol_op range_op = {
.statement = parse_range_statement,
};
@@ -254,6 +259,7 @@ static struct init_keyword {
{ "do", NS_KEYWORD, .op = &do_op },
{ "goto", NS_KEYWORD, .op = &goto_op },
{ "__context__",NS_KEYWORD, .op = &__context___op },
+ { "__exact_context__",NS_KEYWORD, .op = &__exact_context___op },
{ "__range__", NS_KEYWORD, .op = &range_op },
{ "asm", NS_KEYWORD, .op = &asm_op },
{ "__asm", NS_KEYWORD, .op = &asm_op },
@@ -1810,7 +1816,7 @@ static struct token *parse_goto_statemen
return expect(token, ';', "at end of statement");
}
-static struct token *parse_context_statement(struct token *token, struct statement *stmt)
+static struct token *_parse_context_statement(struct token *token, struct statement *stmt, int exact)
{
struct expression *args[3];
int argc = 0;
@@ -1835,6 +1841,8 @@ static struct token *parse_context_state
stmt->expression = args[0];
stmt->context = NULL;
+ stmt->exact = exact;
+
switch (argc) {
case 0:
sparse_error(token->pos, "__context__ statement needs argument(s)");
@@ -1864,6 +1872,16 @@ static struct token *parse_context_state
return expect(token, ')', "at end of __context__");
}
+static struct token *parse_context_statement(struct token *token, struct statement *stmt)
+{
+ return _parse_context_statement(token, stmt, 0);
+}
+
+static struct token *parse_exact_context_statement(struct token *token, struct statement *stmt)
+{
+ return _parse_context_statement(token, stmt, 1);
+}
+
static struct token *parse_range_statement(struct token *token, struct statement *stmt)
{
stmt->type = STMT_RANGE;
--- sparse.orig/sparse.1 2008-04-26 23:09:00.000000000 +0200
+++ sparse/sparse.1 2008-04-26 23:09:05.000000000 +0200
@@ -90,7 +90,7 @@ To indicate that a function requires
.BI exactly
a certain lock context (not "at least" as above), use the form
.BI __attribute__((exact_context( [expression ,] in_context , out_context ))
-There currently is no corresponding
+There is also the corresponding
.BI __exact_context__( [expression , ]adjust_value[ , required] )
statement.
--- sparse.orig/sparse.c 2008-04-26 23:09:00.000000000 +0200
+++ sparse/sparse.c 2008-04-26 23:09:05.000000000 +0200
@@ -239,7 +239,7 @@ static int handle_context(struct entrypo
struct context_check_list **combined)
{
struct context_check *c;
- const char *name;
+ const char *name, *cmp;
char *buf;
int val, ok;
@@ -256,7 +256,13 @@ static int handle_context(struct entrypo
}
} END_FOR_EACH_PTR(c);
- ok = insn->required <= val;
+ if (insn->exact) {
+ ok = insn->required == val;
+ cmp = "";
+ } else {
+ ok = insn->required <= val;
+ cmp = ">= ";
+ }
if (!ok && Wcontext) {
get_context_string(&buf, &name);
@@ -266,8 +272,8 @@ static int handle_context(struct entrypo
"__context__ statement expected different context",
show_ident(ep->name->ident));
- info(insn->pos, "%swanted >= %d, got %d",
- name, insn->required, val);
+ info(insn->pos, "%swanted %s%d, got %d",
+ name, cmp, insn->required, val);
free(buf);
return -1;
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ sparse/validation/context-exact.c 2008-04-26 23:09:05.000000000 +0200
@@ -0,0 +1,67 @@
+static void a(void) __attribute__((context(TEST,0,1)))
+{
+ __context__(TEST,1);
+}
+
+static void r(void) __attribute__((context(TEST,1,0)))
+{
+ __context__(TEST,-1,1);
+}
+
+static void good_1(void)
+{
+ a();
+ r();
+}
+
+static void good_2(void)
+{
+ a();
+ r();
+ a();
+ r();
+}
+
+static void good_3(void)
+{
+ a();
+ a();
+ r();
+ r();
+}
+
+static void good_4(void)
+{
+ a();
+ a();
+ __context__(TEST,0,1);
+ r();
+ r();
+}
+
+static void warn_1(void)
+{
+ a();
+ a();
+ __exact_context__(TEST,0,1);
+ r();
+ r();
+}
+
+static void good_5(void)
+{
+ a();
+ a();
+ __exact_context__(TEST,0,2);
+ r();
+ r();
+}
+
+/*
+ * check-name: Check __exact_context__ statement with required context
+ *
+ * check-error-start
+context-exact.c:46:2: warning: context imbalance in 'warn_1': __context__ statement expected different context
+context-exact.c:46:2: context 'TEST': wanted 1, got 2
+ * check-error-end
+ */
--- sparse.orig/linearize.h 2008-04-26 23:09:00.000000000 +0200
+++ sparse/linearize.h 2008-04-26 23:09:05.000000000 +0200
@@ -116,7 +116,7 @@ struct instruction {
struct pseudo_list *arguments;
};
struct /* context */ {
- int increment, required, inc_false;
+ int increment, required, inc_false, exact;
struct expression *context_expr;
};
struct /* asm */ {
--- sparse.orig/parse.h 2008-04-26 23:09:00.000000000 +0200
+++ sparse/parse.h 2008-04-26 23:09:05.000000000 +0200
@@ -43,6 +43,7 @@ struct statement {
struct expression *expression;
struct expression *context;
struct expression *required;
+ int exact;
};
struct /* return_statement */ {
struct expression *ret_value;
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 2/5] allow context() attribute on variables
2008-04-27 11:31 [PATCH 0/5] more sparse context tracking improvements Johannes Berg
2008-04-27 11:31 ` [PATCH 1/5] add __exact_context__ Johannes Berg
@ 2008-04-27 11:31 ` Johannes Berg
2008-04-27 11:31 ` [PATCH 3/5] evaluate/expand context expressions Johannes Berg
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 11:31 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
[-- Attachment #1: 003-context-on-vars.patch --]
[-- Type: text/plain, Size: 17452 bytes --]
This patch makes it possible to add the context attribute on
variables, to warn for example in this case:
struct something {
int x __attribute__((context(L,1,1)));
};
extern struct something *s;
static void warn_access13(void)
{
s->x = 7;
}
This is achieved by translating the context attribute on
variables that are loaded from/stored to into a context
expression internally. A number of tests are included,
including tests for a struct member (as above) and array
accesses.
To distinguish between reads and writes (the default is to
check both) use the fourth parameter to the context attribute:
__attribute__((context(L,1,1,read)))
or
__attribute__((context(L,1,1,write)))
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
The exact_context() attribute is also allowed so we have the
same max/no-max semantics as functions.
linearize.c | 92 ++++++++++++++++-
linearize.h | 1
parse.c | 25 ++++
sparse.1 | 7 +
sparse.c | 18 ++-
symbol.h | 7 +
validation/context-exact.c | 2
validation/context-on-vars.c | 219 +++++++++++++++++++++++++++++++++++++++++
validation/context-statement.c | 6 -
9 files changed, 365 insertions(+), 12 deletions(-)
--- sparse.orig/sparse.c 2008-04-26 23:09:05.000000000 +0200
+++ sparse/sparse.c 2008-04-26 23:09:27.000000000 +0200
@@ -114,6 +114,7 @@ static struct context_check_list *checke
}
#define IMBALANCE_IN "context imbalance in '%s': "
+#define CONTEXT_PROB "context problem in '%s': "
#define DEFAULT_CONTEXT_DESCR " default context: "
static void get_context_string(char **buf, const char **name)
@@ -267,10 +268,19 @@ static int handle_context(struct entrypo
if (!ok && Wcontext) {
get_context_string(&buf, &name);
- warning(insn->pos,
- IMBALANCE_IN
- "__context__ statement expected different context",
- show_ident(ep->name->ident));
+ if (insn->access_var) {
+ char *symname = strdup(show_ident(insn->access_var->ident));
+ warning(insn->pos,
+ CONTEXT_PROB
+ "access to '%s' requires different context",
+ show_ident(ep->name->ident), symname);
+ free(symname);
+ } else {
+ warning(insn->pos,
+ CONTEXT_PROB
+ "__context__ statement expected different context",
+ show_ident(ep->name->ident));
+ }
info(insn->pos, "%swanted %s%d, got %d",
name, cmp, insn->required, val);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ sparse/validation/context-on-vars.c 2008-04-26 23:37:36.000000000 +0200
@@ -0,0 +1,219 @@
+static void a(void) __attribute__((context(L,0,1)))
+{
+ __context__(L,1);
+}
+
+static void r(void) __attribute__((context(L,1,0)))
+{
+ __context__(L,-1);
+}
+
+static int nl_int __attribute__((context(L,1,1)));
+static int nl_array[100] __attribute__((context(L,1,1)));
+extern int condition;
+
+static void warn_access1(void)
+{
+ nl_int = 7;
+}
+
+static void warn_access2(void)
+{
+ nl_int++;
+}
+
+static void warn_access3(void)
+{
+ if (condition)
+ nl_int++;
+}
+
+static void warn_access4(void)
+{
+ condition -= nl_int;
+}
+
+static void warn_access5(void)
+{
+ int x = condition ? nl_int : 0;
+}
+
+static void warn_access6(void)
+{
+ if (!nl_int) {
+ condition = 1;
+ }
+}
+
+static void warn_access7(void)
+{
+ if (nl_int) {
+ condition = 1;
+ }
+}
+
+static int *warn_access8(void)
+{
+ return &nl_int;
+}
+
+static void warn_access9(void)
+{
+ (void*)nl_int;
+}
+
+static void warn_access10(void)
+{
+ nl_array[7]++;
+}
+
+static void good_access1(void)
+{
+ a();
+ nl_int = 7;
+ r();
+}
+
+static void good_access1(void)
+{
+ if (condition) {
+ a();
+ nl_int = 7;
+ r();
+ }
+}
+
+static void good_access3(void)
+{
+ /* tests more our ability to optimise things out ... */
+ int x = 0 ? nl_int : 0;
+}
+
+static int *good_access4(void)
+{
+ return &nl_int;
+}
+
+struct something {
+ int a;
+ int b;
+};
+
+extern struct something *s __attribute__((context(L,1,1)));
+
+static void warn_access11(void)
+{
+ s->b = 7;
+}
+
+struct something2 {
+ int a;
+ int b __attribute__((context(L,1,1)));
+};
+
+extern struct something2 *s2;
+extern int lx __attribute__((context(L,1,1)));
+
+static void warn_access12(void)
+{
+ s2->b = lx;
+}
+
+static void warn_access13(void)
+{
+ s2->b = 7;
+}
+
+static void good_1(void)
+{
+ a();
+ s2->b = 7;
+ r();
+}
+
+static void good_2(void)
+{
+ a();
+ a();
+ s2->b = 8;
+ r();
+ r();
+}
+
+struct something3 {
+ int a;
+ int b __attribute__((exact_context(L,1,1)));
+};
+
+extern struct something3 *s3;
+
+static void warn_exact1(void)
+{
+ a();
+ a();
+ s3->b = 8;
+ r();
+ r();
+}
+
+extern int x __attribute__((context(L,1,1,read)));
+extern int y __attribute__((context(L,1,1,write)));
+
+static void good_3(void)
+{
+ a();
+ y = x;
+ r();
+}
+
+static void good_4(void)
+{
+ x = y;
+}
+
+static void warn_access14(void)
+{
+ x;
+}
+
+static void warn_access15(void)
+{
+ y = 7;
+}
+
+/*
+ * check-name: Check -Wcontext for variables
+ *
+ * check-error-start
+context-on-vars.c:17:14: warning: context problem in 'warn_access1': access to 'nl_int' requires different context
+context-on-vars.c:17:14: context 'L': wanted >= 1, got 0
+context-on-vars.c:22:11: warning: context problem in 'warn_access2': access to 'nl_int' requires different context
+context-on-vars.c:22:11: context 'L': wanted >= 1, got 0
+context-on-vars.c:28:15: warning: context problem in 'warn_access3': access to 'nl_int' requires different context
+context-on-vars.c:28:15: context 'L': wanted >= 1, got 0
+context-on-vars.c:33:18: warning: context problem in 'warn_access4': access to 'nl_int' requires different context
+context-on-vars.c:33:18: context 'L': wanted >= 1, got 0
+context-on-vars.c:38:25: warning: context problem in 'warn_access5': access to 'nl_int' requires different context
+context-on-vars.c:38:25: context 'L': wanted >= 1, got 0
+context-on-vars.c:43:10: warning: context problem in 'warn_access6': access to 'nl_int' requires different context
+context-on-vars.c:43:10: context 'L': wanted >= 1, got 0
+context-on-vars.c:50:9: warning: context problem in 'warn_access7': access to 'nl_int' requires different context
+context-on-vars.c:50:9: context 'L': wanted >= 1, got 0
+context-on-vars.c:62:12: warning: context problem in 'warn_access9': access to 'nl_int' requires different context
+context-on-vars.c:62:12: context 'L': wanted >= 1, got 0
+context-on-vars.c:67:16: warning: context problem in 'warn_access10': access to 'nl_array' requires different context
+context-on-vars.c:67:16: context 'L': wanted >= 1, got 0
+context-on-vars.c:106:5: warning: context problem in 'warn_access11': access to 's' requires different context
+context-on-vars.c:106:5: context 'L': wanted >= 1, got 0
+context-on-vars.c:119:13: warning: context problem in 'warn_access12': access to 'lx' requires different context
+context-on-vars.c:119:13: context 'L': wanted >= 1, got 0
+context-on-vars.c:124:5: warning: context problem in 'warn_access13': access to 'b' requires different context
+context-on-vars.c:124:5: context 'L': wanted >= 1, got 0
+context-on-vars.c:154:5: warning: context problem in 'warn_exact1': access to 'b' requires different context
+context-on-vars.c:154:5: context 'L': wanted 1, got 2
+context-on-vars.c:176:3: warning: context problem in 'warn_access14': access to 'x' requires different context
+context-on-vars.c:176:3: context 'L': wanted >= 1, got 0
+context-on-vars.c:181:7: warning: context problem in 'warn_access15': access to 'y' requires different context
+context-on-vars.c:181:7: context 'L': wanted >= 1, got 0
+ * check-error-end
+ */
--- sparse.orig/linearize.c 2008-04-26 23:09:05.000000000 +0200
+++ sparse/linearize.c 2008-04-26 23:37:56.000000000 +0200
@@ -30,7 +30,6 @@ static pseudo_t add_setval(struct entryp
static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym);
struct access_data;
-static pseudo_t add_load(struct entrypoint *ep, struct access_data *);
static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *);
struct pseudo void_pseudo = {};
@@ -935,6 +934,8 @@ static pseudo_t linearize_store_gen(stru
pseudo_t value,
struct access_data *ad)
{
+ struct context *context;
+ struct instruction *insn;
pseudo_t store = value;
if (type_size(ad->source_type) != type_size(ad->result_type)) {
@@ -950,6 +951,49 @@ static pseudo_t linearize_store_gen(stru
store = add_binary_op(ep, ad->source_type, OP_OR, orig, store);
}
add_store(ep, ad, store);
+
+ FOR_EACH_PTR(ad->source_type->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_WRITE)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->source_type;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+
+ FOR_EACH_PTR(ad->result_type->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_WRITE)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->result_type;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+
+ if (ad->address->type == PSEUDO_SYM &&
+ ad->address->sym->namespace & NS_SYMBOL) {
+ FOR_EACH_PTR(ad->address->sym->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_WRITE)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->address->sym;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+ }
+
return value;
}
@@ -987,6 +1031,8 @@ static pseudo_t add_symbol_address(struc
static pseudo_t linearize_load_gen(struct entrypoint *ep, struct access_data *ad)
{
+ struct context *context;
+ struct instruction *insn;
pseudo_t new = add_load(ep, ad);
if (ad->bit_offset) {
@@ -994,7 +1040,49 @@ static pseudo_t linearize_load_gen(struc
pseudo_t newval = add_binary_op(ep, ad->source_type, OP_LSR, new, shift);
new = newval;
}
-
+
+ FOR_EACH_PTR(ad->source_type->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_READ)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->source_type;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+
+ FOR_EACH_PTR(ad->result_type->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_READ)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->result_type;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+
+ if (ad->address->type == PSEUDO_SYM &&
+ ad->address->sym->namespace & NS_SYMBOL) {
+ FOR_EACH_PTR(ad->address->sym->ctype.contexts, context) {
+ if (context->rws != CTX_RWS_BOTH &&
+ context->rws != CTX_RWS_READ)
+ continue;
+ insn = alloc_instruction(OP_CONTEXT, 0);
+ insn->required = context->in;
+ insn->increment = insn->inc_false = context->out - context->in;
+ insn->context_expr = context->context;
+ insn->access_var = ad->address->sym;
+ insn->exact = context->exact;
+ add_one_insn(ep, insn);
+ } END_FOR_EACH_PTR(context);
+ }
+
return new;
}
--- sparse.orig/linearize.h 2008-04-26 23:09:05.000000000 +0200
+++ sparse/linearize.h 2008-04-26 23:09:27.000000000 +0200
@@ -118,6 +118,7 @@ struct instruction {
struct /* context */ {
int increment, required, inc_false, exact;
struct expression *context_expr;
+ struct symbol *access_var;
};
struct /* asm */ {
const char *string;
--- sparse.orig/validation/context-statement.c 2008-04-26 23:08:59.000000000 +0200
+++ sparse/validation/context-statement.c 2008-04-26 23:09:06.000000000 +0200
@@ -59,11 +59,11 @@ static void bad_macro3(void)
* check-error-start
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: warning: context problem 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: warning: context problem 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: warning: context problem in 'bad_macro3': __context__ statement expected different context
context-statement.c:53:5: context 'LOCK': wanted >= 0, got -1
* check-error-end
*/
--- sparse.orig/sparse.1 2008-04-26 23:09:05.000000000 +0200
+++ sparse/sparse.1 2008-04-26 23:42:50.000000000 +0200
@@ -94,6 +94,13 @@ There is also the corresponding
.BI __exact_context__( [expression , ]adjust_value[ , required] )
statement.
+Both these can also be added to variable accesses but it is not recommended
+to make variable accesses modify the context. For variables, it is possible
+to distinguish between reads and writes (the regular context attribute will
+be required on both reads and writes) by using either the token "read" or
+the token "write" for an optional fourth argument:
+.BI __attribute__((context( expression , in_context , out_context , read|write )).
+
To indicate that a certain function acquires a context depending on its
return value, use
.BI __attribute__((conditional_context( [expression ,] in_context , out_success , out_failure ))
--- sparse.orig/validation/context-exact.c 2008-04-26 23:09:05.000000000 +0200
+++ sparse/validation/context-exact.c 2008-04-26 23:09:06.000000000 +0200
@@ -61,7 +61,7 @@ static void good_5(void)
* check-name: Check __exact_context__ statement with required context
*
* check-error-start
-context-exact.c:46:2: warning: context imbalance in 'warn_1': __context__ statement expected different context
+context-exact.c:46:2: warning: context problem in 'warn_1': __context__ statement expected different context
context-exact.c:46:2: context 'TEST': wanted 1, got 2
* check-error-end
*/
--- sparse.orig/parse.c 2008-04-26 23:37:51.000000000 +0200
+++ sparse/parse.c 2008-04-26 23:39:10.000000000 +0200
@@ -883,16 +883,18 @@ static struct token *attribute_mode(stru
static struct token *_attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype, int exact)
{
struct context *context = alloc_context();
- struct expression *args[3];
+ struct expression *args[4];
int argc = 0;
+ struct token *last = NULL;
token = expect(token, '(', "after context attribute");
while (!match_op(token, ')')) {
struct expression *expr = NULL;
+ last = token;
token = conditional_expression(token, &expr);
if (!expr)
break;
- if (argc < 3)
+ if (argc < 4)
args[argc++] = expr;
else
argc++;
@@ -917,6 +919,25 @@ static struct token *_attribute_context(
context->in = get_expression_value(args[1]);
context->out = get_expression_value(args[2]);
break;
+ case 4: {
+ const char *rw;
+ context->context = args[0];
+ context->in = get_expression_value(args[1]);
+ context->out = get_expression_value(args[2]);
+
+ if (last && token_type(last) == TOKEN_IDENT)
+ rw = show_token(last);
+ else
+ rw = NULL;
+
+ if (rw && strcmp(rw, "read") == 0)
+ context->rws = CTX_RWS_READ;
+ else if (rw && strcmp(rw, "write") == 0)
+ context->rws = CTX_RWS_WRITE;
+ else
+ sparse_error(last->pos, "invalid read/write specifier");
+ break;
+ }
default:
sparse_error(token->pos, "too many arguments to context attribute");
break;
--- sparse.orig/symbol.h 2008-04-26 23:37:51.000000000 +0200
+++ sparse/symbol.h 2008-04-26 23:37:56.000000000 +0200
@@ -69,10 +69,17 @@ enum keyword {
KW_MODE = 1 << 7,
};
+enum context_read_write_specifier {
+ CTX_RWS_BOTH = 0,
+ CTX_RWS_READ,
+ CTX_RWS_WRITE,
+};
+
struct context {
struct expression *context;
unsigned int in, out, out_false;
int exact;
+ enum context_read_write_specifier rws;
};
extern struct context *alloc_context(void);
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 3/5] evaluate/expand context expressions
2008-04-27 11:31 [PATCH 0/5] more sparse context tracking improvements Johannes Berg
2008-04-27 11:31 ` [PATCH 1/5] add __exact_context__ Johannes Berg
2008-04-27 11:31 ` [PATCH 2/5] allow context() attribute on variables Johannes Berg
@ 2008-04-27 11:31 ` Johannes Berg
2008-04-27 11:31 ` [PATCH 4/5] revert the conditional_context patch Johannes Berg
2008-04-27 11:31 ` [PATCH 5/5] check context expressions as expressions Johannes Berg
4 siblings, 0 replies; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 11:31 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
[-- Attachment #1: 004-bugfix-context-stmt.patch --]
[-- Type: text/plain, Size: 6534 bytes --]
But still allow having a standalone symbol as the context
expression, also evaluate the context change/requirement
directly in the parser and pass them up as integers. Also
fixes a number of bugs e.g. in the expression copier and
a segfault when the default context is used as such:
__context__(1,1);
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
evaluate.c | 9 ++++++++-
expand.c | 2 +-
inline.c | 19 ++++++++++++-------
linearize.c | 17 +++--------------
parse.c | 22 +++++++++++++---------
parse.h | 6 ++++--
validation/context.c | 28 ++++++++++++++++++++++++++++
7 files changed, 69 insertions(+), 34 deletions(-)
--- sparse.orig/evaluate.c 2008-04-26 23:09:27.000000000 +0200
+++ sparse/evaluate.c 2008-04-26 23:44:32.000000000 +0200
@@ -3356,7 +3356,14 @@ struct symbol *evaluate_statement(struct
evaluate_asm_statement(stmt);
return NULL;
case STMT_CONTEXT:
- evaluate_expression(stmt->expression);
+ /*
+ * If this is an unknown symbol accept it as-is
+ * as a context name.
+ */
+ if (stmt->context &&
+ (stmt->context->type != EXPR_SYMBOL ||
+ stmt->context->symbol))
+ evaluate_expression(stmt->context);
return NULL;
case STMT_RANGE:
evaluate_expression(stmt->range_expression);
--- sparse.orig/expand.c 2008-04-26 23:09:27.000000000 +0200
+++ sparse/expand.c 2008-04-26 23:44:32.000000000 +0200
@@ -1169,7 +1169,7 @@ static int expand_statement(struct state
/* FIXME! Do the asm parameter evaluation! */
break;
case STMT_CONTEXT:
- expand_expression(stmt->expression);
+ expand_expression(stmt->context);
break;
case STMT_RANGE:
expand_expression(stmt->range_expression);
--- sparse.orig/inline.c 2008-04-26 23:09:27.000000000 +0200
+++ sparse/inline.c 2008-04-26 23:44:32.000000000 +0200
@@ -328,7 +328,18 @@ static struct statement *copy_one_statem
stmt = newstmt;
break;
}
- case STMT_CONTEXT:
+ case STMT_CONTEXT: {
+ struct expression *expr = copy_expression(stmt->context);
+ struct statement *newstmt;
+ if (expr == stmt->context)
+ break;
+ newstmt = dup_statement(stmt);
+ newstmt->context = expr;
+ newstmt->change = stmt->change;
+ newstmt->required = stmt->required;
+ stmt = newstmt;
+ break;
+ }
case STMT_EXPRESSION: {
struct expression *expr = copy_expression(stmt->expression);
struct statement *newstmt;
@@ -336,12 +347,6 @@ static struct statement *copy_one_statem
break;
newstmt = dup_statement(stmt);
newstmt->expression = expr;
- if (stmt->required) {
- expr = copy_expression(stmt->required);
- if (expr == stmt->required)
- break;
- newstmt->required = expr;
- }
stmt = newstmt;
break;
}
--- sparse.orig/linearize.c 2008-04-26 23:37:56.000000000 +0200
+++ sparse/linearize.c 2008-04-26 23:44:32.000000000 +0200
@@ -1753,22 +1753,11 @@ static pseudo_t linearize_inlined_call(s
static pseudo_t linearize_context(struct entrypoint *ep, struct statement *stmt)
{
struct instruction *insn = alloc_instruction(OP_CONTEXT, 0);
- struct expression *expr = stmt->expression;
- int value = 0;
- if (expr->type == EXPR_VALUE)
- value = expr->value;
+ insn->increment = stmt->change;
+ insn->inc_false = stmt->change;
- insn->increment = value;
- insn->inc_false = value;
-
- expr = stmt->required;
- value = 0;
-
- if (expr && expr->type == EXPR_VALUE)
- value = expr->value;
-
- insn->required = value;
+ insn->required = stmt->required;
insn->exact = stmt->exact;
insn->context_expr = stmt->context;
--- sparse.orig/parse.c 2008-04-26 23:39:10.000000000 +0200
+++ sparse/parse.c 2008-04-26 23:44:32.000000000 +0200
@@ -1859,9 +1859,7 @@ static struct token *_parse_context_stat
token = token->next;
}
- stmt->expression = args[0];
stmt->context = NULL;
-
stmt->exact = exact;
switch (argc) {
@@ -1869,21 +1867,27 @@ static struct token *_parse_context_stat
sparse_error(token->pos, "__context__ statement needs argument(s)");
return token;
case 1:
- /* already done */
+ stmt->change = get_expression_value(args[0]);
break;
case 2:
- if (args[0]->type != STMT_EXPRESSION) {
+ /*
+ * We should actually check whether we can evalulate
+ * it as a constant expression and if so use as the
+ * 'change' value. I hope nobody gives a calculation
+ * for the number.
+ */
+ if (args[0]->type != EXPR_VALUE) {
stmt->context = args[0];
- stmt->expression = args[1];
+ stmt->change = get_expression_value(args[1]);
} else {
- stmt->expression = args[0];
- stmt->required = args[1];
+ stmt->change = get_expression_value(args[0]);
+ stmt->required = get_expression_value(args[1]);
}
break;
case 3:
stmt->context = args[0];
- stmt->expression = args[1];
- stmt->required = args[2];
+ stmt->change = get_expression_value(args[1]);
+ stmt->required = get_expression_value(args[2]);
break;
default:
sparse_error(token->pos, "too many arguments for __context__ statement");
--- sparse.orig/parse.h 2008-04-26 23:09:27.000000000 +0200
+++ sparse/parse.h 2008-04-26 23:44:32.000000000 +0200
@@ -39,10 +39,12 @@ struct statement {
struct symbol *label;
struct statement *label_statement;
};
- struct { /* __context__ */
+ struct { /* expression */
struct expression *expression;
+ };
+ struct { /* __context__ */
struct expression *context;
- struct expression *required;
+ int change, required;
int exact;
};
struct /* return_statement */ {
--- sparse.orig/validation/context.c 2008-04-26 23:09:27.000000000 +0200
+++ sparse/validation/context.c 2008-04-26 23:44:32.000000000 +0200
@@ -380,6 +380,32 @@ static int warn_conditional(void)
return 0;
}
+static void areq(void) __attribute__((context(1,2)))
+{
+ __context__(1,1);
+}
+
+static void good_reqlock(void)
+{
+ a();
+ areq();
+ r();
+ r();
+}
+
+static void warn_reqlock(void)
+{
+ areq();
+ r();
+}
+
+
+static void dummy1(void) __attribute__((context(p,0,1)))
+{
+ void *p;
+ __context__(p,1);
+}
+
/*
* check-name: Check -Wcontext
*
@@ -418,5 +444,7 @@ context.c:360:10: warning: context probl
context.c:360:10: default context: wanted >= 1, got 0
context.c:380:12: warning: context imbalance in 'warn_conditional': wrong count at exit
context.c:380:12: default context: wanted 0, got 1
+context.c:398:6: warning: context problem in 'warn_reqlock': 'areq' expected different context
+context.c:398:6: default context: wanted >= 1, got 0
* check-error-end
*/
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 4/5] revert the conditional_context patch
2008-04-27 11:31 [PATCH 0/5] more sparse context tracking improvements Johannes Berg
` (2 preceding siblings ...)
2008-04-27 11:31 ` [PATCH 3/5] evaluate/expand context expressions Johannes Berg
@ 2008-04-27 11:31 ` Johannes Berg
2008-04-27 11:31 ` [PATCH 5/5] check context expressions as expressions Johannes Berg
4 siblings, 0 replies; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 11:31 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
[-- Attachment #1: 005-remove-dynamic.patch --]
[-- Type: text/plain, Size: 16398 bytes --]
This patch removes the conditional_context attribute again, it turned
out that my attempt to do this was rather misguided and contrary to
what I thought we do not gain anything at all over using macros for
it as the kernel and the tests have been doing for a while.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
linearize.c | 32 +++++---
linearize.h | 2
parse.c | 52 -------------
sparse.1 | 9 --
sparse.c | 39 +++------
symbol.h | 2
validation/context-dynamic.c | 171 -------------------------------------------
7 files changed, 37 insertions(+), 270 deletions(-)
--- sparse.orig/linearize.c 2008-04-27 03:10:44.000000000 +0200
+++ sparse/linearize.c 2008-04-27 03:16:56.000000000 +0200
@@ -437,7 +437,7 @@ const char *show_instruction(struct inst
break;
case OP_CONTEXT:
- buf += sprintf(buf, "%s%d,%d", "", insn->increment, insn->inc_false);
+ buf += sprintf(buf, "%d", insn->increment);
break;
case OP_RANGE:
buf += sprintf(buf, "%s between %s..%s", show_pseudo(insn->src1), show_pseudo(insn->src2), show_pseudo(insn->src3));
@@ -958,7 +958,7 @@ static pseudo_t linearize_store_gen(stru
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->source_type;
insn->exact = context->exact;
@@ -971,7 +971,7 @@ static pseudo_t linearize_store_gen(stru
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->result_type;
insn->exact = context->exact;
@@ -986,7 +986,7 @@ static pseudo_t linearize_store_gen(stru
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->address->sym;
insn->exact = context->exact;
@@ -1047,7 +1047,7 @@ static pseudo_t linearize_load_gen(struc
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->source_type;
insn->exact = context->exact;
@@ -1060,7 +1060,7 @@ static pseudo_t linearize_load_gen(struc
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->result_type;
insn->exact = context->exact;
@@ -1075,7 +1075,7 @@ static pseudo_t linearize_load_gen(struc
continue;
insn = alloc_instruction(OP_CONTEXT, 0);
insn->required = context->in;
- insn->increment = insn->inc_false = context->out - context->in;
+ insn->increment = context->out - context->in;
insn->context_expr = context->context;
insn->access_var = ad->address->sym;
insn->exact = context->exact;
@@ -1320,12 +1320,21 @@ static pseudo_t linearize_call_expressio
FOR_EACH_PTR(ctype->contexts, context) {
int in = context->in;
int out = context->out;
-
- if (out - in || context->out_false - in) {
+ int check = 0;
+ int context_diff;
+ if (in < 0) {
+ check = 1;
+ in = 0;
+ }
+ if (out < 0) {
+ check = 0;
+ out = 0;
+ }
+ context_diff = out - in;
+ if (check || context_diff) {
insn = alloc_instruction(OP_CONTEXT, 0);
- insn->increment = out - in;
+ insn->increment = context_diff;
insn->context_expr = context->context;
- insn->inc_false = context->out_false - in;
add_one_insn(ep, insn);
}
} END_FOR_EACH_PTR(context);
@@ -1755,7 +1764,6 @@ static pseudo_t linearize_context(struct
struct instruction *insn = alloc_instruction(OP_CONTEXT, 0);
insn->increment = stmt->change;
- insn->inc_false = stmt->change;
insn->required = stmt->required;
insn->exact = stmt->exact;
--- sparse.orig/parse.c 2008-04-27 03:10:44.000000000 +0200
+++ sparse/parse.c 2008-04-27 03:10:52.000000000 +0200
@@ -65,7 +65,6 @@ static struct token *attribute_address_s
static struct token *attribute_aligned(struct token *token, struct symbol *attr, struct ctype *ctype);
static struct token *attribute_mode(struct token *token, struct symbol *attr, struct ctype *ctype);
static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype);
-static struct token *attribute_conditional_context(struct token *token, struct symbol *attr, struct ctype *ctype);
static struct token *attribute_exact_context(struct token *token, struct symbol *attr, struct ctype *ctype);
static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype);
static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct ctype *ctype);
@@ -189,10 +188,6 @@ static struct symbol_op context_op = {
.attribute = attribute_context,
};
-static struct symbol_op conditional_context_op = {
- .attribute = attribute_conditional_context,
-};
-
static struct symbol_op exact_context_op = {
.attribute = attribute_exact_context,
};
@@ -279,7 +274,6 @@ static struct init_keyword {
{ "address_space",NS_KEYWORD, .op = &address_space_op },
{ "mode", NS_KEYWORD, .op = &mode_op },
{ "context", NS_KEYWORD, .op = &context_op },
- { "conditional_context", NS_KEYWORD, .op = &conditional_context_op },
{ "exact_context", NS_KEYWORD, .op = &exact_context_op },
{ "__transparent_union__", NS_KEYWORD, .op = &transparent_union_op },
@@ -944,7 +938,6 @@ static struct token *_attribute_context(
}
context->exact = exact;
- context->out_false = context->out;
if (argc)
add_ptr_list(&ctype->contexts, context);
@@ -963,51 +956,6 @@ static struct token *attribute_exact_con
return _attribute_context(token, attr, ctype, 1);
}
-static struct token *attribute_conditional_context(struct token *token, struct symbol *attr, struct ctype *ctype)
-{
- struct context *context = alloc_context();
- struct expression *args[4];
- int argc = 0;
-
- token = expect(token, '(', "after conditional_context attribute");
- while (!match_op(token, ')')) {
- struct expression *expr = NULL;
- token = conditional_expression(token, &expr);
- if (!expr)
- break;
- if (argc < 4)
- args[argc++] = expr;
- else
- argc++;
- if (!match_op(token, ','))
- break;
- token = token->next;
- }
-
- switch(argc) {
- case 3:
- context->in = get_expression_value(args[0]);
- context->out = get_expression_value(args[1]);
- context->out_false = get_expression_value(args[2]);
- break;
- case 4:
- context->context = args[0];
- context->in = get_expression_value(args[1]);
- context->out = get_expression_value(args[2]);
- context->out_false = get_expression_value(args[3]);
- break;
- default:
- sparse_error(token->pos, "invalid number of arguments to conditional_context attribute");
- break;
- }
-
- if (argc)
- add_ptr_list(&ctype->contexts, context);
-
- token = expect(token, ')', "after conditional_context attribute");
- return token;
-}
-
static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype)
{
if (Wtransparent_union)
--- sparse.orig/sparse.1 2008-04-27 03:10:44.000000000 +0200
+++ sparse/sparse.1 2008-04-27 03:10:52.000000000 +0200
@@ -101,15 +101,6 @@ be required on both reads and writes) by
the token "write" for an optional fourth argument:
.BI __attribute__((context( expression , in_context , out_context , read|write )).
-To indicate that a certain function acquires a context depending on its
-return value, use
-.BI __attribute__((conditional_context( [expression ,] in_context , out_success , out_failure ))
-where \fIout_success\fR and \fIout_failure\fR indicate the context change
-done depending on success (non-zero) or failure (zero) return of the
-function. Note that currently, using this attribute on a function means that
-the function itself won't be checked for context handling at all. See the
-testsuite for examples.
-
Sparse will warn when it sees a function change a
context without indicating this with a \fBcontext\fR or \fBexact_context\fR attribute, either by
decreasing a context below zero (such as by releasing a lock without acquiring
--- sparse.orig/sparse.c 2008-04-27 03:10:44.000000000 +0200
+++ sparse/sparse.c 2008-04-27 03:14:26.000000000 +0200
@@ -25,7 +25,7 @@
#include "linearize.h"
struct context_check {
- int val, val_false;
+ int val;
char name[32];
};
@@ -44,7 +44,7 @@ static const char *context_name(struct c
}
static void context_add(struct context_check_list **ccl, const char *name,
- int offs, int offs_false)
+ int offs)
{
struct context_check *check, *found = NULL;
@@ -62,7 +62,6 @@ static void context_add(struct context_c
add_ptr_list(ccl, found);
}
found->val += offs;
- found->val_false += offs_false;
}
static int context_list_has(struct context_check_list *ccl,
@@ -73,12 +72,11 @@ static int context_list_has(struct conte
FOR_EACH_PTR(ccl, check) {
if (strcmp(c->name, check->name))
continue;
- return check->val == c->val &&
- check->val_false == c->val_false;
+ return check->val == c->val;
} END_FOR_EACH_PTR(check);
/* not found is equal to 0 */
- return c->val == 0 && c->val_false == 0;
+ return c->val == 0;
}
static int context_lists_equal(struct context_check_list *ccl1,
@@ -107,7 +105,7 @@ static struct context_check_list *checke
struct context_check *c;
FOR_EACH_PTR(ccl, c) {
- context_add(&result, c->name, c->val_false, c->val_false);
+ context_add(&result, c->name, c->val);
} END_FOR_EACH_PTR(c);
return result;
@@ -140,7 +138,7 @@ static int context_list_check(struct ent
/* make sure the loop below checks all */
FOR_EACH_PTR(ccl_target, c1) {
- context_add(&ccl_cur, c1->name, 0, 0);
+ context_add(&ccl_cur, c1->name, 0);
} END_FOR_EACH_PTR(c1);
FOR_EACH_PTR(ccl_cur, c1) {
@@ -289,15 +287,14 @@ static int handle_context(struct entrypo
return -1;
}
- context_add(combined, name, insn->increment, insn->inc_false);
+ context_add(combined, name, insn->increment);
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,
- int in_false)
+ struct context_check_list *ccl_target)
{
struct context_check_list *combined = NULL, *done;
struct context_check *c;
@@ -327,10 +324,7 @@ static int check_bb_context(struct entry
* 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);
- else
- context_add(&combined, c->name, c->val, c->val);
+ context_add(&combined, c->name, c->val);
} END_FOR_EACH_PTR(c);
/* Add the new context to the list of already-checked contexts */
@@ -356,18 +350,18 @@ static int check_bb_context(struct entry
case OP_BR:
if (insn->bb_true)
if (check_bb_context(ep, insn->bb_true,
- combined, ccl_target, 0))
+ combined, ccl_target))
goto out;
if (insn->bb_false)
if (check_bb_context(ep, insn->bb_false,
- combined, ccl_target, 1))
+ combined, ccl_target))
goto out;
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))
+ combined, ccl_target))
goto out;
} END_FOR_EACH_PTR(mj);
break;
@@ -579,14 +573,11 @@ static void check_context(struct entrypo
FOR_EACH_PTR(sym->ctype.contexts, context) {
const char *name = context_name(context);
- context_add(&ccl_in, name, context->in, context->in);
- context_add(&ccl_target, name, context->out, context->out_false);
- /* we don't currently check the body of trylock functions */
- if (context->out != context->out_false)
- return;
+ context_add(&ccl_in, name, context->in);
+ context_add(&ccl_target, name, context->out);
} END_FOR_EACH_PTR(context);
- check_bb_context(ep, ep->entry->bb, ccl_in, ccl_target, 0);
+ check_bb_context(ep, ep->entry->bb, ccl_in, ccl_target);
free_ptr_list(&ccl_in);
free_ptr_list(&ccl_target);
free_bb_context_lists(ep->entry->bb);
--- sparse.orig/symbol.h 2008-04-27 03:10:44.000000000 +0200
+++ sparse/symbol.h 2008-04-27 03:10:52.000000000 +0200
@@ -77,7 +77,7 @@ enum context_read_write_specifier {
struct context {
struct expression *context;
- unsigned int in, out, out_false;
+ unsigned int in, out;
int exact;
enum context_read_write_specifier rws;
};
--- sparse.orig/validation/context-dynamic.c 2008-04-27 03:10:44.000000000 +0200
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,171 +0,0 @@
-static void a(void) __attribute__ ((context(A, 0, 1)))
-{
- __context__(A, 1);
-}
-
-static void r(void) __attribute__ ((context(A, 1, 0)))
-{
- __context__(A, -1);
-}
-
-extern int condition, condition2;
-
-static int tl(void) __attribute__ ((conditional_context(A, 0, 1, 0)))
-{
- if (condition) {
- a();
- return 1;
- }
- return 0;
-}
-
-static int tl2(void) __attribute__ ((conditional_context(A, 0, 0, 1)))
-{
- if (condition) {
- a();
- return 1;
- }
- return 0;
-}
-
-static int dummy(void)
-{
- return condition + condition2;
-}
-
-static int good_trylock1(void)
-{
- if (tl()) {
- r();
- }
-}
-
-static int good_trylock2(void)
-{
- if (tl()) {
- r();
- }
-
- if (tl()) {
- r();
- }
-}
-static int good_trylock3(void)
-{
- a();
- if (tl()) {
- r();
- }
- r();
- if (tl()) {
- r();
- }
-}
-
-static int good_trylock4(void)
-{
- a();
- if (tl()) {
- r();
- }
- if (tl()) {
- r();
- }
- r();
-}
-
-static void bad_trylock1(void)
-{
- a();
- if (dummy()) {
- r();
- }
- r();
-}
-
-static int good_trylock5(void)
-{
- if (!tl2()) {
- r();
- }
-}
-
-static int good_trylock6(void)
-{
- if (!tl2()) {
- r();
- }
-
- if (!tl2()) {
- r();
- }
-}
-static int good_trylock7(void)
-{
- a();
- if (!tl2()) {
- r();
- }
- r();
- if (!tl2()) {
- r();
- }
-}
-
-static int good_trylock8(void)
-{
- a();
- if (!tl2()) {
- r();
- }
- if (!tl2()) {
- r();
- }
- r();
-}
-
-static void bad_trylock2(void)
-{
- a();
- if (!dummy()) {
- r();
- }
- r();
-}
-
-static int good_switch(void)
-{
- switch (condition) {
- case 1:
- a();
- break;
- case 2:
- a();
- break;
- case 3:
- a();
- break;
- default:
- a();
- }
- 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': '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
- */
--- sparse.orig/linearize.h 2008-04-27 03:10:44.000000000 +0200
+++ sparse/linearize.h 2008-04-27 03:11:58.000000000 +0200
@@ -116,7 +116,7 @@ struct instruction {
struct pseudo_list *arguments;
};
struct /* context */ {
- int increment, required, inc_false, exact;
+ int increment, required, exact;
struct expression *context_expr;
struct symbol *access_var;
};
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 5/5] check context expressions as expressions
2008-04-27 11:31 [PATCH 0/5] more sparse context tracking improvements Johannes Berg
` (3 preceding siblings ...)
2008-04-27 11:31 ` [PATCH 4/5] revert the conditional_context patch Johannes Berg
@ 2008-04-27 11:31 ` Johannes Berg
2008-04-27 12:23 ` [PATCH 6/5] test conditional result locking Johannes Berg
4 siblings, 1 reply; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 11:31 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
[-- Attachment #1: 006-context-expressions.patch --]
[-- Type: text/plain, Size: 32449 bytes --]
This patch makes sparse evaluate context expressions allowing this:
struct test {
lock_t lock;
int i;
};
extern void r(struct test *t) __attribute__((context(&t->lock,0,1)));
extern struct test *find(int i) __attribute__((context(&RESULT->lock,1,0)));
void test(void)
{
struct test *x = find(42);
r(x);
r(x);
}
to work the way you think it would.
This works by rewriting the given attribute expression into __context__
statements and evaluating those in the caller scope.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
Somewhat inspired by Philipp's patch. When it warns, the expression is
given as evaluated, e.g. in above case would result in a warning about
"**x+0". We can fix that later by keeping the original expression and
not expanding/evaluating it, but we need to do both for it to work.
evaluate.c | 18 ++-
expand.c | 6 +
expression.c | 272 +++++++++++++++++++++++++++++++++++++++++++++-
expression.h | 7 +
ident-list.h | 1
inline.c | 4
linearize.c | 63 ++++++----
linearize.h | 1
parse.c | 17 ++
parse.h | 1
sparse.c | 144 ++++++------------------
symbol.h | 4
validation/context-vars.c | 171 ++++++++++++++++++++++++++++
13 files changed, 575 insertions(+), 134 deletions(-)
--- sparse.orig/expression.c 2008-04-27 10:45:03.000000000 +0200
+++ sparse/expression.c 2008-04-27 11:05:30.000000000 +0200
@@ -27,6 +27,8 @@
#include "expression.h"
#include "target.h"
+struct expression *current_assignment_expression = NULL;
+
static int match_oplist(int op, ...)
{
va_list args;
@@ -509,6 +511,63 @@ static struct token *expression_list(str
return token;
}
+static int ident_equal(struct ident *ident1, struct ident *ident2)
+{
+ if (ident1 == ident2)
+ return 1;
+ if (!ident1 || !ident2)
+ return 0;
+
+ return ident1->len == ident2->len &&
+ !strncmp(ident1->name, ident2->name, ident1->len);
+}
+
+/* TODO: this is probably not complete */
+void replace_ident(struct expression **_in, struct ident *s, struct expression *r)
+{
+ struct expression *in = *_in;
+
+ switch (in->type) {
+ case EXPR_SYMBOL:
+ if (ident_equal(in->symbol_name, s))
+ *_in = r;
+ break;
+ case EXPR_IDENTIFIER:
+ if (ident_equal(in->expr_ident, s))
+ *_in = r;
+ break;
+ case EXPR_BINOP:
+ case EXPR_COMMA:
+ case EXPR_ASSIGNMENT:
+ case EXPR_COMPARE:
+ case EXPR_LOGICAL:
+ replace_ident(&in->left, s, r);
+ replace_ident(&in->right, s, r);
+ break;
+ case EXPR_DEREF:
+ replace_ident(&in->deref, s, r);
+ break;
+ case EXPR_PREOP:
+ case EXPR_POSTOP:
+ replace_ident(&in->unop, s, r);
+ break;
+ case EXPR_CAST:
+ case EXPR_FORCE_CAST:
+ case EXPR_IMPLIED_CAST:
+ case EXPR_SIZEOF:
+ replace_ident(&in->cast_expression, s, r);
+ break;
+ case EXPR_SLICE:
+ replace_ident(&in->base, s, r);
+ break;
+ case EXPR_CONDITIONAL:
+ replace_ident(&in->conditional, s, r);
+ replace_ident(&in->cond_true, s, r);
+ replace_ident(&in->cond_false, s, r);
+ break;
+ }
+}
+
/*
* extend to deal with the ambiguous C grammar for parsing
* a cast expressions followed by an initializer.
@@ -570,10 +629,50 @@ static struct token *postfix_expression(
case '(': { /* Function call */
struct expression *call = alloc_expression(token->pos, EXPR_CALL);
+ struct symbol *fn = NULL;
+ struct context *c;
+
+ if (expr->symbol_name)
+ fn = lookup_symbol(expr->symbol_name, NS_SYMBOL);
call->op = '(';
call->fn = expr;
token = expression_list(token->next, &call->args);
token = expect(token, ')', "in function call");
+
+ if (fn && fn->ctype.base_type) {
+ FOR_EACH_PTR(fn->ctype.contexts, c) {
+ struct context *copy = alloc_context();
+ struct symbol *fn_arg;
+ struct expression *passed_arg;
+
+ copy->in = c->in;
+ copy->out = c->out;
+ copy->exact = c->exact;
+ add_ptr_list(&call->contexts, copy);
+
+ if (!c->token)
+ continue;
+
+ /* re-parse the token at this place */
+ conditional_expression(c->token, ©->context);
+
+ copy->context->pos = expr->pos;
+
+ if (current_assignment_expression)
+ replace_ident(©->context, &RESULT_ident,
+ current_assignment_expression);
+
+ /* and replace the arg */
+ PREPARE_PTR_LIST(fn->ctype.base_type->arguments, fn_arg);
+ FOR_EACH_PTR(call->args, passed_arg);
+ if (fn_arg)
+ replace_ident(©->context, fn_arg->ident, passed_arg);
+ NEXT_PTR_LIST(fn_arg);
+ END_FOR_EACH_PTR(passed_arg);
+ FINISH_PTR_LIST(fn_arg);
+ } END_FOR_EACH_PTR(c);
+ }
+
expr = call;
continue;
}
@@ -894,6 +993,7 @@ struct token *conditional_expression(str
struct token *assignment_expression(struct token *token, struct expression **tree)
{
+ struct expression *old_cae = current_assignment_expression;
token = conditional_expression(token, tree);
if (*tree && token_type(token) == TOKEN_SPECIAL) {
static const int assignments[] = {
@@ -904,15 +1004,19 @@ struct token *assignment_expression(stru
SPECIAL_SHR_ASSIGN, SPECIAL_AND_ASSIGN,
SPECIAL_OR_ASSIGN, SPECIAL_XOR_ASSIGN };
int i, op = token->special;
+ if (op == '=')
+ current_assignment_expression = *tree;
for (i = 0; i < sizeof(assignments)/sizeof(int); i++)
if (assignments[i] == op) {
struct expression * expr = alloc_expression(token->pos, EXPR_ASSIGNMENT);
expr->left = *tree;
expr->op = op;
*tree = expr;
- return assignment_expression(token->next, &expr->right);
+ token = assignment_expression(token->next, &expr->right);
+ break;
}
}
+ current_assignment_expression = old_cae;
return token;
}
@@ -929,4 +1033,170 @@ struct token *parse_expression(struct to
return comma_expression(token,tree);
}
+int expressions_equal(const struct expression *expr1,
+ const struct expression *expr2)
+{
+ if (expr1 == expr2)
+ return 1;
+
+ if (expr1 == NULL || expr2 == NULL)
+ return 0;
+
+ /* Is this the right way to handle casts? */
+ if (expr1->type == EXPR_CAST ||
+ expr1->type == EXPR_FORCE_CAST ||
+ expr1->type == EXPR_IMPLIED_CAST)
+ return expressions_equal(expr1->cast_expression, expr2);
+
+ if (expr2->type == EXPR_CAST ||
+ expr2->type == EXPR_FORCE_CAST ||
+ expr2->type == EXPR_IMPLIED_CAST)
+ return expressions_equal(expr2->cast_expression, expr1);
+
+ if (expr1->type != expr2->type)
+ return 0;
+
+ switch (expr1->type) {
+ case EXPR_SYMBOL:
+ return ident_equal(expr1->symbol_name, expr2->symbol_name);
+
+ case EXPR_VALUE:
+ return expr1->value == expr2->value;
+
+ case EXPR_FVALUE:
+ return expr1->fvalue == expr2->fvalue;
+
+ case EXPR_STRING:
+ return expr1->string->length == expr2->string->length &&
+ !strncmp(expr1->string->data, expr2->string->data, expr1->string->length);
+
+ case EXPR_BINOP:
+ return expr1->op == expr2->op &&
+ expressions_equal(expr1->left, expr2->left) &&
+ expressions_equal(expr1->right, expr2->right);
+
+ case EXPR_COMMA:
+ case EXPR_ASSIGNMENT:
+ return expressions_equal(expr1->left, expr2->left) &&
+ expressions_equal(expr1->right, expr2->right);
+
+ case EXPR_DEREF:
+ return expressions_equal(expr1->deref, expr2->deref) &&
+ ident_equal(expr1->member, expr2->member);
+
+ case EXPR_PREOP:
+ case EXPR_POSTOP:
+ return expr1->op == expr2->op &&
+ expressions_equal(expr1->unop, expr2->unop);
+
+ /* Not needed right now, but for sake of completness ...
+ case EXPR_LABEL:
+ case EXPR_STATEMENT:
+ case EXPR_CALL:
+ case EXPR_LOGICAL:
+ case EXPR_COMPARE:
+ case EXPR_SELECT:
+ case EXPR_CONDITIONAL:
+ case EXPR_CAST:
+ case EXPR_FORCE_CAST:
+ case EXPR_IMPLIED_CAST:
+ case EXPR_SLICE:
+ case EXPR_INITIALIZER:
+ case EXPR_POS:
+ */
+
+ default:
+ /* nothing, we should already have had a warning */
+ ;
+ }
+
+ return 0;
+}
+
+static int ident_str(struct ident *ident, char *buffer, int length)
+{
+ if (!ident)
+ return 0;
+ return snprintf(buffer, length, "%.*s", ident->len, ident->name);
+}
+
+int expression_str(const struct expression *expr,
+ char *buffer, int length)
+{
+ int n;
+
+ memset(buffer, 0, length);
+
+ if (!expr)
+ return 0;
+
+ /* TODO, think about necessary parentheses () */
+ switch (expr->type) {
+ case EXPR_SYMBOL:
+ return ident_str(expr->symbol_name, buffer, length);
+
+ case EXPR_VALUE:
+ return snprintf(buffer, length, "%llu", expr->value);
+
+ case EXPR_FVALUE:
+ return snprintf(buffer, length, "%Lf", expr->fvalue);
+
+ case EXPR_STRING:
+ return snprintf(buffer, length, "\"%.*s\"", expr->string->length, expr->string->data);
+
+ case EXPR_BINOP:
+ n = expression_str(expr->left, buffer, length);
+ n += snprintf(buffer+n, length-n, "%c", expr->op);
+ n += expression_str(expr->right, buffer+n, length-n);
+ return n;
+
+ case EXPR_COMMA:
+ n = expression_str(expr->left, buffer, length);
+ n += snprintf(buffer+n, length-n, ",");
+ n += expression_str(expr->right, buffer+n, length-n);
+ return n;
+
+ case EXPR_ASSIGNMENT:
+ n = expression_str(expr->left, buffer, length);
+ n += snprintf(buffer+n, length-n, "=");
+ n += expression_str(expr->right, buffer+n, length-n);
+ return n;
+
+ case EXPR_DEREF:
+ if (expr->left->type == EXPR_PREOP &&
+ expr->left->op == '*') {
+ n = expression_str(expr->left->unop, buffer, length);
+ n += snprintf(buffer+n, length-n, "->");
+ n += ident_str(expr->member, buffer+n, length-n);
+ } else {
+ n = expression_str(expr->left, buffer, length);
+ n += snprintf(buffer+n, length-n, ".");
+ n += ident_str(expr->member, buffer+n, length-n);
+ }
+ return n;
+
+ case EXPR_PREOP:
+ n = snprintf(buffer, length, "%c", expr->op);
+ n += expression_str(expr->unop, buffer+n, length-n);
+ return n;
+
+ case EXPR_POSTOP:
+ n = expression_str(expr->unop, buffer, length);
+ n += snprintf(buffer+n, length-n, "%c", expr->op);
+ return n;
+
+ case EXPR_CAST:
+ case EXPR_FORCE_CAST:
+ case EXPR_IMPLIED_CAST:
+ /* todo: print out the cast type's ctype */
+ *buffer++ = '('; length--;
+ *buffer++ = ')'; length--;
+ return expression_str(expr->cast_expression, buffer, length) + 2;
+
+ default:
+ printf("Missing code in expression_str for %d\n", expr->type);
+ }
+
+ return 0;
+}
--- sparse.orig/expression.h 2008-04-27 10:45:03.000000000 +0200
+++ sparse/expression.h 2008-04-27 10:45:27.000000000 +0200
@@ -121,6 +121,7 @@ struct expression {
struct /* call_expr */ {
struct expression *fn;
struct expression_list *args;
+ struct context_list *contexts;
};
// EXPR_LABEL
struct /* label_expr */ {
@@ -216,4 +217,10 @@ struct token *compound_statement(struct
void cast_value(struct expression *expr, struct symbol *newtype,
struct expression *old, struct symbol *oldtype);
+int expressions_equal(const struct expression *expr1,
+ const struct expression *expr2);
+int expression_str(const struct expression *, char *buf, int buflen);
+struct expression *copy_expression(struct expression *expr);
+void replace_ident(struct expression **in, struct ident *s, struct expression *r);
+extern struct expression *current_assignment_expression;
#endif
--- sparse.orig/sparse.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/sparse.c 2008-04-27 11:04:41.000000000 +0200
@@ -26,7 +26,7 @@
struct context_check {
int val;
- char name[32];
+ const struct expression *expr;
};
DECLARE_ALLOCATOR(context_check);
@@ -34,22 +34,15 @@ DECLARE_PTR_LIST(context_check_list, str
DECLARE_PTR_LIST(context_list_list, struct context_check_list);
ALLOCATOR(context_check, "context check list");
-static const char *unnamed_context = "<unnamed>";
-static const char *context_name(struct context *context)
-{
- if (context->context && context->context->symbol_name)
- return show_ident(context->context->symbol_name);
- return unnamed_context;
-}
-
-static void context_add(struct context_check_list **ccl, const char *name,
+static void context_add(struct context_check_list **ccl,
+ const struct expression *expr,
int offs)
{
struct context_check *check, *found = NULL;
FOR_EACH_PTR(*ccl, check) {
- if (strcmp(name, check->name))
+ if (!expressions_equal(expr, check->expr))
continue;
found = check;
break;
@@ -57,8 +50,7 @@ static void context_add(struct context_c
if (!found) {
found = __alloc_context_check(0);
- strncpy(found->name, name, sizeof(found->name));
- found->name[sizeof(found->name) - 1] = '\0';
+ found->expr = expr;
add_ptr_list(ccl, found);
}
found->val += offs;
@@ -70,7 +62,7 @@ static int context_list_has(struct conte
struct context_check *check;
FOR_EACH_PTR(ccl, check) {
- if (strcmp(c->name, check->name))
+ if (!expressions_equal(c->expr, check->expr))
continue;
return check->val == c->val;
} END_FOR_EACH_PTR(check);
@@ -105,7 +97,7 @@ static struct context_check_list *checke
struct context_check *c;
FOR_EACH_PTR(ccl, c) {
- context_add(&result, c->name, c->val);
+ context_add(&result, c->expr, c->val);
} END_FOR_EACH_PTR(c);
return result;
@@ -115,15 +107,15 @@ static struct context_check_list *checke
#define CONTEXT_PROB "context problem in '%s': "
#define DEFAULT_CONTEXT_DESCR " default context: "
-static void get_context_string(char **buf, const char **name)
+static const char *get_context_string(char **buf, const char *name)
{
- if (strcmp(*name, unnamed_context)) {
- *buf = malloc(strlen(*name) + 16);
- sprintf(*buf, " context '%s': ", *name);
- *name = *buf;
+ if (strlen(name)) {
+ *buf = malloc(strlen(name) + 16);
+ sprintf(*buf, " context '%s': ", name);
+ return *buf;
} else {
- *name = DEFAULT_CONTEXT_DESCR;
*buf = NULL;
+ return DEFAULT_CONTEXT_DESCR;
}
}
@@ -133,12 +125,13 @@ static int context_list_check(struct ent
{
struct context_check *c1, *c2;
int cur, tgt;
- const char *name;
+ char name[1000];
char *buf;
+ const char *pname;
/* make sure the loop below checks all */
FOR_EACH_PTR(ccl_target, c1) {
- context_add(&ccl_cur, c1->name, 0);
+ context_add(&ccl_cur, c1->expr, 0);
} END_FOR_EACH_PTR(c1);
FOR_EACH_PTR(ccl_cur, c1) {
@@ -146,7 +139,7 @@ static int context_list_check(struct ent
tgt = 0;
FOR_EACH_PTR(ccl_target, c2) {
- if (strcmp(c2->name, c1->name))
+ if (!expressions_equal(c1->expr, c2->expr))
continue;
tgt = c2->val;
break;
@@ -162,11 +155,11 @@ static int context_list_check(struct ent
warning(pos, IMBALANCE_IN "unexpected unlock",
show_ident(ep->name->ident));
- name = c1->name;
- get_context_string(&buf, &name);
+ expression_str(c1->expr, name, sizeof(name));
+ pname = get_context_string(&buf, name);
info(pos, "%swanted %d, got %d",
- name, tgt, cur);
+ pname, tgt, cur);
free(buf);
@@ -176,83 +169,21 @@ static int context_list_check(struct ent
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, *cmp;
+ const char *cmp, *pname;
char *buf;
+ char name[1000];
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) {
+ if (expressions_equal(c->expr, insn->context_expr))
val = c->val;
- break;
- }
} END_FOR_EACH_PTR(c);
if (insn->exact) {
@@ -264,7 +195,8 @@ static int handle_context(struct entrypo
}
if (!ok && Wcontext) {
- get_context_string(&buf, &name);
+ expression_str(insn->context_expr, name, sizeof(name));
+ pname = get_context_string(&buf, name);
if (insn->access_var) {
char *symname = strdup(show_ident(insn->access_var->ident));
@@ -273,6 +205,13 @@ static int handle_context(struct entrypo
"access to '%s' requires different context",
show_ident(ep->name->ident), symname);
free(symname);
+ } else if (insn->called_fn) {
+ char *symname = strdup(show_ident(insn->called_fn->ident));
+ warning(insn->pos,
+ CONTEXT_PROB
+ "'%s' expected different context",
+ show_ident(ep->name->ident), symname);
+ free(symname);
} else {
warning(insn->pos,
CONTEXT_PROB
@@ -281,13 +220,13 @@ static int handle_context(struct entrypo
}
info(insn->pos, "%swanted %s%d, got %d",
- name, cmp, insn->required, val);
+ pname, cmp, insn->required, val);
free(buf);
return -1;
}
- context_add(combined, name, insn->increment);
+ context_add(combined, insn->context_expr, insn->increment);
return 0;
}
@@ -324,7 +263,7 @@ static int check_bb_context(struct entry
* for the conditional_context() attribute.
*/
FOR_EACH_PTR(ccl_in, c) {
- context_add(&combined, c->name, c->val);
+ context_add(&combined, c->expr, c->val);
} END_FOR_EACH_PTR(c);
/* Add the new context to the list of already-checked contexts */
@@ -338,11 +277,6 @@ static int check_bb_context(struct entry
*/
FOR_EACH_PTR(bb->insns, insn) {
switch (insn->opcode) {
- case OP_INLINED_CALL:
- case OP_CALL:
- if (handle_call(ep, bb, insn, combined))
- goto out;
- break;
case OP_CONTEXT:
if (handle_context(ep, bb, insn, &combined))
goto out;
@@ -571,10 +505,10 @@ static void check_context(struct entrypo
check_instructions(ep);
FOR_EACH_PTR(sym->ctype.contexts, context) {
- const char *name = context_name(context);
-
- context_add(&ccl_in, name, context->in);
- context_add(&ccl_target, name, context->out);
+ context_add(&ccl_in, context->in_fn,
+ context->in);
+ context_add(&ccl_target, context->in_fn,
+ context->out);
} END_FOR_EACH_PTR(context);
check_bb_context(ep, ep->entry->bb, ccl_in, ccl_target);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ sparse/validation/context-vars.c 2008-04-27 12:01:17.000000000 +0200
@@ -0,0 +1,171 @@
+static void a(void *p) __attribute__((context(p,0,1)))
+{
+ __context__(p,1);
+}
+
+static void r(void *p) __attribute__((context(p,1,0)))
+{
+ __context__(p,-1,1);
+}
+
+extern void *l1, *l2;
+
+static void good_paired1(void)
+{
+ a(l1);
+ r(l1);
+}
+
+static void good_paired2(void)
+{
+ a(l1);
+ r(l1);
+ a(l1);
+ r(l1);
+ a(l2);
+ r(l2);
+}
+
+static void good_paired3(void)
+{
+ a(l1);
+ a(l2);
+ r(l2);
+ r(l1);
+}
+
+static void good_lock1(void *lp) __attribute__((context(lp,0,1)))
+{
+ a(lp);
+}
+
+static void good_lock2(void *lp) __attribute__((context(lp,0,1)))
+{
+ a(lp);
+ r(lp);
+ a(lp);
+}
+
+extern void **v;
+
+static void warn_lock1(void)
+{
+ a(v[1]);
+}
+
+extern int condition;
+
+static void good_lock3(void)
+{
+ a(v[1]);
+ if (condition) {
+ a(v[2]);
+ r(v[2]);
+ }
+ r(v[1]);
+}
+
+#define cond_lock(x, c)\
+ ((c) ? ({ __context__(x,1); 1; }) : 0)
+
+#define trylock(x) \
+ cond_lock(x, _try_lock(x))
+
+extern void _try_lock(int *x);
+
+static int good_condlock1(void)
+{
+ if (trylock(v[0]))
+ r(v[0]);
+}
+
+static int good_condlock2(void)
+{
+ if (trylock(&condition))
+ r((void*)&condition);
+}
+
+extern void ai(int *p) __attribute__((context(p,0,1)));
+extern void ri(int *p) __attribute__((context(p,1,0)));
+
+struct test {
+ int lock;
+};
+
+static inline void unlock(struct test *y)
+ __attribute__((context(&y->lock,1,0)))
+{
+ ri(&y->lock);
+}
+
+static void good_lock4(struct test *t)
+ __attribute__((context(&t->lock,0,1)))
+{
+ ai(&t->lock);
+}
+
+extern int *find_locked(void) __attribute__((context(RESULT,0,1)));
+
+static void good_find_release1(void)
+{
+ int *p;
+
+ p = find_locked();
+ ri(p);
+}
+
+extern struct test *find_locked_struct(void) __attribute__((context(&RESULT->lock,0,1)));
+
+static void good_find_release2(void)
+{
+ struct test *t;
+
+ t = find_locked_struct();
+ unlock(t);
+}
+
+static void good_find_release3(void)
+{
+ struct test *t = find_locked_struct();
+ unlock(t);
+}
+
+static void warn_unlock(void)
+{
+ struct test *t;
+ /* check that the warning is here, not at the unlock definition */
+ unlock(t);
+}
+
+extern int _locked_struct_test(struct test *ls, int *flags);
+#define locked_struct_test(ls, flags) (( _locked_struct_test((ls), (flags)) ) ? ({ __context__(&ls->lock,1); 1;}) : 0)
+
+static inline void unlock2(struct test *y)
+ __attribute__((context(&y->lock,1,0)))
+{
+ unlock(y);
+}
+
+static void good_locked_val(void)
+{
+ struct test *t;
+ int flags;
+
+ if (!t || !locked_struct_test(t, &flags))
+ goto out;
+
+ unlock2(t);
+ out:
+ ;
+}
+
+/*
+ * check-name: Check -Wcontext with lock variables
+ *
+ * check-error-start
+context-vars.c:53:7: warning: context imbalance in 'warn_lock1': wrong count at exit
+context-vars.c:53:7: context '**v+4': wanted 0, got 1
+context-vars.c:137:11: warning: context problem in 'warn_unlock': 'unlock' expected different context
+context-vars.c:137:11: context '*t+0': wanted >= 1, got 0
+ * check-error-end
+ */
--- sparse.orig/evaluate.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/evaluate.c 2008-04-27 10:45:27.000000000 +0200
@@ -2954,8 +2954,16 @@ struct symbol *evaluate_expression(struc
return evaluate_alignof(expr);
case EXPR_DEREF:
return evaluate_member_dereference(expr);
- case EXPR_CALL:
+ case EXPR_CALL: {
+ struct context *c;
+ FOR_EACH_PTR(expr->contexts, c) {
+ if (c->context &&
+ (c->context->type != EXPR_SYMBOL ||
+ c->context->symbol))
+ evaluate_expression(c->context);
+ } END_FOR_EACH_PTR(c);
return evaluate_call(expr);
+ }
case EXPR_SELECT:
case EXPR_CONDITIONAL:
return evaluate_conditional_expression(expr);
@@ -3025,6 +3033,7 @@ static void check_duplicates(struct symb
static struct symbol *evaluate_symbol(struct symbol *sym)
{
struct symbol *base_type;
+ struct context *c;
if (!sym)
return sym;
@@ -3054,6 +3063,13 @@ static struct symbol *evaluate_symbol(st
evaluate_statement(base_type->stmt);
current_fn = curr;
+
+ FOR_EACH_PTR(sym->ctype.contexts, c) {
+ if (c->in_fn &&
+ (c->in_fn->type != EXPR_SYMBOL ||
+ c->in_fn->symbol))
+ evaluate_expression(c->in_fn);
+ } END_FOR_EACH_PTR(c);
}
return base_type;
--- sparse.orig/expand.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/expand.c 2008-04-27 10:45:27.000000000 +0200
@@ -1034,8 +1034,14 @@ int expand_symbol(struct symbol *sym)
retval = expand_expression(sym->initializer);
/* expand the body of the symbol */
if (base_type->type == SYM_FN) {
+ struct context *c;
+
if (base_type->stmt)
expand_statement(base_type->stmt);
+
+ FOR_EACH_PTR(sym->ctype.contexts, c) {
+ expand_expression(c->in_fn);
+ } END_FOR_EACH_PTR(c);
}
return retval;
}
--- sparse.orig/parse.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/parse.c 2008-04-27 10:45:28.000000000 +0200
@@ -879,12 +879,13 @@ static struct token *_attribute_context(
struct context *context = alloc_context();
struct expression *args[4];
int argc = 0;
- struct token *last = NULL;
+ struct token *first = NULL, *last = NULL;
token = expect(token, '(', "after context attribute");
while (!match_op(token, ')')) {
struct expression *expr = NULL;
last = token;
+ first = first ? : token;
token = conditional_expression(token, &expr);
if (!expr)
break;
@@ -910,12 +911,14 @@ static struct token *_attribute_context(
break;
case 3:
context->context = args[0];
+ context->token = first;
context->in = get_expression_value(args[1]);
context->out = get_expression_value(args[2]);
break;
case 4: {
const char *rw;
context->context = args[0];
+ context->token = first;
context->in = get_expression_value(args[1]);
context->out = get_expression_value(args[2]);
@@ -2096,6 +2099,7 @@ static struct token *parse_function_body
struct symbol *base_type = decl->ctype.base_type;
struct statement *stmt, **p;
struct symbol *arg;
+ struct context *c;
old_symbol_list = function_symbol_list;
if (decl->ctype.modifiers & MOD_INLINE) {
@@ -2124,6 +2128,11 @@ static struct token *parse_function_body
token = compound_statement(token->next, stmt);
+ FOR_EACH_PTR(decl->ctype.contexts, c) {
+ if (c->token)
+ conditional_expression(c->token, &c->in_fn);
+ } END_FOR_EACH_PTR(c);
+
end_function(decl);
if (!(decl->ctype.modifiers & MOD_INLINE))
add_symbol(list, decl);
@@ -2286,11 +2295,17 @@ struct token *external_declaration(struc
for (;;) {
if (!is_typedef && match_op(token, '=')) {
+ struct expression *old_cae = current_assignment_expression;
if (decl->ctype.modifiers & MOD_EXTERN) {
warning(decl->pos, "symbol with external linkage has initializer");
decl->ctype.modifiers &= ~MOD_EXTERN;
}
+ current_assignment_expression = alloc_expression(token->pos, EXPR_SYMBOL);
+ current_assignment_expression->symbol_name = decl->ident;
+ current_assignment_expression->symbol =
+ lookup_symbol(decl->ident, NS_SYMBOL | NS_TYPEDEF);
token = initializer(&decl->initializer, token->next);
+ current_assignment_expression = old_cae;
}
if (!is_typedef) {
if (!(decl->ctype.modifiers & (MOD_EXTERN | MOD_INLINE))) {
--- sparse.orig/symbol.h 2008-04-27 10:45:27.000000000 +0200
+++ sparse/symbol.h 2008-04-27 10:45:28.000000000 +0200
@@ -77,6 +77,10 @@ enum context_read_write_specifier {
struct context {
struct expression *context;
+ /* store the token pointer */
+ struct token *token;
+ /* to re-evaluate this context within the function it is for */
+ struct expression *in_fn;
unsigned int in, out;
int exact;
enum context_read_write_specifier rws;
--- sparse.orig/inline.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/inline.c 2008-04-27 10:45:28.000000000 +0200
@@ -56,7 +56,7 @@ static struct symbol_list *copy_symbol_l
return dst;
}
-static struct expression * copy_expression(struct expression *expr)
+struct expression *copy_expression(struct expression *expr)
{
if (!expr)
return NULL;
@@ -474,6 +474,7 @@ void copy_statement(struct statement *sr
dst->args = copy_one_statement(src->args);
dst->ret = copy_symbol(src->pos, src->ret);
dst->inline_fn = src->inline_fn;
+ dst->inlined_fn_expr = src->inlined_fn_expr;
}
static struct symbol *create_copy_symbol(struct symbol *orig)
@@ -555,6 +556,7 @@ int inline_function(struct expression *e
stmt->args = decl;
}
stmt->inline_fn = sym;
+ stmt->inlined_fn_expr = expr;
unset_replace_list(fn_symbol_list);
--- sparse.orig/linearize.c 2008-04-27 10:45:27.000000000 +0200
+++ sparse/linearize.c 2008-04-27 11:06:10.000000000 +0200
@@ -35,6 +35,7 @@ static pseudo_t linearize_initializer(st
struct pseudo void_pseudo = {};
static struct position current_pos;
+static int in_inline_skip_context = 0;
ALLOCATOR(pseudo_user, "pseudo_user");
@@ -436,9 +437,15 @@ const char *show_instruction(struct inst
buf += sprintf(buf, "%s <- %s", show_pseudo(insn->target), show_pseudo(insn->src1));
break;
- case OP_CONTEXT:
+ case OP_CONTEXT: {
+ char ctxbuf[100];
+ if (insn->context_expr) {
+ expression_str(insn->context_expr, ctxbuf, sizeof(ctxbuf));
+ buf += sprintf(buf, "%s, ", ctxbuf);
+ }
buf += sprintf(buf, "%d", insn->increment);
break;
+ }
case OP_RANGE:
buf += sprintf(buf, "%s between %s..%s", show_pseudo(insn->src1), show_pseudo(insn->src2), show_pseudo(insn->src3));
break;
@@ -1280,7 +1287,7 @@ static pseudo_t linearize_call_expressio
struct instruction *insn = alloc_typed_instruction(OP_CALL, expr->ctype);
pseudo_t retval, call;
struct ctype *ctype = NULL;
- struct context *context;
+ struct context *c;
if (!expr->ctype) {
warning(expr->pos, "call with no type!");
@@ -1316,29 +1323,17 @@ static pseudo_t linearize_call_expressio
insn->target = retval;
add_one_insn(ep, insn);
- if (ctype) {
- FOR_EACH_PTR(ctype->contexts, context) {
- int in = context->in;
- int out = context->out;
- int check = 0;
- int context_diff;
- if (in < 0) {
- check = 1;
- in = 0;
- }
- if (out < 0) {
- check = 0;
- out = 0;
- }
- context_diff = out - in;
- if (check || context_diff) {
- insn = alloc_instruction(OP_CONTEXT, 0);
- insn->increment = context_diff;
- insn->context_expr = context->context;
- add_one_insn(ep, insn);
- }
- } END_FOR_EACH_PTR(context);
- }
+ if (!in_inline_skip_context)
+ FOR_EACH_PTR(expr->contexts, c) {
+ struct instruction *tmp = alloc_instruction(OP_CONTEXT, 0);
+ tmp->increment = c->out - c->in;
+ tmp->exact = c->exact;
+ tmp->context_expr = c->context;
+ tmp->required = c->in;
+ tmp->called_fn = call->sym;
+ tmp->pos = insn->pos;
+ add_one_insn(ep, tmp);
+ } END_FOR_EACH_PTR(c);
return retval;
}
@@ -1712,6 +1707,8 @@ static pseudo_t linearize_compound_state
pseudo = VOID;
FOR_EACH_PTR(stmt->stmts, s) {
+ if (in_inline_skip_context && s->type == STMT_CONTEXT)
+ continue;
pseudo = linearize_statement(ep, s);
} END_FOR_EACH_PTR(s);
@@ -1739,6 +1736,7 @@ static pseudo_t linearize_inlined_call(s
struct statement *args = stmt->args;
struct basic_block *bb;
pseudo_t pseudo;
+ struct context *c;
if (args) {
struct symbol *sym;
@@ -1750,12 +1748,27 @@ static pseudo_t linearize_inlined_call(s
} END_FOR_EACH_PTR(sym);
}
+ in_inline_skip_context++;
insn->target = pseudo = linearize_compound_statement(ep, stmt);
+ in_inline_skip_context--;
use_pseudo(insn, symbol_pseudo(ep, stmt->inline_fn), &insn->func);
bb = ep->active;
if (bb && !bb->insns)
bb->pos = stmt->pos;
add_one_insn(ep, insn);
+
+ if (!in_inline_skip_context)
+ FOR_EACH_PTR(stmt->inlined_fn_expr->contexts, c) {
+ struct instruction *tmp = alloc_instruction(OP_CONTEXT, 0);
+ tmp->increment = c->out - c->in;
+ tmp->exact = c->exact;
+ tmp->context_expr = c->context;
+ tmp->required = c->in;
+ tmp->called_fn = stmt->inline_fn;
+ tmp->pos = insn->pos;
+ add_one_insn(ep, tmp);
+ } END_FOR_EACH_PTR(c);
+
return pseudo;
}
--- sparse.orig/parse.h 2008-04-27 10:45:27.000000000 +0200
+++ sparse/parse.h 2008-04-27 10:45:28.000000000 +0200
@@ -61,6 +61,7 @@ struct statement {
struct symbol *ret;
struct symbol *inline_fn;
struct statement *args;
+ struct expression *inlined_fn_expr;
};
struct /* labeled_struct */ {
struct symbol *label_identifier;
--- sparse.orig/linearize.h 2008-04-27 10:45:27.000000000 +0200
+++ sparse/linearize.h 2008-04-27 10:45:28.000000000 +0200
@@ -119,6 +119,7 @@ struct instruction {
int increment, required, exact;
struct expression *context_expr;
struct symbol *access_var;
+ struct symbol *called_fn;
};
struct /* asm */ {
const char *string;
--- sparse.orig/ident-list.h 2008-04-27 10:45:27.000000000 +0200
+++ sparse/ident-list.h 2008-04-27 10:45:28.000000000 +0200
@@ -98,6 +98,7 @@ __IDENT(__PRETTY_FUNCTION___ident, "__PR
IDENT_RESERVED(__context__);
IDENT_RESERVED(__exact_context__);
IDENT_RESERVED(__range__);
+IDENT_RESERVED(RESULT);
/* Magic function names we recognize */
IDENT(memset); IDENT(memcpy);
--
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 6/5] test conditional result locking
2008-04-27 11:31 ` [PATCH 5/5] check context expressions as expressions Johannes Berg
@ 2008-04-27 12:23 ` Johannes Berg
2008-04-27 12:45 ` [PATCH v2 " Johannes Berg
0 siblings, 1 reply; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 12:23 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
To test a function that can return a locked struct or NULL,
a macro has to be invented. Add a test case for that.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
This is a bit awkward but I don't see any good way to do it differently
since otherwise we'd have to track the assignment.
validation/context-vars.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
--- sparse.orig/validation/context-vars.c 2008-04-27 14:10:37.000000000 +0200
+++ sparse/validation/context-vars.c 2008-04-27 14:14:25.000000000 +0200
@@ -1,3 +1,5 @@
+#include <stddef.h>
+
static void a(void *p) __attribute__((context(p,0,1)))
{
__context__(p,1);
@@ -159,13 +161,31 @@ static void good_locked_val(void)
;
}
+
+extern struct test *_search(int key);
+
+#define search(res, key) do {\
+ res = _search((key)); \
+ (res ? ({ __context__(&res->lock,1); res; }) : NULL); \
+ } while (0)
+
+static void test(void)
+{
+ struct test *x;
+
+ search(x, 32);
+ if (x)
+ unlock(x);
+}
+
+
/*
* check-name: Check -Wcontext with lock variables
*
* check-error-start
-context-vars.c:53:7: warning: context imbalance in 'warn_lock1': wrong count at exit
-context-vars.c:53:7: context '**v+4': wanted 0, got 1
-context-vars.c:137:11: warning: context problem in 'warn_unlock': 'unlock' expected different context
-context-vars.c:137:11: context '*t+0': wanted >= 1, got 0
+context-vars.c:55:7: warning: context imbalance in 'warn_lock1': wrong count at exit
+context-vars.c:55:7: context '**v+4': wanted 0, got 1
+context-vars.c:139:11: warning: context problem in 'warn_unlock': 'unlock' expected different context
+context-vars.c:139:11: context '*t+0': wanted >= 1, got 0
* check-error-end
*/
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 6/5] test conditional result locking
2008-04-27 12:23 ` [PATCH 6/5] test conditional result locking Johannes Berg
@ 2008-04-27 12:45 ` Johannes Berg
0 siblings, 0 replies; 8+ messages in thread
From: Johannes Berg @ 2008-04-27 12:45 UTC (permalink / raw)
To: Josh Triplett; +Cc: linux-sparse, Philipp Reisner
To test a function that can return a locked struct or NULL,
a macro has to be invented. Add a test case for that.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
The macro was a mess, this one's much better. The key is to pass in the
result variable and use it in __context__.
validation/context-vars.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
--- sparse.orig/validation/context-vars.c 2008-04-27 14:10:37.000000000 +0200
+++ sparse/validation/context-vars.c 2008-04-27 14:41:41.000000000 +0200
@@ -1,3 +1,5 @@
+#include <stddef.h>
+
static void a(void *p) __attribute__((context(p,0,1)))
{
__context__(p,1);
@@ -159,13 +161,32 @@ static void good_locked_val(void)
;
}
+
+extern struct test *_search(int key);
+
+#define search(res, key) do { \
+ (res) = _search((key)); \
+ if (res) \
+ __context__(&(res)->lock,1);\
+ } while (0)
+
+static void test(void)
+{
+ struct test **x;
+
+ search(*x, 32);
+ if (*x)
+ unlock(*x);
+}
+
+
/*
* check-name: Check -Wcontext with lock variables
*
* check-error-start
-context-vars.c:53:7: warning: context imbalance in 'warn_lock1': wrong count at exit
-context-vars.c:53:7: context '**v+4': wanted 0, got 1
-context-vars.c:137:11: warning: context problem in 'warn_unlock': 'unlock' expected different context
-context-vars.c:137:11: context '*t+0': wanted >= 1, got 0
+context-vars.c:55:7: warning: context imbalance in 'warn_lock1': wrong count at exit
+context-vars.c:55:7: context '**v+4': wanted 0, got 1
+context-vars.c:139:11: warning: context problem in 'warn_unlock': 'unlock' expected different context
+context-vars.c:139:11: context '*t+0': wanted >= 1, got 0
* check-error-end
*/
^ permalink raw reply [flat|nested] 8+ messages in thread