Просмотр исходного кода

ncd: NCDVal: don't provide a guarantee that strings are null terminated. Rename NCDVal_StringValue() to NCDVal_StringData() to
reflect the change in semantics. Provide NCDVal_StringNullTerminate() for when a null-terminated string is needed. Fix
everything to work with these changes.

ambrop7 13 лет назад
Родитель
Сommit
c28c0d0819
48 измененных файлов с 696 добавлено и 348 удалено
  1. 11 8
      examples/ncdval_test.c
  2. 3 8
      ncd/NCDModule.c
  3. 46 6
      ncd/NCDVal.c
  4. 40 10
      ncd/NCDVal.h
  5. 1 1
      ncd/NCDValGenerator.c
  6. 3 3
      ncd/address_utils.h
  7. 12 12
      ncd/modules/alias.c
  8. 1 1
      ncd/modules/concat.c
  9. 1 1
      ncd/modules/concatv.c
  10. 6 4
      ncd/modules/daemon.c
  11. 14 10
      ncd/modules/depend.c
  12. 40 20
      ncd/modules/dynamic_depend.c
  13. 2 2
      ncd/modules/explode.c
  14. 30 5
      ncd/modules/file.c
  15. 26 13
      ncd/modules/file_open.c
  16. 1 1
      ncd/modules/from_string.c
  17. 2 2
      ncd/modules/implode.c
  18. 9 7
      ncd/modules/multidepend.c
  19. 30 15
      ncd/modules/net_backend_badvpn.c
  20. 21 11
      ncd/modules/net_backend_rfkill.c
  21. 4 2
      ncd/modules/net_backend_waitdevice.c
  22. 13 5
      ncd/modules/net_backend_waitlink.c
  23. 15 8
      ncd/modules/net_backend_wpa_supplicant.c
  24. 10 4
      ncd/modules/net_dns.c
  25. 29 15
      ncd/modules/net_iptables.c
  26. 22 13
      ncd/modules/net_ipv4_addr.c
  27. 4 4
      ncd/modules/net_ipv4_addr_in_network.c
  28. 12 5
      ncd/modules/net_ipv4_arp_probe.c
  29. 43 15
      ncd/modules/net_ipv4_dhcp.c
  30. 33 19
      ncd/modules/net_ipv4_route.c
  31. 22 13
      ncd/modules/net_ipv6_addr.c
  32. 4 4
      ncd/modules/net_ipv6_addr_in_network.c
  33. 33 19
      ncd/modules/net_ipv6_route.c
  34. 10 2
      ncd/modules/net_ipv6_wait_dynamic_addr.c
  35. 15 5
      ncd/modules/net_up.c
  36. 4 4
      ncd/modules/netmask.c
  37. 3 3
      ncd/modules/parse.c
  38. 1 1
      ncd/modules/print.c
  39. 27 22
      ncd/modules/process_manager.c
  40. 22 7
      ncd/modules/regex_match.c
  41. 6 4
      ncd/modules/run.c
  42. 10 9
      ncd/modules/runonce.c
  43. 1 1
      ncd/modules/socket.c
  44. 10 1
      ncd/modules/sys_evdev.c
  45. 22 12
      ncd/modules/sys_watch_directory.c
  46. 7 5
      ncd/modules/sys_watch_input.c
  47. 3 3
      ncd/modules/value.c
  48. 12 3
      ncd/value_utils.h

+ 11 - 8
examples/ncdval_test.c

@@ -48,8 +48,13 @@ static void print_value (NCDValRef val, unsigned int indent)
 {
     switch (NCDVal_Type(val)) {
         case NCDVAL_STRING: {
+            NCDValNullTermString nts;
+            FORCE( NCDVal_StringNullTerminate(val, &nts) )
+            
             print_indent(indent);
-            printf("string(%zu) %s\n", NCDVal_StringLength(val), NCDVal_StringValue(val));
+            printf("string(%zu) %s\n", NCDVal_StringLength(val), nts.data);
+            
+            NCDValNullTermString_Free(&nts);
         } break;
         
         case NCDVAL_LIST: {
@@ -105,8 +110,6 @@ int main ()
     NCDValRef s2 = NCDVal_NewString(&mem, "This is reeeeeeeeeeeeeallllllllyyyyy fun!");
     FORCE( !NCDVal_IsInvalid(s2) )
     
-    printf("%s. %s\n", NCDVal_StringValue(s1), NCDVal_StringValue(s2));
-    
     NCDValRef l1 = NCDVal_NewList(&mem, 10);
     FORCE( !NCDVal_IsInvalid(l1) )
     
@@ -135,7 +138,7 @@ int main ()
     
     NCDValRef ids1 = NCDVal_NewIdString(&mem, NCD_STRING_ARG1, &string_index);
     FORCE( !NCDVal_IsInvalid(ids1) )
-    ASSERT( !strcmp(NCDVal_StringValue(ids1), "_arg1") )
+    ASSERT( !memcmp(NCDVal_StringData(ids1), "_arg1", 5) )
     ASSERT( NCDVal_StringLength(ids1) == 5 )
     ASSERT( !NCDVal_StringHasNulls(ids1) )
     ASSERT( NCDVal_StringEquals(ids1, "_arg1") )
@@ -144,7 +147,7 @@ int main ()
     
     NCDValRef ids2 = NCDVal_NewIdString(&mem, NCD_STRING_ARG2, &string_index);
     FORCE( !NCDVal_IsInvalid(ids2) )
-    ASSERT( !strcmp(NCDVal_StringValue(ids2), "_arg2") )
+    ASSERT( !memcmp(NCDVal_StringData(ids2), "_arg2", 5) )
     ASSERT( NCDVal_StringLength(ids2) == 5 )
     ASSERT( !NCDVal_StringHasNulls(ids2) )
     ASSERT( NCDVal_StringEquals(ids2, "_arg2") )
@@ -179,12 +182,12 @@ int main ()
     for (int i = 1; i < 100; i++) {
         s[i] = NCDVal_NewCopy(&mem, s[i - 1]);
         FORCE( !NCDVal_IsInvalid(s[i]) )
-        ASSERT( !strcmp(NCDVal_StringValue(s[i - 1]), "Eeeeeeeeeeeevil.") )
-        ASSERT( !strcmp(NCDVal_StringValue(s[i]), "Eeeeeeeeeeeevil.") )
+        ASSERT( NCDVal_StringEquals(s[i - 1], "Eeeeeeeeeeeevil.") )
+        ASSERT( NCDVal_StringEquals(s[i], "Eeeeeeeeeeeevil.") )
     }
     
     for (int i = 0; i < 100; i++) {
-        ASSERT( !strcmp(NCDVal_StringValue(s[i]), "Eeeeeeeeeeeevil.") )
+        ASSERT( NCDVal_StringEquals(s[i], "Eeeeeeeeeeeevil.") )
     }
     
     NCDValMem_Free(&mem);

+ 3 - 8
ncd/NCDModule.c

@@ -405,17 +405,12 @@ int NCDModuleProcess_InitValue (NCDModuleProcess *o, NCDModuleInst *n, NCDValRef
     if (NCDVal_IsIdString(template_name)) {
         template_name_id = NCDVal_IdStringId(template_name);
     } else {
-        const char *str = NCDVal_StringValue(template_name);
+        const char *str = NCDVal_StringData(template_name);
         size_t len = NCDVal_StringLength(template_name);
         
-        if (strlen(str) != len) {
-            BLog(BLOG_ERROR, "template name cannot have nulls");
-            return 0;
-        }
-        
-        template_name_id = NCDStringIndex_Get(n->params->iparams->string_index, str);
+        template_name_id = NCDStringIndex_GetBin(n->params->iparams->string_index, str, len);
         if (template_name_id < 0) {
-            BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
+            BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
             return 0;
         }
     }

+ 46 - 6
ncd/NCDVal.c

@@ -330,7 +330,7 @@ NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val)
                 goto fail;
             }
             
-            memcpy((char *)NCDVal_StringValue(copy), NCDVal_StringValue(val), len);
+            memcpy((char *)NCDVal_StringData(copy), NCDVal_StringData(val), len);
             
             return copy;
         } break;
@@ -410,7 +410,7 @@ int NCDVal_Compare (NCDValRef val1, NCDValRef val2)
             size_t len2 = NCDVal_StringLength(val2);
             size_t min_len = len1 < len2 ? len1 : len2;
             
-            int cmp = memcmp(NCDVal_StringValue(val1), NCDVal_StringValue(val2), min_len);
+            int cmp = memcmp(NCDVal_StringData(val1), NCDVal_StringData(val2), min_len);
             if (cmp) {
                 return (cmp > 0) - (cmp < 0);
             }
@@ -525,7 +525,7 @@ int NCDVal_IsStringNoNulls (NCDValRef val)
 {
     NCDVal__AssertVal(val);
     
-    return NCDVal_Type(val) == NCDVAL_STRING && strlen(NCDVal_StringValue(val)) == NCDVal_StringLength(val);
+    return NCDVal_Type(val) == NCDVAL_STRING && !memchr(NCDVal_StringData(val), '\0', NCDVal_StringLength(val));
 }
 
 NCDValRef NCDVal_NewString (NCDValMem *mem, const char *data)
@@ -615,7 +615,7 @@ fail:
     return NCDVal_NewInvalid();
 }
 
-const char * NCDVal_StringValue (NCDValRef string)
+const char * NCDVal_StringData (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
     
@@ -647,6 +647,41 @@ size_t NCDVal_StringLength (NCDValRef string)
     return str_e->length;
 }
 
+int NCDVal_StringNullTerminate (NCDValRef string, NCDValNullTermString *out)
+{
+    ASSERT(NCDVal_IsString(string))
+    ASSERT(out)
+    
+    void *ptr = NCDValMem__BufAt(string.mem, string.idx);
+    
+    if (*(int *)ptr == IDSTRING_TYPE) {
+        struct NCDVal__idstring *ids_e = ptr;
+        out->data = (char *)NCDStringIndex_Value(ids_e->string_index, ids_e->string_id);
+        out->is_allocated = 0;
+        return 1;
+    }
+    
+    struct NCDVal__string *str_e = ptr;
+    out->data = str_e->data;
+    out->is_allocated = 0;
+    return 1;
+}
+
+NCDValNullTermString NCDValNullTermString_NewDummy (void)
+{
+    NCDValNullTermString nts;
+    nts.data = NULL;
+    nts.is_allocated = 0;
+    return nts;
+}
+
+void NCDValNullTermString_Free (NCDValNullTermString *o)
+{
+    if (o->is_allocated) {
+        BFree(o->data);
+    }
+}
+
 void NCDVal_IdStringGet (NCDValRef idstring, NCD_string_id_t *out_string_id,
                          NCDStringIndex **out_string_index)
 {
@@ -679,7 +714,10 @@ int NCDVal_StringHasNulls (NCDValRef string)
 {
     ASSERT(NCDVal_IsString(string))
     
-    return strlen(NCDVal_StringValue(string)) != NCDVal_StringLength(string);
+    const char *data = NCDVal_StringData(string);
+    size_t length = NCDVal_StringLength(string);
+    
+    return !!memchr(data, '\0', length);
 }
 
 int NCDVal_StringEquals (NCDValRef string, const char *data)
@@ -687,7 +725,9 @@ int NCDVal_StringEquals (NCDValRef string, const char *data)
     ASSERT(NCDVal_IsString(string))
     ASSERT(data)
     
-    return !NCDVal_StringHasNulls(string) && !strcmp(NCDVal_StringValue(string), data);
+    size_t len = strlen(data);
+    
+    return NCDVal_StringLength(string) == len && !memcmp(NCDVal_StringData(string), data, len);
 }
 
 int NCDVal_StringEqualsId (NCDValRef string, NCD_string_id_t string_id,

+ 40 - 10
ncd/NCDVal.h

@@ -130,6 +130,11 @@ typedef struct {
     size_t num_instrs;
 } NCDValReplaceProg;
 
+typedef struct {
+    char *data;
+    int is_allocated;
+} NCDValNullTermString;
+
 //
 
 #define NCDVAL_STRING 1
@@ -305,8 +310,7 @@ NCDValRef NCDVal_NewStringBin (NCDValMem *mem, const uint8_t *data, size_t len);
 /**
  * Builds a new string value of the given length with undefined contents.
  * You can define the contents of the string later by copying to the address
- * returned by {@link NCDVal_StringValue}. The terminating null byte is
- * however automatically written.
+ * returned by {@link NCDVal_StringData}.
  */
 NCDValRef NCDVal_NewStringUninitialized (NCDValMem *mem, size_t len);
 
@@ -319,7 +323,7 @@ NCDValRef NCDVal_NewStringUninitialized (NCDValMem *mem, size_t len);
  * efficiently as a string identifier via {@link NCDStringIndex}. An ID-string
  * is also a string and is transparent for use. For example, for an ID-string,
  * {@link NCDVal_Type} still returns NCDVAL_STRING, {@link NCDVal_IsString}
- * returns 1, and {@link NCDVal_StringValue} and {@link NCDVal_StringLength}
+ * returns 1, and {@link NCDVal_StringData} and {@link NCDVal_StringLength}
  * both work. The only way to distinguish an ID-string from a non-ID string is
  * by calling {@link NCDVal_IsIdString}.
  */
@@ -327,19 +331,46 @@ NCDValRef NCDVal_NewIdString (NCDValMem *mem, NCD_string_id_t string_id,
                               NCDStringIndex *string_index);
 
 /**
- * Returns a pointer to the data of a string value. An extra null byte
- * is always appended to the actual contents of the string.
+ * Returns a pointer to the data of a string value.
+ * WARNING: the string data may not be null-terminated. To get a null-terminated
+ * version, use {@link NCDVal_StringNullTerminate}.
  * The value reference must point to a string value.
  */
-const char * NCDVal_StringValue (NCDValRef string);
+const char * NCDVal_StringData (NCDValRef string);
 
 /**
- * Returns the length of the string value, excluding the automatically
- * appended null byte.
+ * Returns the length of the string value.
  * The value reference must point to a string value.
  */
 size_t NCDVal_StringLength (NCDValRef string);
 
+/**
+ * Produces a null-terminated version of a string value. On success, the result is
+ * stored into a {@link NCDValNullTermString} structure, and the null-terminated
+ * string is available via its 'data' member. This function may either simply pass
+ * through the data pointer as returned by {@link NCDVal_StringData} (if the string
+ * is known to be null-terminated) or produce a null-terminated dynamically allocated
+ * copy.
+ * On success, {@link NCDValNullTermString_Free} should be called to release any allocated
+ * memory when the null-terminated string is no longer needed. This must be called before
+ * the memory object is freed, because it may point to data inside the memory object.
+ * It is guaranteed that *out is not modified on failure.
+ * Returns 1 on success and 0 on failure.
+ */
+int NCDVal_StringNullTerminate (NCDValRef string, NCDValNullTermString *out) WARN_UNUSED;
+
+/**
+ * Returns a dummy {@link NCDValNullTermString} which can be freed using
+ * {@link NCDValNullTermString_Free}, but need not be.
+ */
+NCDValNullTermString NCDValNullTermString_NewDummy (void);
+
+/**
+ * Releases any memory which was dynamically allocated by {@link NCDVal_StringNullTerminate}
+ * to null-terminate a string.
+ */
+void NCDValNullTermString_Free (NCDValNullTermString *o);
+
 /**
  * Returns the string ID and the string index of an ID-string.
  * The value given must be an ID-string value (which can be determined via
@@ -364,8 +395,7 @@ NCD_string_id_t NCDVal_IdStringId (NCDValRef idstring);
 NCDStringIndex * NCDVal_IdStringStringIndex (NCDValRef idstring);
 
 /**
- * Determines if the string value has any null bytes in its contents,
- * i.e. that length > strlen().
+ * Determines if the string value has any null bytes in its contents.
  * The value reference must point to a string value.
  */
 int NCDVal_StringHasNulls (NCDValRef string);

+ 1 - 1
ncd/NCDValGenerator.c

@@ -45,7 +45,7 @@ static int generate_val (NCDValRef value, ExpString *out_str)
     
     switch (NCDVal_Type(value)) {
         case NCDVAL_STRING: {
-            const char *str = NCDVal_StringValue(value);
+            const char *str = NCDVal_StringData(value);
             size_t len = NCDVal_StringLength(value);
             
             if (!ExpString_AppendChar(out_str, '"')) {

+ 3 - 3
ncd/address_utils.h

@@ -84,7 +84,7 @@ static int ncd_read_baddr (NCDValRef val, BAddr *out)
         
         addr.type = BADDR_TYPE_IPV4;
         
-        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringValue(ipaddr_val), NCDVal_StringLength(ipaddr_val), &addr.ipv4.ip)) {
+        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(ipaddr_val), NCDVal_StringLength(ipaddr_val), &addr.ipv4.ip)) {
             goto fail;
         }
         
@@ -107,7 +107,7 @@ static int ncd_read_baddr (NCDValRef val, BAddr *out)
         addr.type = BADDR_TYPE_IPV6;
         
         struct ipv6_addr i6addr;
-        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringValue(ipaddr_val), NCDVal_StringLength(ipaddr_val), &i6addr)) {
+        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(ipaddr_val), NCDVal_StringLength(ipaddr_val), &i6addr)) {
             goto fail;
         }
         memcpy(addr.ipv6.ip, i6addr.bytes, 16);
@@ -241,7 +241,7 @@ static int ncd_read_bconnection_addr (NCDValRef val, struct BConnection_addr *ou
             goto fail;
         }
         
-        *out_addr = BConnection_addr_unix(NCDVal_StringValue(data_arg), NCDVal_StringLength(data_arg));
+        *out_addr = BConnection_addr_unix(NCDVal_StringData(data_arg), NCDVal_StringLength(data_arg));
     }
     else if (NCDVal_StringEquals(protocol_arg, "tcp")) {
         BAddr baddr;

+ 12 - 12
ncd/modules/alias.c

@@ -59,24 +59,24 @@ struct instance {
     NCD_string_id_t static_names[NUM_STATIC_NAMES];
 };
 
-static size_t count_names (const char *str)
+static size_t count_names (const char *str, size_t str_len)
 {
     size_t count = 1;
     
-    while (*str) {
+    while (str_len > 0) {
         if (*str == '.') {
             count++;
         }
         str++;
+        str_len--;
     }
     
     return count;
 }
 
-static int add_name (struct instance *o, const char *str, size_t str_len, const char *remain)
+static int add_name (struct instance *o, const char *str, size_t str_len, const char *remain, size_t remain_len)
 {
     ASSERT(str)
-    ASSERT(!memchr(str, '\0', str_len))
     ASSERT(!!o->dynamic_names == (o->num_names > NUM_STATIC_NAMES))
     
     NCD_string_id_t id = NCDStringIndex_GetBin(o->i->params->iparams->string_index, str, str_len);
@@ -90,7 +90,7 @@ static int add_name (struct instance *o, const char *str, size_t str_len, const
     }
     
     if (o->num_names == NUM_STATIC_NAMES) {
-        size_t num_more = (!remain ? 0 : count_names(remain));
+        size_t num_more = (!remain ? 0 : count_names(remain, remain_len));
         size_t num_all = o->num_names + 1 + num_more;
         
         if (!(o->dynamic_names = BAllocArray(num_all, sizeof(o->dynamic_names[0])))) {
@@ -105,7 +105,7 @@ static int add_name (struct instance *o, const char *str, size_t str_len, const
     return 1;
 }
 
-static int make_names (struct instance *o, const char *str)
+static int make_names (struct instance *o, const char *str, size_t str_len)
 {
     ASSERT(str)
     
@@ -113,19 +113,20 @@ static int make_names (struct instance *o, const char *str)
     o->dynamic_names = NULL;
     
     size_t i = 0;
-    while (str[i]) {
+    while (i < str_len) {
         if (str[i] == '.') {
-            if (!add_name(o, str, i, str + i + 1)) {
+            if (!add_name(o, str, i, str + (i + 1), str_len - (i + 1))) {
                 goto fail;
             }
             str += i + 1;
+            str_len -= i + 1;
             i = 0;
             continue;
         }
         i++;
     }
     
-    if (!add_name(o, str, i, NULL)) {
+    if (!add_name(o, str, i, NULL, 0)) {
         goto fail;
     }
     
@@ -147,14 +148,13 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(target_arg)) {
+    if (!NCDVal_IsString(target_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *target = NCDVal_StringValue(target_arg);
     
     // parse name string
-    if (!make_names(o, target)) {
+    if (!make_names(o, NCDVal_StringData(target_arg), NCDVal_StringLength(target_arg))) {
         ModuleLog(i, BLOG_ERROR, "make_names failed");
         goto fail0;
     }

+ 1 - 1
ncd/modules/concat.c

@@ -73,7 +73,7 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
             goto fail1;
         }
         
-        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringValue(arg), NCDVal_StringLength(arg))) {
+        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_Append failed");
             goto fail1;
         }

+ 1 - 1
ncd/modules/concatv.c

@@ -84,7 +84,7 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
             goto fail1;
         }
         
-        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringValue(arg), NCDVal_StringLength(arg))) {
+        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_Append failed");
             goto fail1;
         }

+ 6 - 4
ncd/modules/daemon.c

@@ -46,8 +46,10 @@
 #include <string.h>
 
 #include <misc/cmdline.h>
+#include <misc/strdup.h>
 #include <system/BProcess.h>
 #include <ncd/NCDModule.h>
+#include <ncd/value_utils.h>
 
 #include <generated/blog_channel_ncd_daemon.h>
 
@@ -94,8 +96,8 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
-        ModuleLog(i, BLOG_ERROR, "strdup failed");
+    if (!(*exec = ncd_strdup(exec_arg))) {
+        ModuleLog(i, BLOG_ERROR, "ncd_strdup failed");
         goto fail0;
     }
     
@@ -120,8 +122,8 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+        if (!CmdLine_AppendNoNull(cl, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 14 - 10
ncd/modules/depend.c

@@ -70,6 +70,7 @@
 struct provide {
     NCDModuleInst *i;
     const char *name;
+    size_t name_len;
     int is_queued;
     union {
         struct {
@@ -87,6 +88,7 @@ struct provide {
 struct depend {
     NCDModuleInst *i;
     const char *name;
+    size_t name_len;
     struct provide *p;
     LinkedList1Node node;
 };
@@ -94,13 +96,13 @@ struct depend {
 static LinkedList1 provides;
 static LinkedList1 free_depends;
 
-static struct provide * find_provide (const char *name)
+static struct provide * find_provide (const char *name, size_t name_len)
 {
     for (LinkedList1Node *n = LinkedList1_GetFirst(&provides); n; n = LinkedList1Node_Next(n)) {
         struct provide *p = UPPER_OBJECT(n, struct provide, provides_node);
         ASSERT(!p->is_queued)
         
-        if (!strcmp(p->name, name)) {
+        if (p->name_len == name_len && !memcmp(p->name, name, name_len)) {
             return p;
         }
     }
@@ -110,7 +112,7 @@ static struct provide * find_provide (const char *name)
 
 static void provide_promote (struct provide *o)
 {
-    ASSERT(!find_provide(o->name))
+    ASSERT(!find_provide(o->name, o->name_len))
     
     // set not queued
     o->is_queued = 0;
@@ -131,7 +133,7 @@ static void provide_promote (struct provide *o)
         struct depend *d = UPPER_OBJECT(n, struct depend, node);
         ASSERT(!d->p)
         
-        if (strcmp(d->name, o->name)) {
+        if (d->name_len != o->name_len || memcmp(d->name, o->name, d->name_len)) {
             n = next;
             continue;
         }
@@ -174,11 +176,12 @@ static void provide_func_new_templ (void *vo, NCDModuleInst *i, const struct NCD
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->name = NCDVal_StringValue(name_arg);
+    o->name = NCDVal_StringData(name_arg);
+    o->name_len = NCDVal_StringLength(name_arg);
     
     // signal up.
     // This comes above provide_promote(), so that effects on related depend statements are
@@ -186,7 +189,7 @@ static void provide_func_new_templ (void *vo, NCDModuleInst *i, const struct NCD
     NCDModuleInst_Backend_Up(o->i);
     
     // check for existing provide with this name
-    struct provide *ep = find_provide(o->name);
+    struct provide *ep = find_provide(o->name, o->name_len);
     if (ep) {
         ASSERT(!ep->is_queued)
         
@@ -290,14 +293,15 @@ static void depend_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleI
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->name = NCDVal_StringValue(name_arg);
+    o->name = NCDVal_StringData(name_arg);
+    o->name_len = NCDVal_StringLength(name_arg);
     
     // find a provide with our name
-    struct provide *p = find_provide(o->name);
+    struct provide *p = find_provide(o->name, o->name_len);
     ASSERT(!p || !p->is_queued)
     
     if (p && !p->dying) {

+ 40 - 20
ncd/modules/dynamic_depend.c

@@ -40,6 +40,7 @@
 #include <misc/offset.h>
 #include <misc/debug.h>
 #include <misc/compare.h>
+#include <misc/strdup.h>
 #include <structure/LinkedList0.h>
 #include <structure/BAVL.h>
 #include <ncd/NCDModule.h>
@@ -50,8 +51,13 @@
 
 struct provide;
 
+struct name_string {
+    char *data;
+    size_t len;
+};
+
 struct name {
-    char *name;
+    struct name_string name;
     BAVLNode names_tree_node;
     BAVL provides_tree;
     LinkedList0 waiting_depends_list;
@@ -80,10 +86,19 @@ static BAVL names_tree;
 static void provide_free (struct provide *o);
 static void depend_free (struct depend *o);
 
-static int stringptr_comparator (void *user, char **v1, char **v2)
+static int name_string_comparator (void *user, void *vv1, void *vv2)
 {
-    int cmp = strcmp(*v1, *v2);
-    return B_COMPARE(cmp, 0);
+    struct name_string *v1 = vv1;
+    struct name_string *v2 = vv2;
+    
+    size_t min_len = (v1->len < v2->len ? v1->len : v2->len);
+    
+    int cmp = memcmp(v1->data, v2->data, min_len);
+    if (cmp) {
+        return B_COMPARE(cmp, 0);
+    }
+    
+    return B_COMPARE(v1->len, v2->len);
 }
 
 static int val_comparator (void *user, NCDValRef *v1, NCDValRef *v2)
@@ -91,22 +106,24 @@ static int val_comparator (void *user, NCDValRef *v1, NCDValRef *v2)
     return NCDVal_Compare(*v1, *v2);
 }
 
-static struct name * find_name (const char *name)
+static struct name * find_name (const char *name, size_t name_len)
 {
-    BAVLNode *tn = BAVL_LookupExact(&names_tree, &name);
+    struct name_string ns = {(char *)name, name_len};
+    BAVLNode *tn = BAVL_LookupExact(&names_tree, &ns);
     if (!tn) {
         return NULL;
     }
     
     struct name *n = UPPER_OBJECT(tn, struct name, names_tree_node);
-    ASSERT(!strcmp(n->name, name))
+    ASSERT(n->name.len == name_len)
+    ASSERT(!memcmp(n->name.data, name, name_len))
     
     return n;
 }
 
-static struct name * name_init (NCDModuleInst *i, const char *name)
+static struct name * name_init (NCDModuleInst *i, const char *name, size_t name_len)
 {
-    ASSERT(!find_name(name))
+    ASSERT(!find_name(name, name_len))
     
     // allocate structure
     struct name *o = malloc(sizeof(*o));
@@ -116,10 +133,11 @@ static struct name * name_init (NCDModuleInst *i, const char *name)
     }
     
     // copy name
-    if (!(o->name = strdup(name))) {
+    if (!(o->name.data = b_strdup_bin(name, name_len))) {
         ModuleLog(i, BLOG_ERROR, "strdup failed");
         goto fail1;
     }
+    o->name.len = name_len;
     
     // insert to names tree
     ASSERT_EXECUTE(BAVL_Insert(&names_tree, &o->names_tree_node, NULL))
@@ -151,7 +169,7 @@ static void name_free (struct name *o)
     BAVL_Remove(&names_tree, &o->names_tree_node);
     
     // free name
-    free(o->name);
+    free(o->name.data);
     
     // free structure
     free(o);
@@ -263,7 +281,7 @@ static void name_start_resetting (struct name *o)
 static int func_globalinit (const struct NCDModuleInst_iparams *params)
 {
     // init names tree
-    BAVL_Init(&names_tree, OFFSET_DIFF(struct name, name, names_tree_node), (BAVL_comparator)stringptr_comparator, NULL);
+    BAVL_Init(&names_tree, OFFSET_DIFF(struct name, name, names_tree_node), name_string_comparator, NULL);
     
     return 1;
 }
@@ -279,15 +297,16 @@ static void provide_func_new (void *vo, NCDModuleInst *i, const struct NCDModule
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *name_str = NCDVal_StringValue(name_arg);
+    const char *name_str = NCDVal_StringData(name_arg);
+    size_t name_len = NCDVal_StringLength(name_arg);
     
     // find name, create new if needed
-    struct name *n = find_name(name_str);
-    if (!n && !(n = name_init(i, name_str))) {
+    struct name *n = find_name(name_str, name_len);
+    if (!n && !(n = name_init(i, name_str, name_len))) {
         goto fail0;
     }
     
@@ -374,15 +393,16 @@ static void depend_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleI
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *name_str = NCDVal_StringValue(name_arg);
+    const char *name_str = NCDVal_StringData(name_arg);
+    size_t name_len = NCDVal_StringLength(name_arg);
     
     // find name, create new if needed
-    struct name *n = find_name(name_str);
-    if (!n && !(n = name_init(i, name_str))) {
+    struct name *n = find_name(name_str, name_len);
+    if (!n && !(n = name_init(i, name_str, name_len))) {
         goto fail0;
     }
     

+ 2 - 2
ncd/modules/explode.c

@@ -99,7 +99,7 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         limit = (n <= SIZE_MAX ? n : SIZE_MAX);
     }
     
-    const char *del_data = NCDVal_StringValue(delimiter_arg);
+    const char *del_data = NCDVal_StringData(delimiter_arg);
     size_t del_len = NCDVal_StringLength(delimiter_arg);
     
     if (del_len == 0) {
@@ -121,7 +121,7 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     }
     o->num = 0;
     
-    const char *data = NCDVal_StringValue(input_arg);
+    const char *data = NCDVal_StringData(input_arg);
     size_t len = NCDVal_StringLength(input_arg);
     
     while (1) {

+ 30 - 5
ncd/modules/file.c

@@ -127,8 +127,17 @@ static void read_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIns
         goto fail0;
     }
     
+    // get null terminated name
+    NCDValNullTermString filename_nts;
+    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // read file
-    if (!read_file(NCDVal_StringValue(filename_arg), &o->file_data, &o->file_len)) {
+    int res = read_file(filename_nts.data, &o->file_data, &o->file_len);
+    NCDValNullTermString_Free(&filename_nts);
+    if (!res) {
         ModuleLog(i, BLOG_ERROR, "failed to read file");
         goto fail0;
     }
@@ -181,8 +190,17 @@ static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
         goto fail0;
     }
     
+    // get null terminated name
+    NCDValNullTermString filename_nts;
+    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // write file
-    if (!write_file(NCDVal_StringValue(filename_arg), (const uint8_t *)NCDVal_StringValue(contents_arg), NCDVal_StringLength(contents_arg))) {
+    int res = write_file(filename_nts.data, (const uint8_t *)NCDVal_StringData(contents_arg), NCDVal_StringLength(contents_arg));
+    NCDValNullTermString_Free(&filename_nts);
+    if (!res) {
         ModuleLog(i, BLOG_ERROR, "failed to write file");
         goto fail0;
     }
@@ -216,14 +234,21 @@ static void stat_func_new_common (void *vo, NCDModuleInst *i, const struct NCDMo
     if (!NCDVal_IsStringNoNulls(filename_arg)) {
         goto out;
     }
-    const char *filename = NCDVal_StringValue(filename_arg);
+    
+    // null terminate filename
+    NCDValNullTermString filename_nts;
+    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     int res;
     if (is_lstat) {
-        res = lstat(filename, &o->result);
+        res = lstat(filename_nts.data, &o->result);
     } else {
-        res = stat(filename, &o->result);
+        res = stat(filename_nts.data, &o->result);
     }
+    NCDValNullTermString_Free(&filename_nts);
     
     if (res < 0) {
         goto out;

+ 26 - 13
ncd/modules/file_open.c

@@ -129,35 +129,40 @@ static struct NCD_string_request strings[] = {
     {"is_error"}, {"not_eof"}, {NULL}
 };
 
-static int parse_mode (const char *data, char *out)
+static int parse_mode (const char *data, size_t mode_len, char *out)
 {
+    if (mode_len == 0) {
+        return 0;
+    }
     switch (*data) {
         case 'r':
         case 'w':
         case 'a':
             *out++ = *data++;
+            mode_len--;
             break;
         default:
             return 0;
     }
     
+    if (mode_len == 0) {
+        goto finish;
+    }
     switch (*data) {
-        case '\0':
-            goto finish;
         case '+':
             *out++ = *data++;
+            mode_len--;
             break;
         default:
             return 0;
     }
     
-    switch (*data) {
-        case '\0':
-            goto finish;
-        default:
-            return 0;
+    if (mode_len == 0) {
+        goto finish;
     }
     
+    return 0;
+    
 finish:
     *out = '\0';
     return 1;
@@ -192,20 +197,28 @@ static void open_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIns
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(filename_arg) || !NCDVal_IsStringNoNulls(mode_arg)) {
+    if (!NCDVal_IsStringNoNulls(filename_arg) || !NCDVal_IsString(mode_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // check mode
     char mode[5];
-    if (!parse_mode(NCDVal_StringValue(mode_arg), mode)) {
+    if (!parse_mode(NCDVal_StringData(mode_arg), NCDVal_StringLength(mode_arg), mode)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong mode");
         goto fail0;
     }
     
+    // null terminate filename
+    NCDValNullTermString filename_nts;
+    if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // open file
-    o->fh = fopen(NCDVal_StringValue(filename_arg), mode);
+    o->fh = fopen(filename_nts.data, mode);
+    NCDValNullTermString_Free(&filename_nts);
     if (!o->fh) {
         ModuleLog(o->i, BLOG_ERROR, "fopen failed");
     }
@@ -391,7 +404,7 @@ static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
     }
     
     // get data pointer and length
-    const char *data = NCDVal_StringValue(data_arg);
+    const char *data = NCDVal_StringData(data_arg);
     size_t length = NCDVal_StringLength(data_arg);
     
     while (length > 0) {
@@ -435,7 +448,7 @@ static void seek_func_new (void *unused, NCDModuleInst *i, const struct NCDModul
     // parse position
     int position_sign;
     uintmax_t position_mag;
-    if (!parse_signmag_integer_bin(NCDVal_StringValue(position_arg), NCDVal_StringLength(position_arg), &position_sign, &position_mag)) {
+    if (!parse_signmag_integer_bin(NCDVal_StringData(position_arg), NCDVal_StringLength(position_arg), &position_sign, &position_mag)) {
         ModuleLog(i, BLOG_ERROR, "wrong position");
         goto fail0;
     }

+ 1 - 1
ncd/modules/from_string.c

@@ -71,7 +71,7 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     NCDValMem_Init(&o->mem);
     
     // parse value string
-    if (!NCDValParser_Parse(NCDVal_StringValue(str_arg), NCDVal_StringLength(str_arg), &o->mem, &o->val)) {
+    if (!NCDValParser_Parse(NCDVal_StringData(str_arg), NCDVal_StringLength(str_arg), &o->mem, &o->val)) {
         ModuleLog(i, BLOG_ERROR, "failed to parse");
         goto fail1;
     }

+ 2 - 2
ncd/modules/implode.c

@@ -89,14 +89,14 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         
         // append glue
         if (j > 0) {
-            if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringValue(glue_arg), NCDVal_StringLength(glue_arg))) {
+            if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringData(glue_arg), NCDVal_StringLength(glue_arg))) {
                 ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
                 goto fail1;
             }
         }
         
         // append piece
-        if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringValue(piece), NCDVal_StringLength(piece))) {
+        if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringData(piece), NCDVal_StringLength(piece))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
             goto fail1;
         }

+ 9 - 7
ncd/modules/multidepend.c

@@ -59,6 +59,7 @@
 struct provide {
     NCDModuleInst *i;
     const char *name;
+    size_t name_len;
     LinkedList1Node provides_node;
     LinkedList1 depends;
     int dying;
@@ -76,11 +77,11 @@ struct depend {
 static LinkedList1 provides;
 static LinkedList1 depends;
 
-static struct provide * find_provide (const char *name)
+static struct provide * find_provide (const char *name, size_t name_len)
 {
     for (LinkedList1Node *n = LinkedList1_GetFirst(&provides); n; n = LinkedList1Node_Next(n)) {
         struct provide *p = UPPER_OBJECT(n, struct provide, provides_node);
-        if (!strcmp(p->name, name)) {
+        if (p->name_len == name_len && !memcmp(p->name, name, name_len)) {
             return p;
         }
     }
@@ -94,7 +95,7 @@ static struct provide * depend_find_best_provide (struct depend *o)
     
     for (size_t j = 0; j < count; j++) {
         NCDValRef e = NCDVal_ListGet(o->names, j);
-        struct provide *p = find_provide(NCDVal_StringValue(e));
+        struct provide *p = find_provide(NCDVal_StringData(e), NCDVal_StringLength(e));
         if (p && !p->dying) {
             return p;
         }
@@ -162,14 +163,15 @@ static void provide_func_new (void *vo, NCDModuleInst *i, const struct NCDModule
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->name = NCDVal_StringValue(name_arg);
+    o->name = NCDVal_StringData(name_arg);
+    o->name_len = NCDVal_StringLength(name_arg);
     
     // check for existing provide with this name
-    if (find_provide(o->name)) {
+    if (find_provide(o->name, o->name_len)) {
         ModuleLog(o->i, BLOG_ERROR, "a provide with this name already exists");
         goto fail0;
     }
@@ -256,7 +258,7 @@ static void depend_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleI
     size_t count = NCDVal_ListCount(o->names);
     for (size_t j = 0; j < count; j++) {
         NCDValRef e = NCDVal_ListGet(o->names, j);
-        if (!NCDVal_IsStringNoNulls(e)) {
+        if (!NCDVal_IsString(e)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail0;
         }

+ 30 - 15
ncd/modules/net_backend_badvpn.c

@@ -48,9 +48,11 @@
 
 struct instance {
     NCDModuleInst *i;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
     const char *user;
+    size_t user_len;
     const char *exec;
+    size_t exec_len;
     NCDValRef args;
     int dying;
     int started;
@@ -71,12 +73,12 @@ void try_process (struct instance *o)
     }
     
     // append exec
-    if (!CmdLine_Append(&c, o->exec)) {
+    if (!CmdLine_AppendNoNull(&c, o->exec, o->exec_len)) {
         goto fail1;
     }
     
     // append tapdev
-    if (!CmdLine_Append(&c, "--tapdev") || !CmdLine_Append(&c, o->ifname)) {
+    if (!CmdLine_Append(&c, "--tapdev") || !CmdLine_Append(&c, o->ifname_nts.data)) {
         goto fail1;
     }
     
@@ -84,7 +86,7 @@ void try_process (struct instance *o)
     size_t count = NCDVal_ListCount(o->args);
     for (size_t j = 0; j < count; j++) {
         NCDValRef arg = NCDVal_ListGet(o->args, j);
-        if (!CmdLine_Append(&c, NCDVal_StringValue(arg))) {
+        if (!CmdLine_AppendNoNull(&c, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
             goto fail1;
         }
     }
@@ -165,9 +167,11 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->ifname = NCDVal_StringValue(ifname_arg);
-    o->user = NCDVal_StringValue(user_arg);
-    o->exec = NCDVal_StringValue(exec_arg);
+    
+    o->user = NCDVal_StringData(user_arg);
+    o->user_len = NCDVal_StringLength(user_arg);
+    o->exec = NCDVal_StringData(exec_arg);
+    o->exec_len = NCDVal_StringLength(exec_arg);
     o->args = args_arg;
     
     // check arguments
@@ -180,16 +184,22 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         }
     }
     
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // create TAP device
-    if (!NCDIfConfig_make_tuntap(o->ifname, o->user, 0)) {
+    if (!NCDIfConfig_make_tuntap(o->ifname_nts.data, o->user, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to create TAP device");
-        goto fail0;
+        goto fail1;
     }
     
     // set device up
-    if (!NCDIfConfig_set_up(o->ifname)) {
+    if (!NCDIfConfig_set_up(o->ifname_nts.data)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to set device up");
-        goto fail1;
+        goto fail2;
     }
     
     // set not dying
@@ -205,10 +215,12 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     try_process(o);
     return;
     
-fail1:
-    if (!NCDIfConfig_remove_tuntap(o->ifname, 0)) {
+fail2:
+    if (!NCDIfConfig_remove_tuntap(o->ifname_nts.data, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to remove TAP device");
     }
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -222,15 +234,18 @@ void instance_free (struct instance *o)
     BReactor_RemoveTimer(o->i->params->iparams->reactor, &o->timer);
     
     // set device down
-    if (!NCDIfConfig_set_down(o->ifname)) {
+    if (!NCDIfConfig_set_down(o->ifname_nts.data)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to set device down");
     }
     
     // free TAP device
-    if (!NCDIfConfig_remove_tuntap(o->ifname, 0)) {
+    if (!NCDIfConfig_remove_tuntap(o->ifname_nts.data, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to remove TAP device");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 21 - 11
ncd/modules/net_backend_rfkill.c

@@ -142,40 +142,50 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(type_arg) || !NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(type_arg) || !NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *type = NCDVal_StringValue(type_arg);
-    const char *name = NCDVal_StringValue(name_arg);
     
-    if (!strcmp(type, "index")) {
-        if (sscanf(name, "%"SCNu32, &o->index) != 1) {
+    // null terminate name
+    NCDValNullTermString name_nts;
+    if (!NCDVal_StringNullTerminate(name_arg, &name_nts)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
+    if (NCDVal_StringEquals(type_arg, "index")) {
+        if (sscanf(name_nts.data, "%"SCNu32, &o->index) != 1) {
             ModuleLog(o->i, BLOG_ERROR, "wrong index argument");
-            goto fail0;
+            goto fail1;
         }
     }
-    else if (!strcmp(type, "wlan")) {
-        if (!find_wlan_rfill(name, &o->index)) {
+    else if (NCDVal_StringEquals(type_arg, "wlan")) {
+        if (!find_wlan_rfill(name_nts.data, &o->index)) {
             ModuleLog(o->i, BLOG_ERROR, "failed to find rfkill for wlan interface");
-            goto fail0;
+            goto fail1;
         }
     }
     else {
         ModuleLog(o->i, BLOG_ERROR, "unknown type argument");
-        goto fail0;
+        goto fail1;
     }
     
     // init monitor
     if (!NCDRfkillMonitor_Init(&o->monitor, o->i->params->iparams->reactor, (NCDRfkillMonitor_handler)monitor_handler, o)) {
         ModuleLog(o->i, BLOG_ERROR, "monitor failed");
-        goto fail0;
+        goto fail1;
     }
     
     // set not up
     o->up = 0;
+    
+    // free name nts
+    NCDValNullTermString_Free(&name_nts);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&name_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);

+ 4 - 2
ncd/modules/net_backend_waitdevice.c

@@ -52,6 +52,7 @@
 struct instance {
     NCDModuleInst *i;
     const char *ifname;
+    size_t ifname_len;
     NCDUdevClient client;
     regex_t reg;
     char *devpath;
@@ -80,7 +81,7 @@ static void client_handler (struct instance *o, char *devpath, int have_map, BSt
         const char *ifindex_str = BStringMap_Get(cache_map, "IFINDEX");
         
         uintmax_t ifindex;
-        if (!(!match_res && interface && !strcmp(interface, o->ifname) && ifindex_str && parse_unsigned_integer(ifindex_str, &ifindex))) {
+        if (!(!match_res && interface && strlen(interface) == o->ifname_len && !memcmp(interface, o->ifname, o->ifname_len) && ifindex_str && parse_unsigned_integer(ifindex_str, &ifindex))) {
             goto out;
         }
         
@@ -130,7 +131,8 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->ifname = NCDVal_StringValue(arg);
+    o->ifname = NCDVal_StringData(arg);
+    o->ifname_len = NCDVal_StringLength(arg);
     
     // init client
     NCDUdevClient_Init(&o->client, o->i->params->iparams->umanager, o, (NCDUdevClient_handler)client_handler);

+ 13 - 5
ncd/modules/net_backend_waitlink.c

@@ -82,20 +82,28 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     o->i = i;
     
     // check arguments
-    NCDValRef arg;
-    if (!NCDVal_ListRead(params->args, 1, &arg)) {
+    NCDValRef ifname_arg;
+    if (!NCDVal_ListRead(params->args, 1, &ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(arg)) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *ifname = NCDVal_StringValue(arg);
+    
+    // null terminate ifname
+    NCDValNullTermString ifname_nts;
+    if (!NCDVal_StringNullTerminate(ifname_arg, &ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // get interface index
     int ifindex;
-    if (!get_iface_info(ifname, NULL, NULL, &ifindex)) {
+    int res = get_iface_info(ifname_nts.data, NULL, NULL, &ifindex);
+    NCDValNullTermString_Free(&ifname_nts);
+    if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "failed to get interface index");
         goto fail0;
     }

+ 15 - 8
ncd/modules/net_backend_wpa_supplicant.c

@@ -69,8 +69,11 @@
 struct instance {
     NCDModuleInst *i;
     const char *ifname;
+    size_t ifname_len;
     const char *conf;
+    size_t conf_len;
     const char *exec;
+    size_t exec_len;
     NCDValRef args;
     int dying;
     int up;
@@ -211,7 +214,7 @@ int build_cmdline (struct instance *o, CmdLine *c)
     }
     
     // append stdbuf part
-    if (!build_stdbuf_cmdline(c, o->exec, strlen(o->exec))) {
+    if (!build_stdbuf_cmdline(c, o->exec, o->exec_len)) {
         goto fail1;
     }
     
@@ -226,18 +229,18 @@ int build_cmdline (struct instance *o, CmdLine *c)
         }
         
         // append argument
-        if (!CmdLine_Append(c, NCDVal_StringValue(arg))) {
+        if (!CmdLine_AppendNoNull(c, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
             goto fail1;
         }
     }
     
     // append interface name
-    if (!CmdLine_Append(c, "-i") || !CmdLine_Append(c, o->ifname)) {
+    if (!CmdLine_Append(c, "-i") || !CmdLine_AppendNoNull(c, o->ifname, o->ifname_len)) {
         goto fail1;
     }
     
     // append config file
-    if (!CmdLine_Append(c, "-c") || !CmdLine_Append(c, o->conf)) {
+    if (!CmdLine_Append(c, "-c") || !CmdLine_AppendNoNull(c, o->conf, o->conf_len)) {
         goto fail1;
     }
     
@@ -343,7 +346,7 @@ void process_pipe_handler_send (struct instance *o, uint8_t *data, int data_len)
     // prefix, so don't fail if there isn't one.
     size_t l1;
     size_t l2;
-    if (strlen(o->ifname) > 0 && (l1 = data_begins_with((char *)data, data_len, o->ifname)) && (l2 = data_begins_with((char *)data + l1, data_len - l1, ": "))) {
+    if (o->ifname_len > 0 && (l1 = data_begins_with_bin((char *)data, data_len, o->ifname, o->ifname_len)) && (l2 = data_begins_with((char *)data + l1, data_len - l1, ": "))) {
         data += l1 + l2;
         data_len -= l1 + l2;
     }
@@ -416,9 +419,13 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->ifname = NCDVal_StringValue(ifname_arg);
-    o->conf = NCDVal_StringValue(conf_arg);
-    o->exec = NCDVal_StringValue(exec_arg);
+    
+    o->ifname = NCDVal_StringData(ifname_arg);
+    o->ifname_len = NCDVal_StringLength(ifname_arg);
+    o->conf = NCDVal_StringData(conf_arg);
+    o->conf_len = NCDVal_StringLength(conf_arg);
+    o->exec = NCDVal_StringData(exec_arg);
+    o->exec_len = NCDVal_StringLength(exec_arg);
     o->args = args_arg;
     
     // set not dying

+ 10 - 4
ncd/modules/net_dns.c

@@ -35,6 +35,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
 #include <misc/offset.h>
 #include <misc/bsort.h>
@@ -43,6 +44,7 @@
 #include <structure/LinkedList1.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDIfConfig.h>
+#include <ncd/value_utils.h>
 
 #include <generated/blog_channel_ncd_net_dns.h>
 
@@ -201,25 +203,29 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDVal_IsList(servers_arg) || !NCDVal_IsStringNoNulls(priority_arg)) {
+    if (!NCDVal_IsList(servers_arg) || !NCDVal_IsString(priority_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
-    int priority = atoi(NCDVal_StringValue(priority_arg));
+    uintmax_t priority;
+    if (!ncd_read_uintmax(priority_arg, &priority) || priority > INT_MAX) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong priority");
+        goto fail1;
+    }
     
     // read servers
     size_t count = NCDVal_ListCount(servers_arg);
     for (size_t j = 0; j < count; j++) {
         NCDValRef server_arg = NCDVal_ListGet(servers_arg, j);
         
-        if (!NCDVal_IsStringNoNulls(server_arg)) {
+        if (!NCDVal_IsString(server_arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
         
         uint32_t addr;
-        if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(server_arg), &addr)) {
+        if (!ipaddr_parse_ipv4_addr_bin((char *)NCDVal_StringData(server_arg), NCDVal_StringLength(server_arg), &addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong addr");
             goto fail1;
         }

+ 29 - 15
ncd/modules/net_iptables.c

@@ -149,8 +149,10 @@ static int build_append_cmdline (NCDModuleInst *i, NCDValRef args, const char *p
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *table = NCDVal_StringValue(table_arg);
-    const char *chain = NCDVal_StringValue(chain_arg);
+    const char *table = NCDVal_StringData(table_arg);
+    size_t table_len = NCDVal_StringLength(table_arg);
+    const char *chain = NCDVal_StringData(chain_arg);
+    size_t chain_len = NCDVal_StringLength(chain_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {
@@ -165,7 +167,7 @@ static int build_append_cmdline (NCDModuleInst *i, NCDValRef args, const char *p
     }
     
     // add header
-    if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_Append(cl, table) || !CmdLine_Append(cl, (remove ? "-D" : "-A")) || !CmdLine_Append(cl, chain)) {
+    if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_AppendNoNull(cl, table, table_len) || !CmdLine_Append(cl, (remove ? "-D" : "-A")) || !CmdLine_AppendNoNull(cl, chain, chain_len)) {
         ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
         goto fail2;
     }
@@ -180,8 +182,8 @@ static int build_append_cmdline (NCDModuleInst *i, NCDValRef args, const char *p
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+        if (!CmdLine_AppendNoNull(cl, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }
@@ -219,10 +221,14 @@ static int build_policy_cmdline (NCDModuleInst *i, NCDValRef args, const char *p
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *table = NCDVal_StringValue(table_arg);
-    const char *chain = NCDVal_StringValue(chain_arg);
-    const char *target = NCDVal_StringValue(target_arg);
-    const char *revert_target = NCDVal_StringValue(revert_target_arg);
+    const char *table = NCDVal_StringData(table_arg);
+    size_t table_len = NCDVal_StringLength(table_arg);
+    const char *chain = NCDVal_StringData(chain_arg);
+    size_t chain_len = NCDVal_StringLength(chain_arg);
+    const char *target = NCDVal_StringData(target_arg);
+    size_t target_len = NCDVal_StringLength(target_arg);
+    const char *revert_target = NCDVal_StringData(revert_target_arg);
+    size_t revert_target_len = NCDVal_StringLength(revert_target_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {
@@ -237,8 +243,10 @@ static int build_policy_cmdline (NCDModuleInst *i, NCDValRef args, const char *p
     }
     
     // add arguments
-    if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_Append(cl, table) ||
-        !CmdLine_Append(cl, "-P") || !CmdLine_Append(cl, chain) || !CmdLine_Append(cl, (remove ? revert_target : target))) {
+    if (!CmdLine_Append(cl, *exec) || !CmdLine_Append(cl, "-t") || !CmdLine_AppendNoNull(cl, table, table_len) ||
+        !CmdLine_Append(cl, "-P") || !CmdLine_AppendNoNull(cl, chain, chain_len) ||
+        !CmdLine_AppendNoNull(cl, (remove ? revert_target : target), (remove ? revert_target_len : target_len))
+    ) {
         ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
         goto fail2;
     }
@@ -272,8 +280,10 @@ static int build_newchain_cmdline (NCDModuleInst *i, NCDValRef args, const char
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *table = (NCDVal_IsInvalid(table_arg) ? "filter" : NCDVal_StringValue(table_arg));
-    const char *chain = NCDVal_StringValue(chain_arg);
+    const char *table = (NCDVal_IsInvalid(table_arg) ? "filter" : NCDVal_StringData(table_arg));
+    size_t table_len = (NCDVal_IsInvalid(table_arg) ? 6 : NCDVal_StringLength(table_arg));
+    const char *chain = NCDVal_StringData(chain_arg);
+    size_t chain_len = NCDVal_StringLength(chain_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {
@@ -288,8 +298,12 @@ static int build_newchain_cmdline (NCDModuleInst *i, NCDValRef args, const char
     }
     
     // add arguments
-    if (!CmdLine_AppendMulti(cl, 5, *exec, "-t", table, (remove ? "-X" : "-N"), chain)) {
-        ModuleLog(i, BLOG_ERROR, "CmdLine_AppendMulti failed");
+    if (!CmdLine_AppendMulti(cl, 2, *exec, "-t") ||
+        !CmdLine_AppendNoNull(cl, table, table_len) ||
+        !CmdLine_Append(cl, (remove ? "-X" : "-N")) ||
+        !CmdLine_AppendNoNull(cl, chain, chain_len)
+    ) {
+        ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
         goto fail2;
     }
     

+ 22 - 13
ncd/modules/net_ipv4_addr.c

@@ -52,7 +52,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
     struct ipv4_ifaddr ifaddr;
 };
 
@@ -71,42 +71,48 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(addr_arg) ||
-        (!NCDVal_IsInvalid(prefix_arg) && !NCDVal_IsStringNoNulls(prefix_arg))
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsString(addr_arg) ||
+        (!NCDVal_IsInvalid(prefix_arg) && !NCDVal_IsString(prefix_arg))
     ) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
-    o->ifname = NCDVal_StringValue(ifname_arg);
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     if (NCDVal_IsInvalid(prefix_arg)) {
-        if (!ipaddr_parse_ipv4_ifaddr(NCDVal_StringValue(addr_arg), &o->ifaddr)) {
+        if (!ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringData(addr_arg), NCDVal_StringLength(addr_arg), &o->ifaddr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong CIDR notation address");
-            goto fail0;
+            goto fail1;
         }
     } else {
-        if (!ipaddr_parse_ipv4_addr(NCDVal_StringValue(addr_arg), &o->ifaddr.addr)) {
+        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(addr_arg), NCDVal_StringLength(addr_arg), &o->ifaddr.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong address");
-            goto fail0;
+            goto fail1;
         }
         
-        if (!ipaddr_parse_ipv4_prefix(NCDVal_StringValue(prefix_arg), &o->ifaddr.prefix)) {
+        if (!ipaddr_parse_ipv4_prefix_bin(NCDVal_StringData(prefix_arg), NCDVal_StringLength(prefix_arg), &o->ifaddr.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong prefix");
-            goto fail0;
+            goto fail1;
         }
     }
     
     // add address
-    if (!NCDIfConfig_add_ipv4_addr(o->ifname, o->ifaddr)) {
+    if (!NCDIfConfig_add_ipv4_addr(o->ifname_nts.data, o->ifaddr)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to add IP address");
-        goto fail0;
+        goto fail1;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -117,10 +123,13 @@ static void func_die (void *vo)
     struct instance *o = vo;
     
     // remove address
-    if (!NCDIfConfig_remove_ipv4_addr(o->ifname, o->ifaddr)) {
+    if (!NCDIfConfig_remove_ipv4_addr(o->ifname_nts.data, o->ifaddr)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to remove IP address");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 4 - 4
ncd/modules/net_ipv4_addr_in_network.c

@@ -83,7 +83,7 @@ static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleI
     
     // parse addr
     uint32_t addr;
-    if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringValue(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
+    if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
         ModuleLog(o->i, BLOG_ERROR, "bad address");
         goto fail0;
     }
@@ -91,16 +91,16 @@ static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleI
     // parse network
     struct ipv4_ifaddr network;
     if (NCDVal_IsInvalid(arg_net_prefix)) {
-        if (!ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringValue(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network)) {
+        if (!ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network in CIDR notation");
             goto fail0;
         }
     } else {
-        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringValue(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network.addr)) {
+        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network address");
             goto fail0;
         }
-        if (!ipaddr_parse_ipv4_prefix_bin(NCDVal_StringValue(arg_net_prefix), NCDVal_StringLength(arg_net_prefix), &network.prefix)) {
+        if (!ipaddr_parse_ipv4_prefix_bin(NCDVal_StringData(arg_net_prefix), NCDVal_StringLength(arg_net_prefix), &network.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network prefix");
             goto fail0;
         }

+ 12 - 5
ncd/modules/net_ipv4_arp_probe.c

@@ -130,22 +130,29 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(arg_ifname) || !NCDVal_IsStringNoNulls(arg_addr)) {
+    if (!NCDVal_IsStringNoNulls(arg_ifname) || !NCDVal_IsString(arg_addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *ifname = NCDVal_StringValue(arg_ifname);
-    const char *addr_str = NCDVal_StringValue(arg_addr);
     
     // parse address
     uint32_t addr;
-    if (!ipaddr_parse_ipv4_addr((char *)addr_str, &addr)) {
+    if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong address");
         goto fail0;
     }
     
+    // null terminate ifname
+    NCDValNullTermString ifname_nts;
+    if (!NCDVal_StringNullTerminate(arg_ifname, &ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // init arpprobe
-    if (!BArpProbe_Init(&o->arpprobe, ifname, addr, i->params->iparams->reactor, o, (BArpProbe_handler)arpprobe_handler)) {
+    int res = BArpProbe_Init(&o->arpprobe, ifname_nts.data, addr, i->params->iparams->reactor, o, (BArpProbe_handler)arpprobe_handler);
+    NCDValNullTermString_Free(&ifname_nts);
+    if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "BArpProbe_Init failed");
         goto fail0;
     }

+ 43 - 15
ncd/modules/net_ipv4_dhcp.c

@@ -115,7 +115,9 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *ifname = NCDVal_StringValue(ifname_arg);
+    
+    NCDValNullTermString hostname_nts = NCDValNullTermString_NewDummy();
+    NCDValNullTermString vendorclassid_nts = NCDValNullTermString_NewDummy();
     
     struct BDHCPClient_opts opts = {};
     
@@ -125,52 +127,78 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         NCDValRef opt = NCDVal_ListGet(opts_arg, j);
         
         // read name
-        if (!NCDVal_IsStringNoNulls(opt)) {
+        if (!NCDVal_IsString(opt)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
-            goto fail0;
+            goto fail1;
         }
-        const char *optname = NCDVal_StringValue(opt);
         
-        if (!strcmp(optname, "hostname") || !strcmp(optname, "vendorclassid")) {
+        if (NCDVal_StringEquals(opt, "hostname") || NCDVal_StringEquals(opt, "vendorclassid")) {
+            int is_hostname = NCDVal_StringEquals(opt, "hostname");
+            
             // read value
             if (j == count) {
                 ModuleLog(o->i, BLOG_ERROR, "option value missing");
-                goto fail0;
+                goto fail1;
             }
             NCDValRef val = NCDVal_ListGet(opts_arg, j + 1);
             if (!NCDVal_IsStringNoNulls(val)) {
                 ModuleLog(o->i, BLOG_ERROR, "wrong option value type");
-                goto fail0;
+                goto fail1;
+            }
+            
+            // null terminate
+            NCDValNullTermString nts;
+            if (!NCDVal_StringNullTerminate(val, &nts)) {
+                ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+                goto fail1;
             }
-            const char *optval = NCDVal_StringValue(val);
+            NCDValNullTermString *nts_ptr = (is_hostname ? &hostname_nts : &vendorclassid_nts);
+            NCDValNullTermString_Free(nts_ptr);
+            *nts_ptr = nts;
             
-            if (!strcmp(optname, "hostname")) {
-                opts.hostname = optval;
+            if (is_hostname) {
+                opts.hostname = nts.data;
             } else {
-                opts.vendorclassid = optval;
+                opts.vendorclassid = nts.data;
             }
             
             j++;
         }
-        else if (!strcmp(optname, "auto_clientid")) {
+        else if (NCDVal_StringEquals(opt, "auto_clientid")) {
             opts.auto_clientid = 1;
         }
         else {
             ModuleLog(o->i, BLOG_ERROR, "unknown option name");
-            goto fail0;
+            goto fail1;
         }
     }
     
+    // null terminate ifname
+    NCDValNullTermString ifname_nts;
+    if (!NCDVal_StringNullTerminate(ifname_arg, &ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail1;
+    }
+    
     // init DHCP
-    if (!BDHCPClient_Init(&o->dhcp, ifname, opts, o->i->params->iparams->reactor, o->i->params->iparams->random2, (BDHCPClient_handler)dhcp_handler, o)) {
+    int res = BDHCPClient_Init(&o->dhcp, ifname_nts.data, opts, o->i->params->iparams->reactor, o->i->params->iparams->random2, (BDHCPClient_handler)dhcp_handler, o);
+    NCDValNullTermString_Free(&ifname_nts);
+    if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "BDHCPClient_Init failed");
-        goto fail0;
+        goto fail1;
     }
     
     // set not up
     o->up = 0;
+    
+    // free options nts's
+    NCDValNullTermString_Free(&hostname_nts);
+    NCDValNullTermString_Free(&vendorclassid_nts);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&hostname_nts);
+    NCDValNullTermString_Free(&vendorclassid_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);

+ 33 - 19
ncd/modules/net_ipv4_route.c

@@ -44,10 +44,12 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 
 #include <misc/debug.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDIfConfig.h>
+#include <ncd/value_utils.h>
 
 #include <generated/blog_channel_ncd_net_ipv4_route.h>
 
@@ -63,7 +65,7 @@ struct instance {
     int type;
     uint32_t gateway;
     int metric;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
 };
 
 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
@@ -83,9 +85,9 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(dest_arg) || !NCDVal_IsStringNoNulls(gateway_arg) ||
-        !NCDVal_IsStringNoNulls(metric_arg) || !NCDVal_IsStringNoNulls(ifname_arg) ||
-        (!NCDVal_IsInvalid(dest_prefix_arg) && !NCDVal_IsStringNoNulls(dest_prefix_arg))
+    if (!NCDVal_IsString(dest_arg) || !NCDVal_IsString(gateway_arg) ||
+        !NCDVal_IsString(metric_arg) || !NCDVal_IsStringNoNulls(ifname_arg) ||
+        (!NCDVal_IsInvalid(dest_prefix_arg) && !NCDVal_IsString(dest_prefix_arg))
     ) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
@@ -93,30 +95,29 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     
     // read dest
     if (NCDVal_IsInvalid(dest_prefix_arg)) {
-        if (!ipaddr_parse_ipv4_ifaddr(NCDVal_StringValue(dest_arg), &o->dest)) {
+        if (!ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringData(dest_arg), NCDVal_StringLength(dest_arg), &o->dest)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong CIDR notation dest");
             goto fail0;
         }
     } else {
-        if (!ipaddr_parse_ipv4_addr(NCDVal_StringValue(dest_arg), &o->dest.addr)) {
+        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(dest_arg), NCDVal_StringLength(dest_arg), &o->dest.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong dest addr");
             goto fail0;
         }
-        if (!ipaddr_parse_ipv4_prefix(NCDVal_StringValue(dest_prefix_arg), &o->dest.prefix)) {
+        if (!ipaddr_parse_ipv4_prefix_bin(NCDVal_StringData(dest_prefix_arg), NCDVal_StringLength(dest_prefix_arg), &o->dest.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong dest prefix");
             goto fail0;
         }
     }
     
     // read gateway and choose type
-    const char *gateway_str = NCDVal_StringValue(gateway_arg);
-    if (!strcmp(gateway_str, "none")) {
+    if (NCDVal_StringEquals(gateway_arg, "none")) {
         o->type = TYPE_IFONLY;
     }
-    else if (!strcmp(gateway_str, "blackhole")) {
+    else if (NCDVal_StringEquals(gateway_arg, "blackhole")) {
         o->type = TYPE_BLACKHOLE;
     } else {
-        if (!ipaddr_parse_ipv4_addr(gateway_str, &o->gateway)) {
+        if (!ipaddr_parse_ipv4_addr_bin(NCDVal_StringData(gateway_arg), NCDVal_StringLength(gateway_arg), &o->gateway)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong gateway");
             goto fail0;
         }
@@ -124,19 +125,27 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     }
     
     // read metric
-    o->metric = atoi(NCDVal_StringValue(metric_arg));
+    uintmax_t metric;
+    if (!ncd_read_uintmax(metric_arg, &metric) || metric > INT_MAX) {
+        ModuleLog(i, BLOG_ERROR, "bad metric");
+        goto fail0;
+    }
+    o->metric = metric;
     
-    // read ifname
-    o->ifname = NCDVal_StringValue(ifname_arg);
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // add route
     int res = 0; // to remove warning
     switch (o->type) {
         case TYPE_NORMAL:
-            res = NCDIfConfig_add_ipv4_route(o->dest, &o->gateway, o->metric, o->ifname);
+            res = NCDIfConfig_add_ipv4_route(o->dest, &o->gateway, o->metric, o->ifname_nts.data);
             break;
         case TYPE_IFONLY:
-            res = NCDIfConfig_add_ipv4_route(o->dest, NULL, o->metric, o->ifname);
+            res = NCDIfConfig_add_ipv4_route(o->dest, NULL, o->metric, o->ifname_nts.data);
             break;
         case TYPE_BLACKHOLE:
             res = NCDIfConfig_add_ipv4_blackhole_route(o->dest, o->metric);
@@ -145,13 +154,15 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     }
     if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "failed to add route");
-        goto fail0;
+        goto fail1;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -165,10 +176,10 @@ static void func_die (void *vo)
     int res = 0; // to remove warning
     switch (o->type) {
         case TYPE_NORMAL:
-            res = NCDIfConfig_remove_ipv4_route(o->dest, &o->gateway, o->metric, o->ifname);
+            res = NCDIfConfig_remove_ipv4_route(o->dest, &o->gateway, o->metric, o->ifname_nts.data);
             break;
         case TYPE_IFONLY:
-            res = NCDIfConfig_remove_ipv4_route(o->dest, NULL, o->metric, o->ifname);
+            res = NCDIfConfig_remove_ipv4_route(o->dest, NULL, o->metric, o->ifname_nts.data);
             break;
         case TYPE_BLACKHOLE:
             res = NCDIfConfig_remove_ipv4_blackhole_route(o->dest, o->metric);
@@ -179,6 +190,9 @@ static void func_die (void *vo)
         ModuleLog(o->i, BLOG_ERROR, "failed to remove route");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 22 - 13
ncd/modules/net_ipv6_addr.c

@@ -52,7 +52,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
     struct ipv6_ifaddr ifaddr;
 };
 
@@ -71,42 +71,48 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(addr_arg) ||
-        (!NCDVal_IsInvalid(prefix_arg) && !NCDVal_IsStringNoNulls(prefix_arg))
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsString(addr_arg) ||
+        (!NCDVal_IsInvalid(prefix_arg) && !NCDVal_IsString(prefix_arg))
     ) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
-    o->ifname = NCDVal_StringValue(ifname_arg);
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     if (NCDVal_IsInvalid(prefix_arg)) {
-        if (!ipaddr6_parse_ipv6_ifaddr(NCDVal_StringValue(addr_arg), &o->ifaddr)) {
+        if (!ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringData(addr_arg), NCDVal_StringLength(addr_arg), &o->ifaddr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong CIDR notation address");
-            goto fail0;
+            goto fail1;
         }
     } else {
-        if (!ipaddr6_parse_ipv6_addr(NCDVal_StringValue(addr_arg), &o->ifaddr.addr)) {
+        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(addr_arg), NCDVal_StringLength(addr_arg), &o->ifaddr.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong address");
-            goto fail0;
+            goto fail1;
         }
         
-        if (!ipaddr6_parse_ipv6_prefix(NCDVal_StringValue(prefix_arg), &o->ifaddr.prefix)) {
+        if (!ipaddr6_parse_ipv6_prefix_bin(NCDVal_StringData(prefix_arg), NCDVal_StringLength(prefix_arg), &o->ifaddr.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong prefix");
-            goto fail0;
+            goto fail1;
         }
     }
     
     // add address
-    if (!NCDIfConfig_add_ipv6_addr(o->ifname, o->ifaddr)) {
+    if (!NCDIfConfig_add_ipv6_addr(o->ifname_nts.data, o->ifaddr)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to add IP address");
-        goto fail0;
+        goto fail1;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -117,10 +123,13 @@ static void func_die (void *vo)
     struct instance *o = vo;
     
     // remove address
-    if (!NCDIfConfig_remove_ipv6_addr(o->ifname, o->ifaddr)) {
+    if (!NCDIfConfig_remove_ipv6_addr(o->ifname_nts.data, o->ifaddr)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to remove IP address");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 4 - 4
ncd/modules/net_ipv6_addr_in_network.c

@@ -83,7 +83,7 @@ static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleI
     
     // parse addr
     struct ipv6_addr addr;
-    if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringValue(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
+    if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(arg_addr), NCDVal_StringLength(arg_addr), &addr)) {
         ModuleLog(o->i, BLOG_ERROR, "bad address");
         goto fail0;
     }
@@ -91,16 +91,16 @@ static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleI
     // parse network
     struct ipv6_ifaddr network;
     if (NCDVal_IsInvalid(arg_net_prefix)) {
-        if (!ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringValue(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network)) {
+        if (!ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network in CIDR notation");
             goto fail0;
         }
     } else {
-        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringValue(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network.addr)) {
+        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(arg_net_addr), NCDVal_StringLength(arg_net_addr), &network.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network address");
             goto fail0;
         }
-        if (!ipaddr6_parse_ipv6_prefix_bin(NCDVal_StringValue(arg_net_prefix), NCDVal_StringLength(arg_net_prefix), &network.prefix)) {
+        if (!ipaddr6_parse_ipv6_prefix_bin(NCDVal_StringData(arg_net_prefix), NCDVal_StringLength(arg_net_prefix), &network.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "bad network prefix");
             goto fail0;
         }

+ 33 - 19
ncd/modules/net_ipv6_route.c

@@ -48,8 +48,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <misc/debug.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDIfConfig.h>
+#include <ncd/value_utils.h>
 
 #include <generated/blog_channel_ncd_net_ipv6_route.h>
 
@@ -65,7 +67,7 @@ struct instance {
     int type;
     struct ipv6_addr gateway;
     int metric;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
 };
 
 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
@@ -85,9 +87,9 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(dest_arg) || !NCDVal_IsStringNoNulls(gateway_arg) ||
-        !NCDVal_IsStringNoNulls(metric_arg) || !NCDVal_IsStringNoNulls(ifname_arg) ||
-        (!NCDVal_IsInvalid(dest_prefix_arg) && !NCDVal_IsStringNoNulls(dest_prefix_arg))
+    if (!NCDVal_IsString(dest_arg) || !NCDVal_IsString(gateway_arg) ||
+        !NCDVal_IsString(metric_arg) || !NCDVal_IsStringNoNulls(ifname_arg) ||
+        (!NCDVal_IsInvalid(dest_prefix_arg) && !NCDVal_IsString(dest_prefix_arg))
     ) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
@@ -95,30 +97,29 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     
     // read dest
     if (NCDVal_IsInvalid(dest_prefix_arg)) {
-        if (!ipaddr6_parse_ipv6_ifaddr(NCDVal_StringValue(dest_arg), &o->dest)) {
+        if (!ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringData(dest_arg), NCDVal_StringLength(dest_arg), &o->dest)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong CIDR notation dest");
             goto fail0;
         }
     } else {
-        if (!ipaddr6_parse_ipv6_addr(NCDVal_StringValue(dest_arg), &o->dest.addr)) {
+        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(dest_arg), NCDVal_StringLength(dest_arg), &o->dest.addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong dest addr");
             goto fail0;
         }
-        if (!ipaddr6_parse_ipv6_prefix(NCDVal_StringValue(dest_prefix_arg), &o->dest.prefix)) {
+        if (!ipaddr6_parse_ipv6_prefix_bin(NCDVal_StringData(dest_prefix_arg), NCDVal_StringLength(dest_prefix_arg), &o->dest.prefix)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong dest prefix");
             goto fail0;
         }
     }
     
     // read gateway and choose type
-    const char *gateway_str = NCDVal_StringValue(gateway_arg);
-    if (!strcmp(gateway_str, "none")) {
+    if (NCDVal_StringEquals(gateway_arg, "none")) {
         o->type = TYPE_IFONLY;
     }
-    else if (!strcmp(gateway_str, "blackhole")) {
+    else if (NCDVal_StringEquals(gateway_arg, "blackhole")) {
         o->type = TYPE_BLACKHOLE;
     } else {
-        if (!ipaddr6_parse_ipv6_addr(gateway_str, &o->gateway)) {
+        if (!ipaddr6_parse_ipv6_addr_bin(NCDVal_StringData(gateway_arg), NCDVal_StringLength(gateway_arg), &o->gateway)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong gateway");
             goto fail0;
         }
@@ -126,19 +127,27 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     }
     
     // read metric
-    o->metric = atoi(NCDVal_StringValue(metric_arg));
+    uintmax_t metric;
+    if (!ncd_read_uintmax(metric_arg, &metric) || metric > INT_MAX) {
+        ModuleLog(i, BLOG_ERROR, "bad metric");
+        goto fail0;
+    }
+    o->metric = metric;
     
-    // read ifname
-    o->ifname = NCDVal_StringValue(ifname_arg);
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // add route
     int res = 0; // to remove warning
     switch (o->type) {
         case TYPE_NORMAL:
-            res = NCDIfConfig_add_ipv6_route(o->dest, &o->gateway, o->metric, o->ifname);
+            res = NCDIfConfig_add_ipv6_route(o->dest, &o->gateway, o->metric, o->ifname_nts.data);
             break;
         case TYPE_IFONLY:
-            res = NCDIfConfig_add_ipv6_route(o->dest, NULL, o->metric, o->ifname);
+            res = NCDIfConfig_add_ipv6_route(o->dest, NULL, o->metric, o->ifname_nts.data);
             break;
         case TYPE_BLACKHOLE:
             res = NCDIfConfig_add_ipv6_blackhole_route(o->dest, o->metric);
@@ -147,13 +156,15 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     }
     if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "failed to add route");
-        goto fail0;
+        goto fail1;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
     return;
     
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -167,10 +178,10 @@ static void func_die (void *vo)
     int res = 0; // to remove warning
     switch (o->type) {
         case TYPE_NORMAL:
-            res = NCDIfConfig_remove_ipv6_route(o->dest, &o->gateway, o->metric, o->ifname);
+            res = NCDIfConfig_remove_ipv6_route(o->dest, &o->gateway, o->metric, o->ifname_nts.data);
             break;
         case TYPE_IFONLY:
-            res = NCDIfConfig_remove_ipv6_route(o->dest, NULL, o->metric, o->ifname);
+            res = NCDIfConfig_remove_ipv6_route(o->dest, NULL, o->metric, o->ifname_nts.data);
             break;
         case TYPE_BLACKHOLE:
             res = NCDIfConfig_remove_ipv6_blackhole_route(o->dest, o->metric);
@@ -181,6 +192,9 @@ static void func_die (void *vo)
         ModuleLog(o->i, BLOG_ERROR, "failed to remove route");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 10 - 2
ncd/modules/net_ipv6_wait_dynamic_addr.c

@@ -107,11 +107,19 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *ifname = NCDVal_StringValue(ifname_arg);
+    
+    // null terminate ifname
+    NCDValNullTermString ifname_nts;
+    if (!NCDVal_StringNullTerminate(ifname_arg, &ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // get interface index
     int ifindex;
-    if (!get_iface_info(ifname, NULL, NULL, &ifindex)) {
+    int res = get_iface_info(ifname_nts.data, NULL, NULL, &ifindex);
+    NCDValNullTermString_Free(&ifname_nts);
+    if (!res) {
         ModuleLog(o->i, BLOG_ERROR, "failed to get interface index");
         goto fail0;
     }

+ 15 - 5
ncd/modules/net_up.c

@@ -46,7 +46,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    const char *ifname;
+    NCDValNullTermString ifname_nts;
 };
 
 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
@@ -64,12 +64,17 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->ifname = NCDVal_StringValue(ifname_arg);
+    
+    // null terminate ifname
+    if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // set interface up
-    if (!NCDIfConfig_set_up(o->ifname)) {
+    if (!NCDIfConfig_set_up(o->ifname_nts.data)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to set interface up");
-        goto fail0;
+        goto fail1;
     }
     
     // signal up
@@ -77,6 +82,8 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     
     return;
     
+fail1:
+    NCDValNullTermString_Free(&o->ifname_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -87,10 +94,13 @@ static void func_die (void *vo)
     struct instance *o = vo;
     
     // set interface down
-    if (!NCDIfConfig_set_down(o->ifname)) {
+    if (!NCDIfConfig_set_down(o->ifname_nts.data)) {
         ModuleLog(o->i, BLOG_ERROR, "failed to set interface down");
     }
     
+    // free ifname nts
+    NCDValNullTermString_Free(&o->ifname_nts);
+    
     NCDModuleInst_Backend_Dead(o->i);
 }
 

+ 4 - 4
ncd/modules/netmask.c

@@ -100,7 +100,7 @@ static void prefix_to_mask_func_init (void *vo, NCDModuleInst *i, const struct N
     
     // parse prefix
     int prefix;
-    if (!ipaddr_parse_ipv4_prefix_bin((char *)NCDVal_StringValue(prefix_arg), NCDVal_StringLength(prefix_arg), &prefix)) {
+    if (!ipaddr_parse_ipv4_prefix_bin((char *)NCDVal_StringData(prefix_arg), NCDVal_StringLength(prefix_arg), &prefix)) {
         ModuleLog(i, BLOG_ERROR, "bad prefix");
         goto fail0;
     }
@@ -132,14 +132,14 @@ static void ipv4_net_from_addr_and_prefix_func_init (void *vo, NCDModuleInst *i,
     
     // parse addr
     uint32_t addr;
-    if (!ipaddr_parse_ipv4_addr_bin((char *)NCDVal_StringValue(addr_arg), NCDVal_StringLength(addr_arg), &addr)) {
+    if (!ipaddr_parse_ipv4_addr_bin((char *)NCDVal_StringData(addr_arg), NCDVal_StringLength(addr_arg), &addr)) {
         ModuleLog(i, BLOG_ERROR, "bad addr");
         goto fail0;
     }
     
     // parse prefix
     int prefix;
-    if (!ipaddr_parse_ipv4_prefix_bin((char *)NCDVal_StringValue(prefix_arg), NCDVal_StringLength(prefix_arg), &prefix)) {
+    if (!ipaddr_parse_ipv4_prefix_bin((char *)NCDVal_StringData(prefix_arg), NCDVal_StringLength(prefix_arg), &prefix)) {
         ModuleLog(i, BLOG_ERROR, "bad prefix");
         goto fail0;
     }
@@ -198,7 +198,7 @@ static void mask_to_prefix_func_init (void *vo, NCDModuleInst *i, const struct N
     
     // parse mask
     uint32_t mask;
-    if (!ipaddr_parse_ipv4_addr_bin((char *)NCDVal_StringValue(mask_arg), NCDVal_StringLength(mask_arg), &mask)) {
+    if (!ipaddr_parse_ipv4_addr_bin((char *)NCDVal_StringData(mask_arg), NCDVal_StringLength(mask_arg), &mask)) {
         ModuleLog(i, BLOG_ERROR, "bad mask");
         goto fail0;
     }

+ 3 - 3
ncd/modules/parse.c

@@ -179,7 +179,7 @@ static void new_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_ne
     NCDValMem_Init(&o->mem);
     
     // parse
-    o->succeeded = pfunc(i, NCDVal_StringValue(str_arg), NCDVal_StringLength(str_arg), &o->mem, &o->value);
+    o->succeeded = pfunc(i, NCDVal_StringData(str_arg), NCDVal_StringLength(str_arg), &o->mem, &o->value);
     
     // signal up
     NCDModuleInst_Backend_Up(i);
@@ -259,7 +259,7 @@ static void ipv4_cidr_addr_func_new (void *vo, NCDModuleInst *i, const struct NC
         goto fail0;
     }
     
-    o->succeeded = ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringValue(str_arg), NCDVal_StringLength(str_arg), &o->ifaddr);
+    o->succeeded = ipaddr_parse_ipv4_ifaddr_bin(NCDVal_StringData(str_arg), NCDVal_StringLength(str_arg), &o->ifaddr);
     
     NCDModuleInst_Backend_Up(i);
     return;
@@ -323,7 +323,7 @@ static void ipv6_cidr_addr_func_new (void *vo, NCDModuleInst *i, const struct NC
         goto fail0;
     }
     
-    o->succeeded = ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringValue(str_arg), NCDVal_StringLength(str_arg), &o->ifaddr);
+    o->succeeded = ipaddr6_parse_ipv6_ifaddr_bin(NCDVal_StringData(str_arg), NCDVal_StringLength(str_arg), &o->ifaddr);
     
     NCDModuleInst_Backend_Up(i);
     return;

+ 1 - 1
ncd/modules/print.c

@@ -89,7 +89,7 @@ static void do_print (NCDModuleInst *i, NCDValRef args, int ln)
         NCDValRef arg = NCDVal_ListGet(args, j);
         ASSERT(NCDVal_IsString(arg))
         
-        const char *str = NCDVal_StringValue(arg);
+        const char *str = NCDVal_StringData(arg);
         size_t len = NCDVal_StringLength(arg);
         size_t pos = 0;
         

+ 27 - 22
ncd/modules/process_manager.c

@@ -51,6 +51,7 @@
 
 #include <misc/offset.h>
 #include <misc/debug.h>
+#include <misc/strdup.h>
 #include <structure/LinkedList1.h>
 #include <ncd/NCDModule.h>
 #include <ncd/value_utils.h>
@@ -75,6 +76,7 @@ struct instance {
 struct process {
     struct instance *manager;
     char *name;
+    size_t name_len;
     BTimer retry_timer;
     LinkedList1Node processes_list_node;
     int have_params;
@@ -88,8 +90,8 @@ struct process {
     int state;
 };
 
-static struct process * find_process (struct instance *o, const char *name);
-static int process_new (struct instance *o, const char *name, NCDValRef template_name, NCDValRef args);
+static struct process * find_process (struct instance *o, const char *name, size_t name_len);
+static int process_new (struct instance *o, const char *name, size_t name_len, NCDValRef template_name, NCDValRef args);
 static void process_free (struct process *p);
 static void process_retry_timer_handler (struct process *p);
 static void process_module_process_handler_event (NCDModuleProcess *process, int event);
@@ -107,12 +109,12 @@ static struct NCD_string_request strings[] = {
     {"_caller"}, {NULL}
 };
 
-struct process * find_process (struct instance *o, const char *name)
+struct process * find_process (struct instance *o, const char *name, size_t name_len)
 {
     LinkedList1Node *n = LinkedList1_GetFirst(&o->processes_list);
     while (n) {
         struct process *p = UPPER_OBJECT(n, struct process, processes_list_node);
-        if (!strcmp(p->name, name)) {
+        if (p->name_len == name_len && !memcmp(p->name, name, name_len)) {
             return p;
         }
         n = LinkedList1Node_Next(n);
@@ -121,10 +123,10 @@ struct process * find_process (struct instance *o, const char *name)
     return NULL;
 }
 
-int process_new (struct instance *o, const char *name, NCDValRef template_name, NCDValRef args)
+int process_new (struct instance *o, const char *name, size_t name_len, NCDValRef template_name, NCDValRef args)
 {
     ASSERT(!o->dying)
-    ASSERT(!find_process(o, name))
+    ASSERT(!find_process(o, name, name_len))
     ASSERT(NCDVal_IsString(template_name))
     ASSERT(NCDVal_IsList(args))
     
@@ -139,10 +141,11 @@ int process_new (struct instance *o, const char *name, NCDValRef template_name,
     p->manager = o;
     
     // copy name
-    if (!(p->name = strdup(name))) {
-        ModuleLog(o->i, BLOG_ERROR, "strdup failed");
+    if (!(p->name = b_strdup_bin(name, name_len))) {
+        ModuleLog(o->i, BLOG_ERROR, "b_strdup_bin failed");
         goto fail1;
     }
+    p->name_len = name_len;
     
     // init retry timer
     BTimer_Init(&p->retry_timer, RETRY_TIME, (BTimer_handler)process_retry_timer_handler, p);
@@ -371,7 +374,7 @@ void process_try (struct process *p)
     ASSERT(p->have_params)
     ASSERT(!p->have_module_process)
     
-    ModuleLog(o->i, BLOG_INFO, "trying process %s", p->name);
+    ModuleLog(o->i, BLOG_INFO, "trying process");
     
     // move params
     p->process_mem = p->params_mem;
@@ -492,12 +495,13 @@ static void start_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg) || !NCDVal_IsString(template_name_arg) ||
+    if (!NCDVal_IsString(name_arg) || !NCDVal_IsString(template_name_arg) ||
         !NCDVal_IsList(args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *name = NCDVal_StringValue(name_arg);
+    const char *name = NCDVal_StringData(name_arg);
+    size_t name_len = NCDVal_StringLength(name_arg);
     
     // signal up.
     // Do it before creating the process so that the process starts initializing before our own process continues.
@@ -507,20 +511,20 @@ static void start_func_new (void *unused, NCDModuleInst *i, const struct NCDModu
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
     
     if (mo->dying) {
-        ModuleLog(i, BLOG_INFO, "manager is dying, not creating process %s", name);
+        ModuleLog(i, BLOG_INFO, "manager is dying, not creating process");
     } else {
-        struct process *p = find_process(mo, name);
+        struct process *p = find_process(mo, name, name_len);
         if (p && p->state != PROCESS_STATE_STOPPING) {
-            ModuleLog(i, BLOG_INFO, "process %s already started", name);
+            ModuleLog(i, BLOG_INFO, "process already started");
         } else {
             if (p) {
                 if (!process_restart(p, template_name_arg, args_arg)) {
-                    ModuleLog(i, BLOG_ERROR, "failed to restart process %s", name);
+                    ModuleLog(i, BLOG_ERROR, "failed to restart process");
                     goto fail0;
                 }
             } else {
-                if (!process_new(mo, name, template_name_arg, args_arg)) {
-                    ModuleLog(i, BLOG_ERROR, "failed to create process %s", name);
+                if (!process_new(mo, name, name_len, template_name_arg, args_arg)) {
+                    ModuleLog(i, BLOG_ERROR, "failed to create process");
                     goto fail0;
                 }
             }
@@ -542,11 +546,12 @@ static void stop_func_new (void *unused, NCDModuleInst *i, const struct NCDModul
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsString(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *name = NCDVal_StringValue(name_arg);
+    const char *name = NCDVal_StringData(name_arg);
+    size_t name_len = NCDVal_StringLength(name_arg);
     
     // signal up.
     // Do it before stopping the process so that the process starts terminating before our own process continues.
@@ -556,11 +561,11 @@ static void stop_func_new (void *unused, NCDModuleInst *i, const struct NCDModul
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
     
     if (mo->dying) {
-        ModuleLog(i, BLOG_INFO, "manager is dying, not stopping process %s", name);
+        ModuleLog(i, BLOG_INFO, "manager is dying, not stopping process");
     } else {
-        struct process *p = find_process(mo, name);
+        struct process *p = find_process(mo, name, name_len);
         if (!(p && p->state != PROCESS_STATE_STOPPING)) {
-            ModuleLog(i, BLOG_INFO, "process %s already stopped", name);
+            ModuleLog(i, BLOG_INFO, "process already stopped");
         } else {
             process_stop(p);
         }

+ 22 - 7
ncd/modules/regex_match.c

@@ -113,9 +113,8 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->input = NCDVal_StringValue(input_arg);
+    o->input = NCDVal_StringData(input_arg);
     o->input_len = NCDVal_StringLength(input_arg);
-    const char *regex = NCDVal_StringValue(regex_arg);
     
     // make sure we don't overflow regoff_t
     if (o->input_len > INT_MAX) {
@@ -123,10 +122,18 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         goto fail0;
     }
     
+    // null terminate regex
+    NCDValNullTermString regex_nts;
+    if (!NCDVal_StringNullTerminate(regex_arg, &regex_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // compile regex
     regex_t preg;
-    int ret;
-    if ((ret = regcomp(&preg, regex, REG_EXTENDED)) != 0) {
+    int ret = regcomp(&preg, regex_nts.data, REG_EXTENDED);
+    NCDValNullTermString_Free(&regex_nts);
+    if (ret != 0) {
         ModuleLog(o->i, BLOG_ERROR, "regcomp failed (error=%d)", ret);
         goto fail0;
     }
@@ -227,7 +234,15 @@ static void replace_func_new (void *vo, NCDModuleInst *i, const struct NCDModule
             goto fail2;
         }
         
-        int res = regcomp(&regs[num_done_regex], NCDVal_StringValue(regex), REG_EXTENDED);
+        // null terminate regex
+        NCDValNullTermString regex_nts;
+        if (!NCDVal_StringNullTerminate(regex, &regex_nts)) {
+            ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+            goto fail2;
+        }
+        
+        int res = regcomp(&regs[num_done_regex], regex_nts.data, REG_EXTENDED);
+        NCDValNullTermString_Free(&regex_nts);
         if (res != 0) {
             ModuleLog(i, BLOG_ERROR, "regcomp failed for pair %zu (error=%d)", num_done_regex, res);
             goto fail2;
@@ -244,7 +259,7 @@ static void replace_func_new (void *vo, NCDModuleInst *i, const struct NCDModule
     }
     
     // input state
-    const char *in = NCDVal_StringValue(input_arg);
+    const char *in = NCDVal_StringData(input_arg);
     size_t in_pos = 0;
     size_t in_len = NCDVal_StringLength(input_arg);
     
@@ -282,7 +297,7 @@ static void replace_func_new (void *vo, NCDModuleInst *i, const struct NCDModule
         
         // append replacement data
         NCDValRef replace = NCDVal_ListGet(replace_arg, match_regex);
-        if (!ExpString_AppendBinary(&out, (const uint8_t *)NCDVal_StringValue(replace), NCDVal_StringLength(replace))) {
+        if (!ExpString_AppendBinary(&out, (const uint8_t *)NCDVal_StringData(replace), NCDVal_StringLength(replace))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
             goto fail3;
         }

+ 6 - 4
ncd/modules/run.c

@@ -43,6 +43,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <misc/strdup.h>
+#include <ncd/value_utils.h>
 #include <ncd/modules/command_template.h>
 
 #include <generated/blog_channel_ncd_run.h>
@@ -86,8 +88,8 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **e
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
-        ModuleLog(i, BLOG_ERROR, "strdup failed");
+    if (!(*exec = ncd_strdup(exec_arg))) {
+        ModuleLog(i, BLOG_ERROR, "ncd_strdup failed");
         goto fail0;
     }
     
@@ -112,8 +114,8 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef args, int remove, char **e
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+        if (!CmdLine_AppendNoNull(cl, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }

+ 10 - 9
ncd/modules/runonce.c

@@ -53,8 +53,10 @@
 #include <string.h>
 
 #include <misc/cmdline.h>
+#include <misc/strdup.h>
 #include <system/BProcess.h>
 #include <ncd/NCDModule.h>
+#include <ncd/value_utils.h>
 
 #include <generated/blog_channel_ncd_runonce.h>
 
@@ -95,7 +97,7 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
+    if (!(*exec = ncd_strdup(exec_arg))) {
         ModuleLog(i, BLOG_ERROR, "strdup failed");
         goto fail0;
     }
@@ -121,8 +123,8 @@ static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdL
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
-            ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+        if (!CmdLine_AppendNoNull(cl, NCDVal_StringData(arg), NCDVal_StringLength(arg))) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_AppendNoNull failed");
             goto fail2;
         }
     }
@@ -196,22 +198,21 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         NCDValRef opt = NCDVal_ListGet(opts_arg, j);
         
         // read name
-        if (!NCDVal_IsStringNoNulls(opt)) {
+        if (!NCDVal_IsString(opt)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
             goto fail0;
         }
-        const char *optname = NCDVal_StringValue(opt);
         
-        if (!strcmp(optname, "term_on_deinit")) {
+        if (NCDVal_StringEquals(opt, "term_on_deinit")) {
             o->term_on_deinit = 1;
         }
-        else if (!strcmp(optname, "keep_stdout")) {
+        else if (NCDVal_StringEquals(opt, "keep_stdout")) {
             keep_stdout = 1;
         }
-        else if (!strcmp(optname, "keep_stderr")) {
+        else if (NCDVal_StringEquals(opt, "keep_stderr")) {
             keep_stderr = 1;
         }
-        else if (!strcmp(optname, "do_setsid")) {
+        else if (NCDVal_StringEquals(opt, "do_setsid")) {
             do_setsid = 1;
         }
         else {

+ 1 - 1
ncd/modules/socket.c

@@ -763,7 +763,7 @@ static void write_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleIn
     }
     
     // set send state
-    o->data = NCDVal_StringValue(data_arg);
+    o->data = NCDVal_StringData(data_arg);
     o->length = NCDVal_StringLength(data_arg);
     
     // if there's nothing to send, go up immediately

+ 10 - 1
ncd/modules/sys_evdev.c

@@ -164,8 +164,17 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         goto fail0;
     }
     
+    // null terminate device
+    NCDValNullTermString device_nts;
+    if (!NCDVal_StringNullTerminate(device_arg, &device_nts)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
+    
     // open device
-    if ((o->evdev_fd = open(NCDVal_StringValue(device_arg), O_RDONLY)) < 0) {
+    o->evdev_fd = open(device_nts.data, O_RDONLY);
+    NCDValNullTermString_Free(&device_nts);
+    if (o->evdev_fd < 0) {
         ModuleLog(o->i, BLOG_ERROR, "open failed");
         goto fail0;
     }

+ 22 - 12
ncd/modules/sys_watch_directory.c

@@ -64,7 +64,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    const char *dir;
+    NCDValNullTermString dir_nts;
     DIR *dir_handle;
     int inotify_fd;
     BFileDescriptor bfd;
@@ -250,37 +250,42 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->dir = NCDVal_StringValue(dir_arg);
+    
+    // null terminate dir
+    if (!NCDVal_StringNullTerminate(dir_arg, &o->dir_nts)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
+        goto fail0;
+    }
     
     // open inotify
     if ((o->inotify_fd = inotify_init()) < 0) {
         ModuleLog(o->i, BLOG_ERROR, "inotify_init failed");
-        goto fail0;
+        goto fail1;
     }
     
     // add watch
-    if (inotify_add_watch(o->inotify_fd, o->dir, IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO) < 0) {
+    if (inotify_add_watch(o->inotify_fd, o->dir_nts.data, IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO) < 0) {
         ModuleLog(o->i, BLOG_ERROR, "inotify_add_watch failed");
-        goto fail1;
+        goto fail2;
     }
     
     // set non-blocking
     if (!badvpn_set_nonblocking(o->inotify_fd)) {
         ModuleLog(o->i, BLOG_ERROR, "badvpn_set_nonblocking failed");
-        goto fail1;
+        goto fail2;
     }
     
     // init BFileDescriptor
     BFileDescriptor_Init(&o->bfd, o->inotify_fd, (BFileDescriptor_handler)inotify_fd_handler, o);
     if (!BReactor_AddFileDescriptor(o->i->params->iparams->reactor, &o->bfd)) {
         ModuleLog(o->i, BLOG_ERROR, "BReactor_AddFileDescriptor failed");
-        goto fail1;
+        goto fail2;
     }
     
     // open directory
-    if (!(o->dir_handle = opendir(o->dir))) {
+    if (!(o->dir_handle = opendir(o->dir_nts.data))) {
         ModuleLog(o->i, BLOG_ERROR, "opendir failed");
-        goto fail2;
+        goto fail3;
     }
     
     // set not processing
@@ -290,12 +295,14 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
     next_dir_event(o);
     return;
     
-fail2:
+fail3:
     BReactor_RemoveFileDescriptor(o->i->params->iparams->reactor, &o->bfd);
-fail1:
+fail2:
     if (close(o->inotify_fd) < 0) {
         ModuleLog(o->i, BLOG_ERROR, "close failed");
     }
+fail1:
+    NCDValNullTermString_Free(&o->dir_nts);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
@@ -318,6 +325,9 @@ void instance_free (struct instance *o, int is_error)
         ModuleLog(o->i, BLOG_ERROR, "close failed");
     }
     
+    // free dir nts
+    NCDValNullTermString_Free(&o->dir_nts);
+    
     if (is_error) {
         NCDModuleInst_Backend_SetError(o->i);
     }
@@ -352,7 +362,7 @@ static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *o
     }
     
     if (!strcmp(name, "filepath")) {
-        char *str = concat_strings(3, o->dir, "/", o->processing_file);
+        char *str = concat_strings(3, o->dir_nts.data, "/", o->processing_file);
         if (!str) {
             ModuleLog(o->i, BLOG_ERROR, "concat_strings failed");
             goto fail;

+ 7 - 5
ncd/modules/sys_watch_input.c

@@ -71,6 +71,7 @@ struct device {
 struct instance {
     NCDModuleInst *i;
     const char *devnode_type;
+    size_t devnode_type_len;
     NCDUdevClient client;
     LinkedList1 devices_list;
     event_template templ;
@@ -158,7 +159,7 @@ fail1:
     return 0;
 }
 
-static int devname_is_type (const char *devname, const char *devname_type)
+static int devname_is_type (const char *devname, const char *devname_type, size_t devname_type_len)
 {
     // skip digits at the end
     size_t i;
@@ -169,7 +170,7 @@ static int devname_is_type (const char *devname, const char *devname_type)
     }
     
     // check if devname_type precedes skipped digits
-    for (size_t j = strlen(devname_type); j > 0; j--) {
+    for (size_t j = devname_type_len; j > 0; j--) {
         if (!(i > 0 && devname[i - 1] == devname_type[j - 1])) {
             return 0;
         }
@@ -290,7 +291,7 @@ static void client_handler (struct instance *o, char *devpath, int have_map, BSt
     const char *subsystem = BStringMap_Get(cache_map, "SUBSYSTEM");
     const char *devname = BStringMap_Get(cache_map, "DEVNAME");
     
-    if (!(subsystem && !strcmp(subsystem, "input") && devname && devname_is_type(devname, o->devnode_type))) {
+    if (!(subsystem && !strcmp(subsystem, "input") && devname && devname_is_type(devname, o->devnode_type, o->devnode_type_len))) {
         if (ex_device) {
             remove_device(o, ex_device);
         }
@@ -353,11 +354,12 @@ static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDVal_IsStringNoNulls(devnode_type_arg)) {
+    if (!NCDVal_IsString(devnode_type_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    o->devnode_type = NCDVal_StringValue(devnode_type_arg);
+    o->devnode_type = NCDVal_StringData(devnode_type_arg);
+    o->devnode_type_len = NCDVal_StringLength(devnode_type_arg);
     
     // init client
     NCDUdevClient_Init(&o->client, o->i->params->iparams->umanager, o, (NCDUdevClient_handler)client_handler);

+ 3 - 3
ncd/modules/value.c

@@ -589,7 +589,7 @@ static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValRef value)
             if (NCDVal_IsIdString(value)) {
                 v = value_init_idstring(i, NCDVal_IdStringId(value), NCDVal_IdStringStringIndex(value));
             } else {
-                v = value_init_string(i, NCDVal_StringValue(value), NCDVal_StringLength(value));
+                v = value_init_string(i, NCDVal_StringData(value), NCDVal_StringLength(value));
             }
             if (!v) {
                 goto fail0;
@@ -980,7 +980,7 @@ static int value_append (NCDModuleInst *i, struct value *v, NCDValRef data)
                 return 0;
             }
             
-            const char *append_string = NCDVal_StringValue(data);
+            const char *append_string = NCDVal_StringData(data);
             size_t append_length = NCDVal_StringLength(data);
             
             if (append_length > SIZE_MAX - v->string.length) {
@@ -1007,7 +1007,7 @@ static int value_append (NCDModuleInst *i, struct value *v, NCDValRef data)
                 return 0;
             }
             
-            const char *append_string = NCDVal_StringValue(data);
+            const char *append_string = NCDVal_StringData(data);
             size_t append_length = NCDVal_StringLength(data);
             
             const char *string = NCDStringIndex_Value(v->idstring.string_index, v->idstring.id);

+ 12 - 3
ncd/value_utils.h

@@ -35,6 +35,7 @@
 
 #include <misc/debug.h>
 #include <misc/parse_number.h>
+#include <misc/strdup.h>
 #include <system/BTime.h>
 #include <ncd/NCDVal.h>
 #include <ncd/NCDStringIndex.h>
@@ -47,6 +48,7 @@ static int ncd_read_uintmax (NCDValRef string, uintmax_t *out) WARN_UNUSED;
 static int ncd_read_time (NCDValRef string, btime_t *out) WARN_UNUSED;
 static NCD_string_id_t ncd_get_string_id (NCDValRef string, NCDStringIndex *string_index);
 static NCDValRef ncd_make_uintmax (NCDValMem *mem, uintmax_t value);
+static char * ncd_strdup (NCDValRef stringnonulls);
 
 static int ncd_is_none (NCDValRef string)
 {
@@ -84,7 +86,7 @@ static int ncd_read_uintmax (NCDValRef string, uintmax_t *out)
     ASSERT(NCDVal_IsString(string))
     ASSERT(out)
     
-    return parse_unsigned_integer_bin(NCDVal_StringValue(string), NCDVal_StringLength(string), out);
+    return parse_unsigned_integer_bin(NCDVal_StringData(string), NCDVal_StringLength(string), out);
 }
 
 static int ncd_read_time (NCDValRef string, btime_t *out)
@@ -113,7 +115,7 @@ static NCD_string_id_t ncd_get_string_id (NCDValRef string, NCDStringIndex *stri
     if (NCDVal_IsIdString(string)) {
         return NCDVal_IdStringId(string);
     } else {
-        return NCDStringIndex_GetBin(string_index, NCDVal_StringValue(string), NCDVal_StringLength(string));
+        return NCDStringIndex_GetBin(string_index, NCDVal_StringData(string), NCDVal_StringLength(string));
     }
 }
 
@@ -126,11 +128,18 @@ static NCDValRef ncd_make_uintmax (NCDValMem *mem, uintmax_t value)
     NCDValRef val = NCDVal_NewStringUninitialized(mem, size);
     
     if (!NCDVal_IsInvalid(val)) {
-        char *data = (char *)NCDVal_StringValue(val);
+        char *data = (char *)NCDVal_StringData(val);
         generate_decimal_repr(value, data, size);
     }
     
     return val;
 }
 
+static char * ncd_strdup (NCDValRef stringnonulls)
+{
+    ASSERT(NCDVal_IsStringNoNulls(stringnonulls))
+    
+    return b_strdup_bin(NCDVal_StringData(stringnonulls), NCDVal_StringLength(stringnonulls));
+}
+
 #endif