bindat (strz): Null terminate fixed-length strings if there is room

* lisp/emacs-lisp/bindat.el (bindat--pack-strz): For fixed-length strz
fields, explicitly write a null terminator after the packed string if
there is room (bug#56048).
* doc/lispref/processes.texi (Bindat Types): Update documentation.
* test/lisp/emacs-lisp/bindat-tests.el (bindat-test--str-strz-prealloc):
Update tests.
This commit is contained in:
Richard Hansen 2022-06-16 15:21:57 -04:00 committed by Eli Zaretskii
parent eff42dc0af
commit 55c2102560
3 changed files with 28 additions and 28 deletions

View file

@ -3509,23 +3509,24 @@ packed; other multibyte strings signal an error. When unpacking a
(but excluding) the null byte that terminated the input string.
If @var{len} is provided, @code{strz} behaves the same as @code{str},
but with one difference: when unpacking, the first null byte
encountered in the packed string is interpreted as the terminating
byte, and it and all subsequent bytes are excluded from the result of
the unpacking.
but with a couple of differences:
@itemize @bullet
@item
When packing, a null terminator is written after the packed input
string if the number of characters in the input string is less than
@var{len}.
@item
When unpacking, the first null byte encountered in the packed string
is interpreted as the terminating byte, and it and all subsequent
bytes are excluded from the result of the unpacking.
@end itemize
@quotation Caution
The packed output will not be null-terminated unless one of the
following is true:
@itemize
@item
The input string is shorter than @var{len} bytes and either no pre-allocated
string was provided to @code{bindat-pack} or the appropriate byte in
the pre-allocated string was already null.
@item
The input string contains a null byte within the first @var{len}
bytes.
@end itemize
The packed output will not be null-terminated unless the input string
is shorter than @var{len} bytes or it contains a null byte within the
first @var{len} bytes.
@end quotation
@item vec @var{len} [@var{type}]

View file

@ -443,11 +443,14 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
(defun bindat--pack-strz (len v)
(let* ((v (string-to-unibyte v))
(vlen (length v)))
;; Explicitly write a null terminator (if there's room) in case
;; the user provided a pre-allocated string to `bindat-pack' that
;; wasn't already zeroed.
(when (or (null len) (< vlen len))
(aset bindat-raw (+ bindat-idx vlen) 0))
(if len
;; When len is specified, behave the same as the str type
;; since we don't actually add the terminating zero anyway
;; (because we rely on the fact that `bindat-raw' was
;; presumably initialized with all-zeroes before we started).
;; (except for the null terminator possibly written above).
(bindat--pack-str len v)
(dotimes (i vlen)
(when (= (aref v i) 0)
@ -456,10 +459,6 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
;; need to scan the input string looking for a null byte.
(error "Null byte encountered in input strz string"))
(aset bindat-raw (+ bindat-idx i) (aref v i)))
;; Explicitly write a null terminator in case the user provided
;; a pre-allocated string to `bindat-pack' that wasn't already
;; zeroed.
(aset bindat-raw (+ bindat-idx vlen) 0)
(setq bindat-idx (+ bindat-idx vlen 1)))))
(defun bindat--pack-bits (len v)

View file

@ -172,14 +172,14 @@
((((x str 2)) ((x . "a"))) . "ax")
((((x str 2)) ((x . "ab"))) . "ab")
((((x str 2)) ((x . "abc"))) . "ab")
((,(bindat-type strz 1) "") . "xx")
((,(bindat-type strz 2) "") . "xx")
((,(bindat-type strz 2) "a") . "ax")
((,(bindat-type strz 1) "") . "\0x")
((,(bindat-type strz 2) "") . "\0x")
((,(bindat-type strz 2) "a") . "a\0")
((,(bindat-type strz 2) "ab") . "ab")
((,(bindat-type strz 2) "abc") . "ab")
((((x strz 1)) ((x . ""))) . "xx")
((((x strz 2)) ((x . ""))) . "xx")
((((x strz 2)) ((x . "a"))) . "ax")
((((x strz 1)) ((x . ""))) . "\0x")
((((x strz 2)) ((x . ""))) . "\0x")
((((x strz 2)) ((x . "a"))) . "a\0")
((((x strz 2)) ((x . "ab"))) . "ab")
((((x strz 2)) ((x . "abc"))) . "ab")
((,(bindat-type strz) "") . "\0x")