From: Johannes Berg <johannes@sipsolutions.net>
To: Josh Triplett <josh@freedesktop.org>
Cc: Philipp Reisner <philipp.reisner@linbit.com>,
linux-sparse@vger.kernel.org
Subject: [PATCH 6/9] check context expressions as expressions
Date: Thu, 29 May 2008 10:54:08 +0200 [thread overview]
Message-ID: <20080529085516.930777000@sipsolutions.net> (raw)
In-Reply-To: 20080529085402.814224000@sipsolutions.net
[-- Attachment #1: 007-context-expressions.patch --]
[-- Type: text/plain, Size: 32597 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.
Note that there's a problem: You cannot give RESULT on a static function
that is declared there without getting an error in the function itself...
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);
--
next prev parent reply other threads:[~2008-05-29 9:03 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-29 8:54 [PATCH 0/9] context tracking updates Johannes Berg
2008-05-29 8:54 ` [PATCH 1/9] add test for acquire/release Johannes Berg
2008-05-29 8:54 ` [PATCH 2/9] add __exact_context__ Johannes Berg
2008-05-29 8:54 ` [PATCH 3/9] allow context() attribute on variables Johannes Berg
2008-05-29 8:54 ` [PATCH 4/9] evaluate/expand context expressions Johannes Berg
2008-05-29 8:54 ` [PATCH 5/9] revert the conditional_context patch Johannes Berg
2008-05-29 8:54 ` Johannes Berg [this message]
2008-09-10 7:33 ` [PATCH 6/9 v2] check context expressions as expressions Johannes Berg
2008-09-10 19:21 ` Christopher Li
2008-09-10 21:34 ` Johannes Berg
2008-09-11 0:15 ` Christopher Li
2008-05-29 8:54 ` [PATCH 7/9] test conditional result locking Johannes Berg
2008-05-29 8:54 ` [PATCH 8/9] show required context in instruction output Johannes Berg
2008-05-29 8:54 ` [PATCH 9/9] check inlines explicitly Johannes Berg
2008-05-29 23:14 ` [PATCH 9/9 v2] " Johannes Berg
2008-05-29 23:20 ` Harvey Harrison
2008-05-29 22:12 ` [PATCH 0/9] context tracking updates Harvey Harrison
2008-05-29 22:35 ` Harvey Harrison
2008-05-29 22:45 ` Johannes Berg
2008-05-29 22:47 ` Harvey Harrison
2008-05-29 22:51 ` Harvey Harrison
2008-05-29 22:54 ` Johannes Berg
2008-05-29 23:03 ` Pavel Roskin
2008-05-29 23:06 ` Johannes Berg
2008-05-29 23:15 ` Johannes Berg
2008-05-29 23:04 ` Johannes Berg
2008-07-20 12:30 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080529085516.930777000@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=josh@freedesktop.org \
--cc=linux-sparse@vger.kernel.org \
--cc=philipp.reisner@linbit.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.