Commit b06aedb8badc0ed99bad01f11015dd3ac85e50bb

Peter Hutterer 2023-05-02T14:15:55

scanner: allow for a zero terminated string as keymap As the documentation for xkb_keymap_new_from_buffer() states, the "input string does not have to be zero-terminated". The actual implementation however failed with "unrecognized token/syntax error" when it encountered a null byte. Fix this by allowing a null byte at the last position of the buffer. Anything else is likely a client error anyway. Fixes #307

diff --git a/src/keymap.c b/src/keymap.c
index d2baf94..0291aed 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -194,6 +194,10 @@ xkb_keymap_new_from_buffer(struct xkb_context *ctx,
     if (!keymap)
         return NULL;
 
+    /* Allow a zero-terminated string as a buffer */
+    if (length > 0 && buffer[length - 1] == '\0')
+        length--;
+
     if (!ops->keymap_new_from_string(keymap, buffer, length)) {
         xkb_keymap_unref(keymap);
         return NULL;
diff --git a/test/buffercomp.c b/test/buffercomp.c
index 12b67fe..9a76036 100644
--- a/test/buffercomp.c
+++ b/test/buffercomp.c
@@ -46,29 +46,33 @@ main(int argc, char *argv[])
     original = test_read_file(DATA_PATH);
     assert(original);
 
-    keymap = test_compile_buffer(ctx, original, strlen(original));
-    assert(keymap);
+    /* Load a prebuild keymap, once without, once with the trailing \0 */
+    for (int i = 0; i <= 1; i++) {
+        keymap = test_compile_buffer(ctx, original, strlen(original) + i);
+        assert(keymap);
 
-    dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
-    assert(dump);
+        dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
+        assert(dump);
 
-    if (!streq(original, dump)) {
-        fprintf(stderr,
-                "round-trip test failed: dumped map differs from original\n");
-        fprintf(stderr, "path to original file: %s\n",
-                test_get_path(DATA_PATH));
-        fprintf(stderr, "length: dumped %lu, original %lu\n",
-                (unsigned long) strlen(dump),
-                (unsigned long) strlen(original));
-        fprintf(stderr, "dumped map:\n");
-        fprintf(stderr, "%s\n", dump);
-        fflush(stderr);
-        assert(0);
+        if (!streq(original, dump)) {
+            fprintf(stderr,
+                    "round-trip test failed: dumped map differs from original\n");
+            fprintf(stderr, "path to original file: %s\n",
+                    test_get_path(DATA_PATH));
+            fprintf(stderr, "length: dumped %lu, original %lu\n",
+                    (unsigned long) strlen(dump),
+                    (unsigned long) strlen(original));
+            fprintf(stderr, "dumped map:\n");
+            fprintf(stderr, "%s\n", dump);
+            fflush(stderr);
+            assert(0);
+        }
+
+        free(dump);
+        xkb_keymap_unref(keymap);
     }
 
     free(original);
-    free(dump);
-    xkb_keymap_unref(keymap);
 
     /* Make sure we can't (falsely claim to) compile an empty string. */
     keymap = test_compile_buffer(ctx, "", 0);