[PATCH 3/3] builtin: add support for __builtin_{add,sub,mul}_overflow(), ...

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

 



It seems they will be used in the kernel so add them.

Unlike __builtin_uadd_overflow() and friends, these don't take
a fixed type and thus can't simply be declared but need their
own evaluate() method to do the type checking.

Note: of course, no expansion is done on them.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
---
 builtin.c                     |  76 +++++++++++
 validation/builtin-overflow.c | 246 ++++++++++++++++++++++++++++++++++
 2 files changed, 322 insertions(+)
 create mode 100644 validation/builtin-overflow.c

diff --git a/builtin.c b/builtin.c
index 9fae8f2cc..9d7743927 100644
--- a/builtin.c
+++ b/builtin.c
@@ -251,6 +251,76 @@ static struct symbol_op fp_unop_op = {
 };
 
 
+static int args_overflow(struct expression *expr)
+{
+	return eval_args(expr, 3);
+}
+
+static int evaluate_overflow_gen(struct expression *expr, int ptr)
+{
+	struct expression *arg;
+	int n = 0;
+
+	/* there will be exactly 3; we'd already verified that */
+	FOR_EACH_PTR(expr->args, arg) {
+		struct symbol *type;
+
+		n++;
+		if (!arg || !(type = arg->ctype))
+			return 0;
+		// 1st & 2nd args must be a basic integer type
+		// 3rd arg must be a pointer to such a type.
+		if (n == 3 && ptr) {
+			if (type->type == SYM_NODE)
+				type = type->ctype.base_type;
+			if (!type)
+				return 0;
+			if (type->type != SYM_PTR)
+				goto err;
+			type = type->ctype.base_type;
+			if (!type)
+				return 0;
+		}
+		if (type->type == SYM_NODE)
+			type = type->ctype.base_type;
+		if (!type)
+			return 0;
+		if (type->ctype.base_type != &int_type || type == &bool_ctype)
+			goto err;
+	} END_FOR_EACH_PTR(arg);
+
+	// the builtin returns a bool
+	expr->ctype = &bool_ctype;
+	return 1;
+
+err:
+	sparse_error(arg->pos, "invalid type for argument %d:", n);
+	info(arg->pos, "        %s", show_typename(arg->ctype));
+	expr->ctype = &bad_ctype;
+	return 0;
+}
+
+static int evaluate_overflow(struct expression *expr)
+{
+	return evaluate_overflow_gen(expr, 1);
+}
+
+static struct symbol_op overflow_op = {
+	.args = args_overflow,
+	.evaluate = evaluate_overflow,
+};
+
+static int evaluate_overflow_p(struct expression *expr)
+{
+	return evaluate_overflow_gen(expr, 0);
+}
+
+static struct symbol_op overflow_p_op = {
+	.args = args_overflow,
+	.evaluate = evaluate_overflow_p,
+};
+
+
 /*
  * Builtin functions
  */
@@ -275,6 +345,12 @@ static struct sym_init {
 	{ "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
 	{ "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
 	{ "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+	{ "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+	{ "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
 	{ NULL,		NULL,		0 }
 };
 
diff --git a/validation/builtin-overflow.c b/validation/builtin-overflow.c
new file mode 100644
index 000000000..867eb42f5
--- /dev/null
+++ b/validation/builtin-overflow.c
@@ -0,0 +1,246 @@
+enum e { OK };
+typedef _Bool bool;
+
+static int test(int i, long l, long long ll, enum e e, bool b, void *p)
+{
+	int rc = 0;
+
+	// should be OK
+	rc += __builtin_add_overflow(i, i, &i);
+	rc += __builtin_add_overflow(l, i, &i);
+	rc += __builtin_add_overflow(i, l, &i);
+	rc += __builtin_add_overflow(i, i, &l);
+	rc += __builtin_add_overflow(ll, i, &i);
+	rc += __builtin_add_overflow(i, ll, &i);
+	rc += __builtin_add_overflow(i, i, &ll);
+
+	rc += __builtin_add_overflow_p(i, i, i);
+	rc += __builtin_add_overflow_p(l, i, i);
+	rc += __builtin_add_overflow_p(i, l, i);
+	rc += __builtin_add_overflow_p(i, i, l);
+	rc += __builtin_add_overflow_p(ll, i, i);
+	rc += __builtin_add_overflow_p(i, ll, i);
+	rc += __builtin_add_overflow_p(i, i, ll);
+
+	rc += __builtin_sub_overflow(i, i, &i);
+	rc += __builtin_sub_overflow(l, i, &i);
+	rc += __builtin_sub_overflow(i, l, &i);
+	rc += __builtin_sub_overflow(i, i, &l);
+	rc += __builtin_sub_overflow(ll, i, &i);
+	rc += __builtin_sub_overflow(i, ll, &i);
+	rc += __builtin_sub_overflow(i, i, &ll);
+
+	rc += __builtin_sub_overflow_p(i, i, i);
+	rc += __builtin_sub_overflow_p(l, i, i);
+	rc += __builtin_sub_overflow_p(i, l, i);
+	rc += __builtin_sub_overflow_p(i, i, l);
+	rc += __builtin_sub_overflow_p(ll, i, i);
+	rc += __builtin_sub_overflow_p(i, ll, i);
+	rc += __builtin_sub_overflow_p(i, i, ll);
+
+	rc += __builtin_mul_overflow(i, i, &i);
+	rc += __builtin_mul_overflow(l, i, &i);
+	rc += __builtin_mul_overflow(i, l, &i);
+	rc += __builtin_mul_overflow(i, i, &l);
+	rc += __builtin_mul_overflow(ll, i, &i);
+	rc += __builtin_mul_overflow(i, ll, &i);
+	rc += __builtin_mul_overflow(i, i, &ll);
+
+	rc += __builtin_mul_overflow_p(i, i, i);
+	rc += __builtin_mul_overflow_p(l, i, i);
+	rc += __builtin_mul_overflow_p(i, l, i);
+	rc += __builtin_mul_overflow_p(i, i, l);
+	rc += __builtin_mul_overflow_p(ll, i, i);
+	rc += __builtin_mul_overflow_p(i, ll, i);
+	rc += __builtin_mul_overflow_p(i, i, ll);
+
+	// should be KO
+	rc += __builtin_add_overflow();
+	rc += __builtin_add_overflow(i);
+	rc += __builtin_add_overflow(i, i);
+	rc += __builtin_add_overflow(i, i, &i, i);
+	rc += __builtin_add_overflow(e, i, &i);
+	rc += __builtin_add_overflow(i, e, &i);
+	rc += __builtin_add_overflow(i, i, &e);
+	rc += __builtin_add_overflow(b, i, &i);
+	rc += __builtin_add_overflow(i, b, &i);
+	rc += __builtin_add_overflow(i, i, &b);
+	rc += __builtin_add_overflow(i, i, p);
+
+	rc += __builtin_add_overflow_p();
+	rc += __builtin_add_overflow_p(i);
+	rc += __builtin_add_overflow_p(i, i);
+	rc += __builtin_add_overflow_p(i, i, i, i);
+	rc += __builtin_add_overflow_p(e, i, i);
+	rc += __builtin_add_overflow_p(i, e, i);
+	rc += __builtin_add_overflow_p(i, i, e);
+	rc += __builtin_add_overflow_p(b, i, i);
+	rc += __builtin_add_overflow_p(i, b, i);
+	rc += __builtin_add_overflow_p(i, i, b);
+	rc += __builtin_add_overflow_p(i, i, p);
+
+	rc += __builtin_sub_overflow();
+	rc += __builtin_sub_overflow(i);
+	rc += __builtin_sub_overflow(i, i);
+	rc += __builtin_sub_overflow(i, i, &i, i);
+	rc += __builtin_sub_overflow(e, i, &i);
+	rc += __builtin_sub_overflow(i, e, &i);
+	rc += __builtin_sub_overflow(i, i, &e);
+	rc += __builtin_sub_overflow(b, i, &i);
+	rc += __builtin_sub_overflow(i, b, &i);
+	rc += __builtin_sub_overflow(i, i, &b);
+	rc += __builtin_sub_overflow(i, i, p);
+
+	rc += __builtin_sub_overflow_p();
+	rc += __builtin_sub_overflow_p(i);
+	rc += __builtin_sub_overflow_p(i, i);
+	rc += __builtin_sub_overflow_p(i, i, i, i);
+	rc += __builtin_sub_overflow_p(e, i, i);
+	rc += __builtin_sub_overflow_p(i, e, i);
+	rc += __builtin_sub_overflow_p(i, i, e);
+	rc += __builtin_sub_overflow_p(b, i, i);
+	rc += __builtin_sub_overflow_p(i, b, i);
+	rc += __builtin_sub_overflow_p(i, i, b);
+	rc += __builtin_sub_overflow_p(i, i, p);
+
+	rc += __builtin_mul_overflow();
+	rc += __builtin_mul_overflow(i);
+	rc += __builtin_mul_overflow(i, i);
+	rc += __builtin_mul_overflow(i, i, &i, i);
+	rc += __builtin_mul_overflow(e, i, &i);
+	rc += __builtin_mul_overflow(i, e, &i);
+	rc += __builtin_mul_overflow(i, i, &e);
+	rc += __builtin_mul_overflow(b, i, &i);
+	rc += __builtin_mul_overflow(i, b, &i);
+	rc += __builtin_mul_overflow(i, i, &b);
+	rc += __builtin_mul_overflow(i, i, p);
+
+	rc += __builtin_mul_overflow_p();
+	rc += __builtin_mul_overflow_p(i);
+	rc += __builtin_mul_overflow_p(i, i);
+	rc += __builtin_mul_overflow_p(i, i, i, i);
+	rc += __builtin_mul_overflow_p(e, i, i);
+	rc += __builtin_mul_overflow_p(i, e, i);
+	rc += __builtin_mul_overflow_p(i, i, e);
+	rc += __builtin_mul_overflow_p(b, i, i);
+	rc += __builtin_mul_overflow_p(i, b, i);
+	rc += __builtin_mul_overflow_p(i, i, b);
+	rc += __builtin_mul_overflow_p(i, i, p);
+
+	return rc;
+}
+
+/*
+ * check-name: builtin-overflow
+ *
+ * check-error-start
+builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow
+builtin-overflow.c:62:38: error: invalid type for argument 1:
+builtin-overflow.c:62:38:         int enum e [signed] e
+builtin-overflow.c:63:41: error: invalid type for argument 2:
+builtin-overflow.c:63:41:         int enum e [signed] e
+builtin-overflow.c:64:45: error: invalid type for argument 3:
+builtin-overflow.c:64:45:         int enum e *<noident>
+builtin-overflow.c:65:38: error: invalid type for argument 1:
+builtin-overflow.c:65:38:         bool [unsigned] [usertype] b
+builtin-overflow.c:66:41: error: invalid type for argument 2:
+builtin-overflow.c:66:41:         bool [unsigned] [usertype] b
+builtin-overflow.c:67:45: error: invalid type for argument 3:
+builtin-overflow.c:67:45:         bool *<noident>
+builtin-overflow.c:68:44: error: invalid type for argument 3:
+builtin-overflow.c:68:44:         void *p
+builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p
+builtin-overflow.c:74:40: error: invalid type for argument 1:
+builtin-overflow.c:74:40:         int enum e [signed] [addressable] e
+builtin-overflow.c:75:43: error: invalid type for argument 2:
+builtin-overflow.c:75:43:         int enum e [signed] [addressable] e
+builtin-overflow.c:76:46: error: invalid type for argument 3:
+builtin-overflow.c:76:46:         int enum e [signed] [addressable] e
+builtin-overflow.c:77:40: error: invalid type for argument 1:
+builtin-overflow.c:77:40:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:78:43: error: invalid type for argument 2:
+builtin-overflow.c:78:43:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:79:46: error: invalid type for argument 3:
+builtin-overflow.c:79:46:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:80:46: error: invalid type for argument 3:
+builtin-overflow.c:80:46:         void *p
+builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow
+builtin-overflow.c:86:38: error: invalid type for argument 1:
+builtin-overflow.c:86:38:         int enum e [signed] [addressable] e
+builtin-overflow.c:87:41: error: invalid type for argument 2:
+builtin-overflow.c:87:41:         int enum e [signed] [addressable] e
+builtin-overflow.c:88:45: error: invalid type for argument 3:
+builtin-overflow.c:88:45:         int enum e *<noident>
+builtin-overflow.c:89:38: error: invalid type for argument 1:
+builtin-overflow.c:89:38:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:90:41: error: invalid type for argument 2:
+builtin-overflow.c:90:41:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:91:45: error: invalid type for argument 3:
+builtin-overflow.c:91:45:         bool *<noident>
+builtin-overflow.c:92:44: error: invalid type for argument 3:
+builtin-overflow.c:92:44:         void *p
+builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p
+builtin-overflow.c:98:40: error: invalid type for argument 1:
+builtin-overflow.c:98:40:         int enum e [signed] [addressable] e
+builtin-overflow.c:99:43: error: invalid type for argument 2:
+builtin-overflow.c:99:43:         int enum e [signed] [addressable] e
+builtin-overflow.c:100:46: error: invalid type for argument 3:
+builtin-overflow.c:100:46:         int enum e [signed] [addressable] e
+builtin-overflow.c:101:40: error: invalid type for argument 1:
+builtin-overflow.c:101:40:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:102:43: error: invalid type for argument 2:
+builtin-overflow.c:102:43:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:103:46: error: invalid type for argument 3:
+builtin-overflow.c:103:46:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:104:46: error: invalid type for argument 3:
+builtin-overflow.c:104:46:         void *p
+builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow
+builtin-overflow.c:110:38: error: invalid type for argument 1:
+builtin-overflow.c:110:38:         int enum e [signed] [addressable] e
+builtin-overflow.c:111:41: error: invalid type for argument 2:
+builtin-overflow.c:111:41:         int enum e [signed] [addressable] e
+builtin-overflow.c:112:45: error: invalid type for argument 3:
+builtin-overflow.c:112:45:         int enum e *<noident>
+builtin-overflow.c:113:38: error: invalid type for argument 1:
+builtin-overflow.c:113:38:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:114:41: error: invalid type for argument 2:
+builtin-overflow.c:114:41:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:115:45: error: invalid type for argument 3:
+builtin-overflow.c:115:45:         bool *<noident>
+builtin-overflow.c:116:44: error: invalid type for argument 3:
+builtin-overflow.c:116:44:         void *p
+builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p
+builtin-overflow.c:122:40: error: invalid type for argument 1:
+builtin-overflow.c:122:40:         int enum e [signed] [addressable] e
+builtin-overflow.c:123:43: error: invalid type for argument 2:
+builtin-overflow.c:123:43:         int enum e [signed] [addressable] e
+builtin-overflow.c:124:46: error: invalid type for argument 3:
+builtin-overflow.c:124:46:         int enum e [signed] [addressable] e
+builtin-overflow.c:125:40: error: invalid type for argument 1:
+builtin-overflow.c:125:40:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:126:43: error: invalid type for argument 2:
+builtin-overflow.c:126:43:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:127:46: error: invalid type for argument 3:
+builtin-overflow.c:127:46:         bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:128:46: error: invalid type for argument 3:
+builtin-overflow.c:128:46:         void *p
+ * check-error-end
+ */
-- 
2.17.1

--
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