aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-03-19 22:43:06 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-11-17 10:04:37 +0100
commit0f1700e896ed0111fa7e248c307c620fd8506000 (patch)
tree76d30477e65bc8bf45e530ba6c80109ab8f1adb0
parent880cd2465e6f2badda7c7e9e81d1d4cca7a35833 (diff)
downloadsparse-dev-0f1700e896ed0111fa7e248c307c620fd8506000.tar.gz
llvm: fix mutating function pointer
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--sparse-llvm.c33
-rw-r--r--validation/backend/function-ptr-xtype.c37
2 files changed, 64 insertions, 6 deletions
diff --git a/sparse-llvm.c b/sparse-llvm.c
index 0043b797..1af6322d 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -456,6 +456,27 @@ static LLVMValueRef adjust_type(struct function *fn, struct symbol *ctype, LLVMV
return val;
}
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype.
+ */
+static LLVMValueRef get_operand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+ return adjust_type(fn, ctype, target);
+}
+
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype but
+ * map all pointers to intptr_t.
+ */
+static LLVMValueRef get_ioperand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+ LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+ return value_to_ivalue(fn, ctype, target);
+}
+
static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off)
{
LLVMTypeRef type = LLVMTypeOf(base);
@@ -515,11 +536,8 @@ static void output_op_binary(struct function *fn, struct instruction *insn)
LLVMValueRef lhs, rhs, target;
char target_name[64];
- lhs = pseudo_to_value(fn, insn->type, insn->src1);
- lhs = value_to_ivalue(fn, insn->type, lhs);
-
- rhs = pseudo_to_value(fn, insn->type, insn->src2);
- rhs = value_to_ivalue(fn, insn->type, rhs);
+ lhs = get_ioperand(fn, insn->type, insn->src1);
+ rhs = get_ioperand(fn, insn->type, insn->src2);
pseudo_name(insn->target, target_name);
@@ -807,6 +825,10 @@ static void output_op_call(struct function *fn, struct instruction *insn)
args = calloc(n_arg, sizeof(LLVMValueRef));
PREPARE_PTR_LIST(insn->fntypes, ctype);
+ if (insn->func->type == PSEUDO_REG || insn->func->type == PSEUDO_PHI)
+ func = get_operand(fn, ctype, insn->func);
+ else
+ func = pseudo_to_value(fn, ctype, insn->func);
i = 0;
FOR_EACH_PTR(insn->arguments, arg) {
NEXT_PTR_LIST(ctype);
@@ -814,7 +836,6 @@ static void output_op_call(struct function *fn, struct instruction *insn)
} END_FOR_EACH_PTR(arg);
FINISH_PTR_LIST(ctype);
- func = pseudo_to_value(fn, NULL, insn->func);
pseudo_name(insn->target, name);
target = LLVMBuildCall(fn->builder, func, args, n_arg, name);
diff --git a/validation/backend/function-ptr-xtype.c b/validation/backend/function-ptr-xtype.c
new file mode 100644
index 00000000..9cdfab05
--- /dev/null
+++ b/validation/backend/function-ptr-xtype.c
@@ -0,0 +1,37 @@
+typedef int (*binop_t)(int, int);
+typedef int (*unop_t)(int);
+typedef int (*idef_t)(void);
+typedef long (*ldef_t)(void);
+typedef void (*use_t)(int);
+
+// We want to 'fn' have several different types.
+// The goal is for the ->priv member to be used
+// with a type different from what it was first stored.
+
+int foo(void *fn, int arg1, int arg2);
+int foo(void *fn, int arg1, int arg2)
+{
+ int res = 0;
+
+ res += ((binop_t)fn)(arg1, arg2);
+ res += ((unop_t)fn)(arg1);
+ res += ((ldef_t)fn)();
+ res += ((idef_t)fn)();
+ ((use_t)fn)(res);
+ return res;
+}
+
+int bar(int (*fn)(int), int arg1, int arg2);
+int bar(int (*fn)(int), int arg1, int arg2)
+{
+ int res = 0;
+
+ res += ((binop_t)fn)(arg1, arg2);
+ res += fn(arg1);
+ return res;
+}
+
+/*
+ * check-name: mutate function pointer's type
+ * check-command: ./sparsec -c $file -o tmp.o
+ */