Blame SOURCES/0002-Use-a-safer-calling-convention-for-native-functions.patch

ee1b47
From c514988fa3ff57e7622678963c1141b59b4d88d7 Mon Sep 17 00:00:00 2001
ee1b47
From: David Lutterkort <lutter@watzmann.net>
ee1b47
Date: Mon, 4 Jun 2018 23:19:28 -0700
ee1b47
Subject: [PATCH] Use a safer calling convention for native functions
ee1b47
ee1b47
The native functions in the lens interpreter used a calling convention that
ee1b47
required unsafe casting of function pointers. We now use a calling
ee1b47
convention that does not cause any function pointer casts.
ee1b47
ee1b47
(cherry picked from commit 31c3532e5e8d4707dfb7de12278221001dafdd5a)
ee1b47
---
ee1b47
 src/builtin.c | 161 +++++++++++++++++++++++++++++++++-----------------
ee1b47
 src/syntax.c  |  34 ++---------
ee1b47
 src/syntax.h  |  11 +++-
ee1b47
 3 files changed, 119 insertions(+), 87 deletions(-)
ee1b47
ee1b47
diff --git a/src/builtin.c b/src/builtin.c
ee1b47
index 732ee10c..7cf4fa0a 100644
ee1b47
--- a/src/builtin.c
ee1b47
+++ b/src/builtin.c
ee1b47
@@ -42,8 +42,10 @@
ee1b47
  */
ee1b47
 
ee1b47
 /* V_REGEXP -> V_STRING -> V_LENS */
ee1b47
-static struct value *lns_del(struct info *info,
ee1b47
-                             struct value *rxp, struct value *dflt) {
ee1b47
+static struct value *lns_del(struct info *info, struct value **argv) {
ee1b47
+    struct value *rxp = argv[0];
ee1b47
+    struct value *dflt = argv[1];
ee1b47
+
ee1b47
     assert(rxp->tag == V_REGEXP);
ee1b47
     assert(dflt->tag == V_STRING);
ee1b47
     return lns_make_prim(L_DEL, ref(info),
ee1b47
@@ -51,44 +53,59 @@ static struct value *lns_del(struct info *info,
ee1b47
 }
ee1b47
 
ee1b47
 /* V_REGEXP -> V_LENS */
ee1b47
-static struct value *lns_store(struct info *info, struct value *rxp) {
ee1b47
+static struct value *lns_store(struct info *info, struct value **argv) {
ee1b47
+    struct value *rxp = argv[0];
ee1b47
+
ee1b47
     assert(rxp->tag == V_REGEXP);
ee1b47
     return lns_make_prim(L_STORE, ref(info), ref(rxp->regexp), NULL);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_LENS */
ee1b47
-static struct value *lns_value(struct info *info, struct value *str) {
ee1b47
+static struct value *lns_value(struct info *info, struct value **argv) {
ee1b47
+    struct value *str = argv[0];
ee1b47
+
ee1b47
     assert(str->tag == V_STRING);
ee1b47
     return lns_make_prim(L_VALUE, ref(info), NULL, ref(str->string));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_REGEXP -> V_LENS */
ee1b47
-static struct value *lns_key(struct info *info, struct value *rxp) {
ee1b47
+static struct value *lns_key(struct info *info, struct value **argv) {
ee1b47
+    struct value *rxp = argv[0];
ee1b47
+
ee1b47
     assert(rxp->tag == V_REGEXP);
ee1b47
     return lns_make_prim(L_KEY, ref(info), ref(rxp->regexp), NULL);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_LENS */
ee1b47
-static struct value *lns_label(struct info *info, struct value *str) {
ee1b47
+static struct value *lns_label(struct info *info, struct value **argv) {
ee1b47
+    struct value *str = argv[0];
ee1b47
+
ee1b47
     assert(str->tag == V_STRING);
ee1b47
     return lns_make_prim(L_LABEL, ref(info), NULL, ref(str->string));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_LENS */
ee1b47
-static struct value *lns_seq(struct info *info, struct value *str) {
ee1b47
+static struct value *lns_seq(struct info *info, struct value **argv) {
ee1b47
+    struct value *str = argv[0];
ee1b47
+
ee1b47
     assert(str->tag == V_STRING);
ee1b47
     return lns_make_prim(L_SEQ, ref(info), NULL, ref(str->string));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_LENS */
ee1b47
-static struct value *lns_counter(struct info *info, struct value *str) {
ee1b47
+static struct value *lns_counter(struct info *info, struct value **argv) {
ee1b47
+    struct value *str = argv[0];
ee1b47
+
ee1b47
     assert(str->tag == V_STRING);
ee1b47
     return lns_make_prim(L_COUNTER, ref(info), NULL, ref(str->string));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_LENS -> V_LENS -> V_LENS */
ee1b47
-static struct value *lns_square(struct info *info, struct value *l1,
ee1b47
-                                struct value *l2, struct value *l3) {
ee1b47
+static struct value *lns_square(struct info *info, struct value **argv) {
ee1b47
+    struct value *l1 = argv[0];
ee1b47
+    struct value *l2 = argv[1];
ee1b47
+    struct value *l3 = argv[2];
ee1b47
+
ee1b47
     assert(l1->tag == V_LENS);
ee1b47
     assert(l2->tag == V_LENS);
ee1b47
     assert(l3->tag == V_LENS);
ee1b47
@@ -179,8 +196,10 @@ static struct value *pathx_parse_glue(struct info *info, struct value *tree,
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_STRING -> V_TREE */
ee1b47
-static struct value *lens_get(struct info *info, struct value *l,
ee1b47
-                              struct value *str) {
ee1b47
+static struct value *lens_get(struct info *info, struct value **argv) {
ee1b47
+    struct value *l = argv[0];
ee1b47
+    struct value *str = argv[1];
ee1b47
+
ee1b47
     assert(l->tag == V_LENS);
ee1b47
     assert(str->tag == V_STRING);
ee1b47
     struct lns_error *err;
ee1b47
@@ -210,8 +229,11 @@ static struct value *lens_get(struct info *info, struct value *l,
ee1b47
 
ee1b47
 
ee1b47
 /* V_LENS -> V_TREE -> V_STRING -> V_STRING */
ee1b47
-static struct value *lens_put(struct info *info, struct value *l,
ee1b47
-                              struct value *tree, struct value *str) {
ee1b47
+static struct value *lens_put(struct info *info, struct value **argv) {
ee1b47
+    struct value *l    = argv[0];
ee1b47
+    struct value *tree = argv[1];
ee1b47
+    struct value *str  = argv[2];
ee1b47
+
ee1b47
     assert(l->tag == V_LENS);
ee1b47
     assert(tree->tag == V_TREE);
ee1b47
     assert(str->tag == V_STRING);
ee1b47
@@ -237,11 +259,14 @@ static struct value *lens_put(struct info *info, struct value *l,
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
ee1b47
-static struct value *tree_set_glue(struct info *info, struct value *path,
ee1b47
-                                   struct value *val, struct value *tree) {
ee1b47
+static struct value *tree_set_glue(struct info *info, struct value **argv) {
ee1b47
     // FIXME: This only works if TREE is not referenced more than once;
ee1b47
     // otherwise we'll have some pretty weird semantics, and would really
ee1b47
     // need to copy TREE first
ee1b47
+    struct value *path = argv[0];
ee1b47
+    struct value *val  = argv[1];
ee1b47
+    struct value *tree = argv[2];
ee1b47
+
ee1b47
     assert(path->tag == V_STRING);
ee1b47
     assert(val->tag == V_STRING);
ee1b47
     assert(tree->tag == V_TREE);
ee1b47
@@ -277,11 +302,13 @@ static struct value *tree_set_glue(struct info *info, struct value *path,
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_TREE -> V_TREE */
ee1b47
-static struct value *tree_clear_glue(struct info *info, struct value *path,
ee1b47
-                                     struct value *tree) {
ee1b47
+static struct value *tree_clear_glue(struct info *info, struct value **argv) {
ee1b47
     // FIXME: This only works if TREE is not referenced more than once;
ee1b47
     // otherwise we'll have some pretty weird semantics, and would really
ee1b47
     // need to copy TREE first
ee1b47
+    struct value *path = argv[0];
ee1b47
+    struct value *tree = argv[1];
ee1b47
+
ee1b47
     assert(path->tag == V_STRING);
ee1b47
     assert(tree->tag == V_TREE);
ee1b47
 
ee1b47
@@ -349,25 +376,32 @@ static struct value *tree_insert_glue(struct info *info, struct value *label,
ee1b47
 
ee1b47
 /* Insert after */
ee1b47
 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
ee1b47
-static struct value *tree_insa_glue(struct info *info, struct value *label,
ee1b47
-                                    struct value *path, struct value *tree) {
ee1b47
+static struct value *tree_insa_glue(struct info *info, struct value **argv) {
ee1b47
+    struct value *label = argv[0];
ee1b47
+    struct value *path  = argv[1];
ee1b47
+    struct value *tree  = argv[2];
ee1b47
+
ee1b47
     return tree_insert_glue(info, label, path, tree, 0);
ee1b47
 }
ee1b47
 
ee1b47
 /* Insert before */
ee1b47
 /* V_STRING -> V_STRING -> V_TREE -> V_TREE */
ee1b47
-static struct value *tree_insb_glue(struct info *info, struct value *label,
ee1b47
-                                    struct value *path, struct value *tree) {
ee1b47
+static struct value *tree_insb_glue(struct info *info, struct value **argv) {
ee1b47
+    struct value *label = argv[0];
ee1b47
+    struct value *path  = argv[1];
ee1b47
+    struct value *tree  = argv[2];
ee1b47
+
ee1b47
     return tree_insert_glue(info, label, path, tree, 1);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_TREE -> V_TREE */
ee1b47
-static struct value *tree_rm_glue(struct info *info,
ee1b47
-                                  struct value *path,
ee1b47
-                                  struct value *tree) {
ee1b47
+static struct value *tree_rm_glue(struct info *info, struct value **argv) {
ee1b47
     // FIXME: This only works if TREE is not referenced more than once;
ee1b47
     // otherwise we'll have some pretty weird semantics, and would really
ee1b47
     // need to copy TREE first
ee1b47
+    struct value *path  = argv[0];
ee1b47
+    struct value *tree  = argv[1];
ee1b47
+
ee1b47
     assert(path->tag == V_STRING);
ee1b47
     assert(tree->tag == V_TREE);
ee1b47
 
ee1b47
@@ -390,7 +424,9 @@ static struct value *tree_rm_glue(struct info *info,
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_STRING */
ee1b47
-static struct value *gensym(struct info *info, struct value *prefix) {
ee1b47
+static struct value *gensym(struct info *info, struct value **argv) {
ee1b47
+    struct value *prefix = argv[0];
ee1b47
+
ee1b47
     assert(prefix->tag == V_STRING);
ee1b47
     static unsigned int count = 0;
ee1b47
     struct value *v;
ee1b47
@@ -406,7 +442,9 @@ static struct value *gensym(struct info *info, struct value *prefix) {
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_FILTER */
ee1b47
-static struct value *xform_incl(struct info *info, struct value *s) {
ee1b47
+static struct value *xform_incl(struct info *info, struct value **argv) {
ee1b47
+    struct value *s = argv[0];
ee1b47
+
ee1b47
     assert(s->tag == V_STRING);
ee1b47
     struct value *v = make_value(V_FILTER, ref(info));
ee1b47
     v->filter = make_filter(ref(s->string), 1);
ee1b47
@@ -414,7 +452,9 @@ static struct value *xform_incl(struct info *info, struct value *s) {
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_FILTER */
ee1b47
-static struct value *xform_excl(struct info *info, struct value *s) {
ee1b47
+static struct value *xform_excl(struct info *info, struct value **argv) {
ee1b47
+    struct value *s = argv[0];
ee1b47
+
ee1b47
     assert(s->tag == V_STRING);
ee1b47
     struct value *v = make_value(V_FILTER, ref(info));
ee1b47
     v->filter = make_filter(ref(s->string), 0);
ee1b47
@@ -422,8 +462,10 @@ static struct value *xform_excl(struct info *info, struct value *s) {
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_FILTER -> V_TRANSFORM */
ee1b47
-static struct value *xform_transform(struct info *info, struct value *l,
ee1b47
-                                     struct value *f) {
ee1b47
+static struct value *xform_transform(struct info *info, struct value **argv) {
ee1b47
+    struct value *l = argv[0];
ee1b47
+    struct value *f = argv[1];
ee1b47
+
ee1b47
     assert(l->tag == V_LENS);
ee1b47
     assert(f->tag == V_FILTER);
ee1b47
     if (l->lens->value || l->lens->key) {
ee1b47
@@ -436,14 +478,16 @@ static struct value *xform_transform(struct info *info, struct value *l,
ee1b47
     return v;
ee1b47
 }
ee1b47
 
ee1b47
-static struct value *sys_getenv(struct info *info, struct value *n) {
ee1b47
-    assert(n->tag == V_STRING);
ee1b47
+static struct value *sys_getenv(struct info *info, struct value **argv) {
ee1b47
+    assert(argv[0]->tag == V_STRING);
ee1b47
     struct value *v = make_value(V_STRING, ref(info));
ee1b47
-    v->string = dup_string(getenv(n->string->str));
ee1b47
+    v->string = dup_string(getenv(argv[0]->string->str));
ee1b47
     return v;
ee1b47
 }
ee1b47
 
ee1b47
-static struct value *sys_read_file(struct info *info, struct value *n) {
ee1b47
+static struct value *sys_read_file(struct info *info, struct value **argv) {
ee1b47
+    struct value *n = argv[0];
ee1b47
+
ee1b47
     assert(n->tag == V_STRING);
ee1b47
     char *str = NULL;
ee1b47
 
ee1b47
@@ -464,7 +508,10 @@ static struct value *sys_read_file(struct info *info, struct value *n) {
ee1b47
 
ee1b47
 /* V_LENS -> V_LENS */
ee1b47
 static struct value *lns_check_rec_glue(struct info *info,
ee1b47
-                                        struct value *l, struct value *r) {
ee1b47
+                                        struct value **argv) {
ee1b47
+    struct value *l = argv[0];
ee1b47
+    struct value *r = argv[1];
ee1b47
+
ee1b47
     assert(l->tag == V_LENS);
ee1b47
     assert(r->tag == V_LENS);
ee1b47
     int check = typecheck_p(info);
ee1b47
@@ -477,28 +524,28 @@ static struct value *lns_check_rec_glue(struct info *info,
ee1b47
  */
ee1b47
 
ee1b47
 /* V_STRING -> V_UNIT */
ee1b47
-static struct value *pr_string(struct info *info, struct value *s) {
ee1b47
-    printf("%s", s->string->str);
ee1b47
+static struct value *pr_string(struct info *info, struct value **argv) {
ee1b47
+    printf("%s", argv[0]->string->str);
ee1b47
     return make_unit(ref(info));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_REGEXP -> V_UNIT */
ee1b47
-static struct value *pr_regexp(struct info *info, struct value *r) {
ee1b47
-    print_regexp(stdout, r->regexp);
ee1b47
+static struct value *pr_regexp(struct info *info, struct value **argv) {
ee1b47
+    print_regexp(stdout, argv[0]->regexp);
ee1b47
     return make_unit(ref(info));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_STRING -> V_UNIT */
ee1b47
-static struct value *pr_endline(struct info *info, struct value *s) {
ee1b47
-    printf("%s\n", s->string->str);
ee1b47
+static struct value *pr_endline(struct info *info, struct value **argv) {
ee1b47
+    printf("%s\n", argv[0]->string->str);
ee1b47
     return make_unit(ref(info));
ee1b47
 }
ee1b47
 
ee1b47
 /* V_TREE -> V_TREE */
ee1b47
 static struct value *pr_tree(ATTRIBUTE_UNUSED struct info *info,
ee1b47
-                             struct value *t) {
ee1b47
-    print_tree_braces(stdout, 0, t->origin);
ee1b47
-    return ref(t);
ee1b47
+                             struct value **argv) {
ee1b47
+    print_tree_braces(stdout, 0, argv[0]->origin);
ee1b47
+    return ref(argv[0]);
ee1b47
 }
ee1b47
 
ee1b47
 /*
ee1b47
@@ -515,27 +562,29 @@ static struct value *lns_value_of_type(struct info *info, struct regexp *rx) {
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_REGEXP */
ee1b47
-static struct value *lns_ctype(struct info *info, struct value *l) {
ee1b47
-    return lns_value_of_type(info, l->lens->ctype);
ee1b47
+static struct value *lns_ctype(struct info *info, struct value **argv) {
ee1b47
+    return lns_value_of_type(info, argv[0]->lens->ctype);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_REGEXP */
ee1b47
-static struct value *lns_atype(struct info *info, struct value *l) {
ee1b47
-    return lns_value_of_type(info, l->lens->atype);
ee1b47
+static struct value *lns_atype(struct info *info, struct value **argv) {
ee1b47
+    return lns_value_of_type(info, argv[0]->lens->atype);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_REGEXP */
ee1b47
-static struct value *lns_vtype(struct info *info, struct value *l) {
ee1b47
-    return lns_value_of_type(info, l->lens->vtype);
ee1b47
+static struct value *lns_vtype(struct info *info, struct value **argv) {
ee1b47
+    return lns_value_of_type(info, argv[0]->lens->vtype);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_REGEXP */
ee1b47
-static struct value *lns_ktype(struct info *info, struct value *l) {
ee1b47
-    return lns_value_of_type(info, l->lens->ktype);
ee1b47
+static struct value *lns_ktype(struct info *info, struct value **argv) {
ee1b47
+    return lns_value_of_type(info, argv[0]->lens->ktype);
ee1b47
 }
ee1b47
 
ee1b47
 /* V_LENS -> V_STRING */
ee1b47
-static struct value *lns_fmt_atype(struct info *info, struct value *l) {
ee1b47
+static struct value *lns_fmt_atype(struct info *info, struct value **argv) {
ee1b47
+    struct value *l = argv[0];
ee1b47
+
ee1b47
     struct value *result = NULL;
ee1b47
     char *s = NULL;
ee1b47
     int r;
ee1b47
@@ -549,8 +598,10 @@ static struct value *lns_fmt_atype(struct info *info, struct value *l) {
ee1b47
 }
ee1b47
 
ee1b47
 /* V_REGEXP -> V_STRING -> V_STRING */
ee1b47
-static struct value *rx_match(struct info *info,
ee1b47
-                              struct value *rx, struct value *s) {
ee1b47
+static struct value *rx_match(struct info *info, struct value **argv) {
ee1b47
+    struct value *rx = argv[0];
ee1b47
+    struct value *s  = argv[1];
ee1b47
+
ee1b47
     struct value *result = NULL;
ee1b47
     const char *str = s->string->str;
ee1b47
     struct re_registers regs;
ee1b47
diff --git a/src/syntax.c b/src/syntax.c
ee1b47
index 612544c7..d26babcc 100644
ee1b47
--- a/src/syntax.c
ee1b47
+++ b/src/syntax.c
ee1b47
@@ -1023,42 +1023,16 @@ typedef struct value *(*impl5)(struct info *, struct value *, struct value *,
ee1b47
 
ee1b47
 static struct value *native_call(struct info *info,
ee1b47
                                  struct native *func, struct ctx *ctx) {
ee1b47
-    struct value *argv[func->argc];
ee1b47
+    struct value *argv[func->argc + 1];
ee1b47
     struct binding *b = ctx->local;
ee1b47
-    struct value *result;
ee1b47
 
ee1b47
     for (int i = func->argc - 1; i >= 0; i--) {
ee1b47
         argv[i] = b->value;
ee1b47
         b = b->next;
ee1b47
     }
ee1b47
+    argv[func->argc] = NULL;
ee1b47
 
ee1b47
-    switch(func->argc) {
ee1b47
-    case 0:
ee1b47
-        result = ((impl0) *func->impl)(info);
ee1b47
-        break;
ee1b47
-    case 1:
ee1b47
-        result = ((impl1) *func->impl)(info, argv[0]);
ee1b47
-        break;
ee1b47
-    case 2:
ee1b47
-        result = ((impl2) *func->impl)(info, argv[0], argv[1]);
ee1b47
-        break;
ee1b47
-    case 3:
ee1b47
-        result = ((impl3) *func->impl)(info, argv[0], argv[1], argv[2]);
ee1b47
-        break;
ee1b47
-    case 4:
ee1b47
-        result = ((impl4) *func->impl)(info, argv[0], argv[1], argv[2], argv[3]);
ee1b47
-        break;
ee1b47
-    case 5:
ee1b47
-        result = ((impl5) *func->impl)(info, argv[0], argv[1], argv[2], argv[3],
ee1b47
-                                       argv[4]);
ee1b47
-        break;
ee1b47
-    default:
ee1b47
-        assert(0);
ee1b47
-        abort();
ee1b47
-        break;
ee1b47
-    }
ee1b47
-
ee1b47
-    return result;
ee1b47
+    return func->impl(info, argv);
ee1b47
 }
ee1b47
 
ee1b47
 static void type_error1(struct info *info, const char *msg, struct type *type) {
ee1b47
@@ -1857,7 +1831,7 @@ make_native_info(struct error *error, const char *fname, int line) {
ee1b47
 int define_native_intl(const char *file, int line,
ee1b47
                        struct error *error,
ee1b47
                        struct module *module, const char *name,
ee1b47
-                       int argc, void *impl, ...) {
ee1b47
+                       int argc, func_impl impl, ...) {
ee1b47
     assert(argc > 0);  /* We have no unit type */
ee1b47
     assert(argc <= 5);
ee1b47
     va_list ap;
ee1b47
diff --git a/src/syntax.h b/src/syntax.h
ee1b47
index 12c3bae4..30aefe58 100644
ee1b47
--- a/src/syntax.h
ee1b47
+++ b/src/syntax.h
ee1b47
@@ -112,10 +112,17 @@ struct param {
ee1b47
     struct type   *type;
ee1b47
 };
ee1b47
 
ee1b47
+/* The protoype for the implementation of a native/builtin function in the
ee1b47
+ * interpreter.
ee1b47
+ *
ee1b47
+ * The arguments are passed as a NULL-terminated array of values.
ee1b47
+ */
ee1b47
+typedef struct value *(*func_impl)(struct info *, struct value *argv[]);
ee1b47
+
ee1b47
 struct native {
ee1b47
     unsigned int argc;
ee1b47
     struct type *type;
ee1b47
-    struct value *(*impl)(void);
ee1b47
+    func_impl    impl;
ee1b47
 };
ee1b47
 
ee1b47
 /* An exception in the interpreter. Some exceptions are reported directly
ee1b47
@@ -270,7 +277,7 @@ ATTRIBUTE_RETURN_CHECK
ee1b47
 int define_native_intl(const char *fname, int line,
ee1b47
                        struct error *error,
ee1b47
                        struct module *module, const char *name,
ee1b47
-                       int argc, void *impl, ...);
ee1b47
+                       int argc, func_impl impl, ...);
ee1b47
 
ee1b47
 struct module *builtin_init(struct error *);
ee1b47
 
ee1b47
-- 
ee1b47
2.17.2
ee1b47