]> git.kaiwu.me - njs.git/commitdiff
Ensuring string values are zero-terminated.
authorDmitry Volyntsev <xeioex@nginx.com>
Sat, 15 Nov 2025 02:22:56 +0000 (18:22 -0800)
committerDmitry Volyntsev <xeioexception@gmail.com>
Tue, 18 Nov 2025 02:56:11 +0000 (18:56 -0800)
This helps when some code requires a string value to be zero-terminated
to avoid copying and adding \0 byte.

It adds small overhead (less than 3% in worst case of an empty string
value) to existing sizeof(njs_value_t) + sizeof(njs_string_t) = 32.

src/njs_scope.c
src/njs_string.c
src/njs_string.h
src/njs_value.h
src/njs_vm.c
src/test/njs_unit_test.c

index cd1176a299f71f5f37be061e44d55a3cfd4cfb9a..9d7b5776d2e31c1cfe76044959806c52a6c9f3c2 100644 (file)
@@ -199,7 +199,7 @@ njs_scope_value_index(njs_vm_t *vm, const njs_value_t *src, njs_uint_t runtime,
                        + njs_string_map_size(length);
             }
 
-            value_size += sizeof(njs_string_t) + size;
+            value_size += sizeof(njs_string_t) + size + 1;
         }
 
         value_size += sizeof(njs_index_t);
@@ -221,6 +221,8 @@ njs_scope_value_index(njs_vm_t *vm, const njs_value_t *src, njs_uint_t runtime,
             string->length = src->string.data->length;
             string->size = src->string.data->size;
 
+            string->start[size] = '\0';
+
             memcpy(string->start, start, size);
         }
 
index 1a2b23338b31906578f8582a4506638bd8f6a066..ae68088949e0db96b6e01113fd6c9e67f84f7d34 100644 (file)
@@ -147,6 +147,7 @@ njs_string_new(njs_vm_t *vm, njs_value_t *value, const u_char *start,
 }
 
 
+/* Underlying string data is zero-terminated. */
 u_char *
 njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint64_t size,
     uint64_t length)
@@ -164,12 +165,12 @@ njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint64_t size,
     value->atom_id = NJS_ATOM_STRING_unknown;
 
     if (size != length && length > NJS_STRING_MAP_STRIDE) {
-        map_offset = njs_string_map_offset(size);
+        map_offset = njs_string_map_offset(size + njs_length("\0"));
         total = map_offset + njs_string_map_size(length);
 
     } else {
         map_offset = 0;
-        total = size;
+        total = size + njs_length("\0");
     }
 
     string = njs_mp_alloc(vm->mem_pool, sizeof(njs_string_t) + total);
@@ -181,6 +182,8 @@ njs_string_alloc(njs_vm_t *vm, njs_value_t *value, uint64_t size,
         string->size = size;
         string->length = length;
 
+        string->start[size] = '\0';
+
         if (map_offset != 0) {
             map = (uint32_t *) (string->start + map_offset);
             map[0] = 0;
index 225721ed4cab8db70e0389fbb6cd552f0f804372..2a676ee0c4b1e2f8c3d5ad7a12a04f499f45d6b7 100644 (file)
@@ -37,7 +37,7 @@
 #define njs_string_map_offset(size)  njs_align_size((size), sizeof(uint32_t))
 
 #define njs_string_map_start(p)                                               \
-    ((uint32_t *) njs_align_ptr((p), sizeof(uint32_t)))
+    ((uint32_t *) njs_align_ptr((u_char *) (p) + 1, sizeof(uint32_t)))
 
 #define njs_string_map_size(length)                                           \
     (((length - 1) / NJS_STRING_MAP_STRIDE) * sizeof(uint32_t))
index 61a46c0a81568eb0d74946c091d571ee976f0b4b..1422f02ccb3dbbc0512b3b01b9da976fb2eee738 100644 (file)
@@ -517,6 +517,7 @@ typedef struct {
         njs_assert((value)->string.data != NULL);                             \
         (str)->length = (value)->string.data->size;                           \
         (str)->start = (u_char *) (value)->string.data->start;                \
+        njs_assert((str)->start[(str)->length] == '\0');                      \
     } while (0)
 
 
index fe4e3a317622506a7bc857395d733fe9f0735277..348316a14f1d2791bd8d823ebee31b5c56a726be 100644 (file)
@@ -1520,31 +1520,12 @@ njs_vm_value_to_string(njs_vm_t *vm, njs_str_t *dst, njs_value_t *src)
 }
 
 
-/*
- * If string value is null-terminated the corresponding C string
- * is returned as is, otherwise the new copy is allocated with
- * the terminating zero byte.
- */
 const char *
 njs_vm_value_to_c_string(njs_vm_t *vm, njs_value_t *value)
 {
-    u_char  *p, *data;
-    size_t  size;
-
     njs_assert(njs_is_string(value));
 
-    size = value->string.data->size;
-
-    data = njs_mp_alloc(vm->mem_pool, size + njs_length("\0"));
-    if (njs_slow_path(data == NULL)) {
-        njs_memory_error(vm);
-        return NULL;
-    }
-
-    p = njs_cpymem(data, value->string.data->start, size);
-    *p++ = '\0';
-
-    return (const char *) data;
+    return (const char *) value->string.data->start;
 }
 
 
index 0c5e55cc0ffd779e17f441f8143a3e838c658206..5b6d556b4d59beccdd7bf1b141d10ba54cd5f428 100644 (file)
@@ -7825,6 +7825,9 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'\\ud83d\\udc4d'.length"),
       njs_str("1") },
 
+    { njs_str("'\\u00A0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.length"),
+      njs_str("35") },
+
     { njs_str("'\\ud83d abc \\udc4d'"),
       njs_str("� abc �") },