aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Hansen2022-06-12 01:19:43 -0400
committerEli Zaretskii2022-06-12 09:59:13 +0300
commitc1829b307cffce046bec6fcbdff03dbab9f4b562 (patch)
tree0814466d82fb9bf840ba719a060f2026931fa643
parentc2695621fc52aa5eeebc45b82b9b916e30568589 (diff)
downloademacs-c1829b307cffce046bec6fcbdff03dbab9f4b562.tar.gz
emacs-c1829b307cffce046bec6fcbdff03dbab9f4b562.zip
bindat (str, strz): Reject non-ASCII, non-`eight-bit' characters
* lisp/emacs-lisp/bindat.el (str) (strz): Signal an error if the user attempts to pack a multibyte string containing characters other than ASCII and `eight-bit' characters (bug#55897). * doc/lispref/processes.texi (Bindat Types): Update documentation. * test/lisp/emacs-lisp/bindat-tests.el (str) (strz): Add tests.
-rw-r--r--doc/lispref/processes.texi14
-rw-r--r--lisp/emacs-lisp/bindat.el10
-rw-r--r--test/lisp/emacs-lisp/bindat-tests.el16
3 files changed, 32 insertions, 8 deletions
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index aa4d0e3ee4f..8c8f8fd6b2a 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -3486,8 +3486,11 @@ When packing, the first @var{len} bytes of the input string are copied
3486to the packed output. If the input string is shorter than @var{len}, 3486to the packed output. If the input string is shorter than @var{len},
3487the remaining bytes will be null (zero) unless a pre-allocated string 3487the remaining bytes will be null (zero) unless a pre-allocated string
3488was provided to @code{bindat-pack}, in which case the remaining bytes 3488was provided to @code{bindat-pack}, in which case the remaining bytes
3489are left unmodified. When unpacking, any null bytes in the packed 3489are left unmodified. If the input string is multibyte with only ASCII
3490input string will appear in the unpacked output. 3490and @code{eight-bit} characters, it is converted to unibyte before it
3491is packed; other multibyte strings signal an error. When unpacking,
3492any null bytes in the packed input string will appear in the unpacked
3493output.
3491 3494
3492@item strz &optional @var{len} 3495@item strz &optional @var{len}
3493If @var{len} is not provided: Variable-length null-terminated unibyte 3496If @var{len} is not provided: Variable-length null-terminated unibyte
@@ -3497,8 +3500,11 @@ null (zero) unless a pre-allocated string was provided to
3497@code{bindat-pack}, in which case that byte is left unmodified. The 3500@code{bindat-pack}, in which case that byte is left unmodified. The
3498length of the packed output is the length of the input string plus one 3501length of the packed output is the length of the input string plus one
3499(for the null terminator). The input string must not contain any null 3502(for the null terminator). The input string must not contain any null
3500bytes. When unpacking, the resulting string contains all bytes up to 3503bytes. If the input string is multibyte with only ASCII and
3501(but excluding) the null byte. 3504@code{eight-bit} characters, it is converted to unibyte before it is
3505packed; other multibyte strings signal an error. When unpacking, the
3506resulting string contains all bytes up to (but excluding) the null
3507byte.
3502 3508
3503@quotation Caution 3509@quotation Caution
3504If a pre-allocated string is provided to @code{bindat-pack}, the 3510If a pre-allocated string is provided to @code{bindat-pack}, the
diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el
index 84d5ea1e3b3..2d6589b52de 100644
--- a/lisp/emacs-lisp/bindat.el
+++ b/lisp/emacs-lisp/bindat.el
@@ -435,12 +435,14 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
435 (bindat--pack-u32r (ash v -32))) 435 (bindat--pack-u32r (ash v -32)))
436 436
437(defun bindat--pack-str (len v) 437(defun bindat--pack-str (len v)
438 (dotimes (i (min len (length v))) 438 (let ((v (string-to-unibyte v)))
439 (aset bindat-raw (+ bindat-idx i) (aref v i))) 439 (dotimes (i (min len (length v)))
440 (setq bindat-idx (+ bindat-idx len))) 440 (aset bindat-raw (+ bindat-idx i) (aref v i)))
441 (setq bindat-idx (+ bindat-idx len))))
441 442
442(defun bindat--pack-strz (v) 443(defun bindat--pack-strz (v)
443 (let ((len (length v))) 444 (let* ((v (string-to-unibyte v))
445 (len (length v)))
444 (dotimes (i len) 446 (dotimes (i len)
445 (aset bindat-raw (+ bindat-idx i) (aref v i))) 447 (aset bindat-raw (+ bindat-idx i) (aref v i)))
446 (setq bindat-idx (+ bindat-idx len 1)))) 448 (setq bindat-idx (+ bindat-idx len 1))))
diff --git a/test/lisp/emacs-lisp/bindat-tests.el b/test/lisp/emacs-lisp/bindat-tests.el
index 1ce402977f5..8bb3baa485e 100644
--- a/test/lisp/emacs-lisp/bindat-tests.el
+++ b/test/lisp/emacs-lisp/bindat-tests.el
@@ -188,6 +188,22 @@
188 (apply #'bindat-pack (append (car tc) (list prealloc))) 188 (apply #'bindat-pack (append (car tc) (list prealloc)))
189 (should (equal prealloc (cdr tc)))))) 189 (should (equal prealloc (cdr tc))))))
190 190
191(ert-deftest bindat-test--str-strz-multibyte ()
192 (dolist (spec (list (bindat-type str 2)
193 (bindat-type strz 2)
194 (bindat-type strz)))
195 (should (equal (bindat-pack spec (string-to-multibyte "x")) "x\0"))
196 (should (equal (bindat-pack spec (string-to-multibyte "\xff")) "\xff\0"))
197 (should-error (bindat-pack spec "💩"))
198 (should-error (bindat-pack spec "\N{U+ff}")))
199 (dolist (spec (list '((x str 2)) '((x strz 2))))
200 (should (equal (bindat-pack spec `((x . ,(string-to-multibyte "x"))))
201 "x\0"))
202 (should (equal (bindat-pack spec `((x . ,(string-to-multibyte "\xff"))))
203 "\xff\0"))
204 (should-error (bindat-pack spec '((x . "💩"))))
205 (should-error (bindat-pack spec '((x . "\N{U+ff}"))))))
206
191(let ((spec (bindat-type strz 2))) 207(let ((spec (bindat-type strz 2)))
192 (ert-deftest bindat-test--strz-fixedlen-len () 208 (ert-deftest bindat-test--strz-fixedlen-len ()
193 (should (equal (bindat-length spec "") 2)) 209 (should (equal (bindat-length spec "") 2))