We've run into a few errors due to very long variable expansion in bsd.port.mk
that overflows execve(2)

I would consider adding a modifier to give the length of a variable, so
that significant tests can be done, along the lines of

.if ${VARIABLE:len} > 200000
ERRORS += "Fatal: variable may overflow execve"
.endif


Now, this is a pure extension.   We already have some highly similar modifier
in the presence of the very old SystemV :sh  to exec variables,
and there's no ambiguity in there.


Would that feature be amenable for inclusion ?

(I'm aware I need to test asprintf's result, it's just a POC at the moment)

Index: varmodifiers.c
===================================================================
RCS file: /cvs/src/usr.bin/make/varmodifiers.c,v
retrieving revision 1.48
diff -u -p -r1.48 varmodifiers.c
--- varmodifiers.c      30 Aug 2020 12:16:04 -0000      1.48
+++ varmodifiers.c      22 Aug 2023 16:19:31 -0000
@@ -147,6 +147,8 @@ static void *check_empty(const char **, 
 static void *check_quote(const char **, SymTable *, bool, int);
 static char *do_upper(const char *, const struct Name *, void *);
 static char *do_lower(const char *, const struct Name *, void *);
+static void *check_length(const char **, SymTable *, bool, int);
+static char *do_length(const char *, const struct Name *, void *);
 static void *check_shcmd(const char **, SymTable *, bool, int);
 static char *do_shcmd(const char *, const struct Name *, void *);
 static char *do_sort(const char *, const struct Name *, void *);
@@ -204,7 +206,8 @@ static struct modifier {
        label_mod = {true, check_empty, do_label, NULL, NULL},
        path_mod = {true, check_empty, do_path, NULL, NULL},
        assign_mod = {true, assign_get_value, do_assign, NULL, free_patternarg},
-       exec_mod = {true, get_cmd, do_exec, NULL, free_patternarg}
+       exec_mod = {true, get_cmd, do_exec, NULL, free_patternarg},
+       length_mod = {false, check_length, do_length, NULL, NULL}
 ;
 
 void
@@ -219,6 +222,7 @@ VarModifiers_Init()
        choose_mod['H'] = &head_mod;
        choose_mod['E'] = &suffix_mod;
        choose_mod['R'] = &root_mod;
+       choose_mod['l'] = &length_mod;
        if (FEATURES(FEATURE_UPPERLOWER)) {
                choose_mod['U'] = &upper_mod;
                choose_mod['L'] = &lower_mod;
@@ -1202,6 +1206,26 @@ do_lower(const char *s, const struct Nam
        for (i = 0; i < len; i++)
                t[i] = TOLOWER(s[i]);
        t[len] = '\0';
+       return t;
+}
+
+static void *
+check_length(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
+{
+       if ((*p)[1] == 'e' && (*p)[2] == 'n' && 
+           ((*p)[3] == endc || (*p)[3] == ':')) {
+               (*p)+=3;
+               return dummy_arg;
+       } else
+               return NULL;
+}
+
+static char *
+do_length(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
+{
+       char    *t;
+
+       asprintf(&t, "%zu", strlen(s));
        return t;
 }
 

Reply via email to