[PATCH] fix handling of pointers in ?:

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



a) qualifiers are joined (const int * / volatile int * -> const volatile int *)
b) pointer to void / pointer to T => pointer to void (with all qualifiers)

testcase added

Still missing: T1 * / T2 * => pointer to composite type of T1 and T2

Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
---
 evaluate.c              |   82 ++++++++++++++++++++++++++++-------------------
 validation/cond_expr2.c |   23 +++++++++++++
 2 files changed, 72 insertions(+), 33 deletions(-)
 create mode 100644 validation/cond_expr2.c

diff --git a/evaluate.c b/evaluate.c
index d505007..9f543fe 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1070,31 +1070,6 @@ OK:
 }
 
 /*
- * FIXME!! This should do casts, array degeneration etc..
- */
-static struct symbol *compatible_ptr_type(struct expression *left, struct expression *right)
-{
-	struct symbol *ltype = left->ctype, *rtype = right->ctype;
-
-	if (ltype->type == SYM_NODE)
-		ltype = ltype->ctype.base_type;
-
-	if (rtype->type == SYM_NODE)
-		rtype = rtype->ctype.base_type;
-
-	if (ltype->type == SYM_PTR) {
-		if (rtype->ctype.base_type == &void_ctype)
-			return ltype;
-	}
-
-	if (rtype->type == SYM_PTR) {
-		if (ltype->ctype.base_type == &void_ctype)
-			return rtype;
-	}
-	return NULL;
-}
-
-/*
  * NOTE! The degenerate case of "x ? : y", where we don't
  * have a true case, this will possibly promote "x" to the
  * same type as "y", and thus _change_ the conditional
@@ -1104,9 +1079,10 @@ static struct symbol *compatible_ptr_type(struct expression *left, struct expres
 static struct symbol *evaluate_conditional_expression(struct expression *expr)
 {
 	struct expression **true;
-	struct symbol *ctype, *ltype, *rtype;
+	struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;
 	int lclass, rclass;
 	const char * typediff;
+	int qual;
 
 	if (!evaluate_conditional(expr->conditional, 0))
 		return NULL;
@@ -1141,9 +1117,11 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
 		expr->cond_false = cast_to(expr->cond_false, ctype);
 		goto out;
 	}
+
 	if ((lclass | rclass) & TYPE_PTR) {
 		int is_null1 = is_null_pointer_constant(*true);
 		int is_null2 = is_null_pointer_constant(expr->cond_false);
+
 		if (is_null1 && is_null2) {
 			*true = cast_to(*true, &ptr_ctype);
 			expr->cond_false = cast_to(expr->cond_false, &ptr_ctype);
@@ -1169,15 +1147,42 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
 			goto Err;
 		}
 		/* OK, it's pointer on pointer */
-		/* XXX - we need to handle qualifiers */
-		ctype = compatible_ptr_type(*true, expr->cond_false);
-		if (ctype)
-			goto out;
+		if (ltype->ctype.as != rtype->ctype.as) {
+			typediff = "different address spaces";
+			goto Err;
+		}
+
+		/* need to be lazier here */
+		lbase = get_base_type(ltype);
+		rbase = get_base_type(rtype);
+		qual = ltype->ctype.modifiers | rtype->ctype.modifiers;
+		qual &= MOD_CONST | MOD_VOLATILE;
+
+		if (lbase == &void_ctype) {
+			/* XXX: pointers to function should warn here */
+			ctype = ltype;
+			goto Qual;
+
+		}
+		if (rbase == &void_ctype) {
+			/* XXX: pointers to function should warn here */
+			ctype = rtype;
+			goto Qual;
+		}
+		/* XXX: that should be pointer to composite */
+		ctype = ltype;
+		typediff = type_difference(lbase, rbase, MOD_IGN, MOD_IGN);
+		if (!typediff)
+			goto Qual;
+		goto Err;
 	}
-	ctype = ltype;
-	typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN);
-	if (!typediff)
+
+	/* void on void, struct on same struct, union on same union */
+	if (ltype == rtype) {
+		ctype = ltype;
 		goto out;
+	}
+	typediff = "different base types";
 
 Err:
 	expression_error(expr, "incompatible types in conditional expression (%s)", typediff);
@@ -1186,6 +1191,17 @@ Err:
 out:
 	expr->ctype = ctype;
 	return ctype;
+
+Qual:
+	if (qual & ~ctype->ctype.modifiers) {
+		struct symbol *sym = alloc_symbol(ctype->pos, SYM_PTR);
+		*sym = *ctype;
+		sym->ctype.modifiers |= qual;
+		ctype = sym;
+	}
+	*true = cast_to(*true, ctype);
+	expr->cond_false = cast_to(expr->cond_false, ctype);
+	goto out;
 }
 
 /* FP assignments can not do modulo or bit operations */
diff --git a/validation/cond_expr2.c b/validation/cond_expr2.c
new file mode 100644
index 0000000..e53cd13
--- /dev/null
+++ b/validation/cond_expr2.c
@@ -0,0 +1,23 @@
+extern const int *p;
+extern volatile void *q;
+extern volatile int *r;
+static void f(void)
+{
+	q = 1 ? p : q;	// warn: const volatile void * -> const int *
+	r = 1 ? r : q;	// OK: volatile void * -> volatile int *
+	r = 1 ? r : p;	// warn: const volatile int * -> volatile int *
+}
+/*
+ * check-name: type of conditional expression
+ * check-description: Used to miss qualifier mixing and mishandle void *
+ * check-command: sparse $file
+ *
+ * check-output-start
+cond_expr2.c:6:4: warning: incorrect type in assignment (different modifiers)
+cond_expr2.c:6:4:    expected void volatile *extern [addressable] [toplevel] q
+cond_expr2.c:6:4:    got void const volatile *
+cond_expr2.c:8:4: warning: incorrect type in assignment (different modifiers)
+cond_expr2.c:8:4:    expected int volatile *extern [addressable] [toplevel] [assigned] r
+cond_expr2.c:8:4:    got int const volatile *
+ * check-output-end
+ */
-- 
1.5.0-rc2.GIT

-
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux