aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-02-25 23:11:44 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-02-25 23:11:44 +0100
commiteaceeafad39ade20c28b6634d30379763511c6e6 (patch)
tree5bc1ae797162583d6ff6191c402d369cdfe7447a
parent3d617353dda682db8b3eb6ea8c1fdfa89edfe5e2 (diff)
parenteb55532d516c93a59946489114422c587a7cd0cd (diff)
downloadsparse-eaceeafad39ade20c28b6634d30379763511c6e6.tar.gz
Merge branch 'objsize'
* expand __builtin_object_size()
-rw-r--r--builtin.c73
-rw-r--r--ptrlist.h4
-rw-r--r--validation/builtin-objsize-dyn.c22
-rw-r--r--validation/builtin-objsize0.c25
-rw-r--r--validation/builtin-objsize1.c21
5 files changed, 144 insertions, 1 deletions
diff --git a/builtin.c b/builtin.c
index 5c7321ca..c7e7da3b 100644
--- a/builtin.c
+++ b/builtin.c
@@ -454,6 +454,77 @@ static struct symbol_op atomic_op = {
};
+///
+// expand __builtin_object_size()
+//
+// :note: type 1 and type 3 are not supported because the
+// needed information isn't available after evaluation.
+static int expand_object_size(struct expression *expr, int cost)
+{
+ struct expression *arg = first_expression(expr->args);
+ int type = get_expression_value_silent(ptr_list_nth(expr->args, 1));
+ unsigned long val = -1, off = 0;
+
+ while (arg) {
+ switch (arg->type) {
+ case EXPR_IMPLIED_CAST:
+ case EXPR_CAST:
+ // ignore those
+ arg = arg->cast_expression;
+ continue;
+ case EXPR_BINOP:
+ // a constant add is (maybe) an offset
+ if (!arg->right || arg->op != '+' || arg->right->type != EXPR_VALUE)
+ break;
+ off += arg->right->value;
+ arg = arg->left;
+ continue;
+ case EXPR_PREOP:
+ // a deref is just intermediate variable
+ // and so the offset needs to be zeroed.
+ if (arg->op == '*') {
+ arg = arg->unop;
+ off = 0;
+ switch (arg->type) {
+ case EXPR_SYMBOL:
+ arg = arg->symbol->initializer;
+ continue;
+ default:
+ break;
+ }
+ }
+ break;
+ case EXPR_SYMBOL:
+ // the symbol we're looking after
+ val = bits_to_bytes(arg->symbol->bit_size);
+ break;
+ case EXPR_CALL:
+ // use alloc_size() attribute but only after linearization.
+ return UNSAFE;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (val == -1)
+ val = (type & 2) ? 0 : val;
+ else if (type & 1)
+ return UNSAFE;
+ else
+ val -= off;
+
+ expr->flags |= CEF_SET_ICE;
+ expr->type = EXPR_VALUE;
+ expr->value = val;
+ expr->taint = 0;
+ return 0;
+}
+
+static struct symbol_op object_size_op = {
+ .expand = expand_object_size,
+};
+
/*
* Builtin functions
*/
@@ -598,7 +669,7 @@ static const struct builtin_fn builtins_common[] = {
{ "__builtin_nan", &double_ctype, 0, { &const_string_ctype }},
{ "__builtin_nanf", &float_ctype, 0, { &const_string_ctype }},
{ "__builtin_nanl", &ldouble_ctype, 0, { &const_string_ctype }},
- { "__builtin_object_size", size_t_ctype, 0, { &const_ptr_ctype, &int_ctype }},
+ { "__builtin_object_size", size_t_ctype, 0, { &const_ptr_ctype, &int_ctype }, .op = &object_size_op},
{ "__builtin_parity", &int_ctype, 0, { &uint_ctype }, .op = &parity_op },
{ "__builtin_parityl", &int_ctype, 0, { &ulong_ctype }, .op = &parity_op },
{ "__builtin_parityll", &int_ctype, 0, { &ullong_ctype }, .op = &parity_op },
diff --git a/ptrlist.h b/ptrlist.h
index 4bf8c709..c5fa4cdd 100644
--- a/ptrlist.h
+++ b/ptrlist.h
@@ -73,6 +73,10 @@ extern void __free_ptr_list(struct ptr_list **);
__free_ptr_list((struct ptr_list **)(list)); \
} while (0)
+#define ptr_list_nth(lst, nth) ({ \
+ struct ptr_list* head = (struct ptr_list*)(lst); \
+ (__typeof__((lst)->list[0])) ptr_list_nth_entry(head, nth);\
+ })
////////////////////////////////////////////////////////////////////////
// API
diff --git a/validation/builtin-objsize-dyn.c b/validation/builtin-objsize-dyn.c
new file mode 100644
index 00000000..276c9204
--- /dev/null
+++ b/validation/builtin-objsize-dyn.c
@@ -0,0 +1,22 @@
+void *alloc(unsigned long)__attribute__((alloc_size(1)));
+
+_Bool sta(void)
+{
+ void *ptr = alloc(4);
+ return __builtin_object_size(ptr, 0) == 4;
+}
+
+_Bool dyn(unsigned long n)
+{
+ void *ptr = alloc(n);
+ return __builtin_object_size(ptr, 0) == n;
+}
+
+/*
+ * check-name: builtin-objsize-dyn
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/builtin-objsize0.c b/validation/builtin-objsize0.c
new file mode 100644
index 00000000..9aab2ddd
--- /dev/null
+++ b/validation/builtin-objsize0.c
@@ -0,0 +1,25 @@
+#define bos(O, T) __builtin_object_size(O, T)
+
+struct s {
+ char arr[8];
+ __INT32_TYPE__ i;
+ __INT32_TYPE__ padding;
+};
+
+static struct s s;
+static char *p = &s.arr[1];
+static int *q = &s.i;
+
+int obj_int0(void) { return bos(&s.i, 0) == 8; }
+int obj_arr0(void) { return bos(&s.arr[1], 0) == 15; }
+
+int ptr_int(struct s *p) { return bos(&p->i, 0) == -1; }
+int ptr_arr(struct s *p) { return bos(&p->arr[1], 0) == -1; }
+
+/*
+ * check-name: builtin-objsize0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/builtin-objsize1.c b/validation/builtin-objsize1.c
new file mode 100644
index 00000000..1f285fc5
--- /dev/null
+++ b/validation/builtin-objsize1.c
@@ -0,0 +1,21 @@
+#define bos(O, T) __builtin_object_size(O, T)
+
+struct s {
+ char arr[8];
+ __INT32_TYPE__ i;
+ __INT32_TYPE__ padding;
+};
+
+static struct s s;
+
+int obj_int1(void) { return bos(&s.i, 1) == 4; }
+int obj_arr1(void) { return bos(&s.arr[1], 1) == 7; }
+
+/*
+ * check-name: builtin-objsize1
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */