bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#56048: [PATCH] bindat (strz): Null terminate fixed-length strings if


From: Stefan Monnier
Subject: bug#56048: [PATCH] bindat (strz): Null terminate fixed-length strings if there is room
Date: Tue, 21 Jun 2022 16:44:06 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux)

Thanks, Richard.  Looks good to me.


        Stefan


Richard Hansen [2022-06-17 23:02:57] wrote:

> Attached are new revisions of the patches. The only differences are the
> comments were filled at column 70 instead of 80, and the commit message
> mentions the bug number.
>
> From 6096bc8bceada87a5c54e4eb500812a0b72ffd44 Mon Sep 17 00:00:00 2001
> From: Richard Hansen <rhansen@rhansen.org>
> Date: Sun, 29 May 2022 21:23:57 -0400
> Subject: [PATCH v2 1/2] ; bindat (strz): Move all pack logic to pack function
>
> ---
>  lisp/emacs-lisp/bindat.el | 49 ++++++++++++++++++---------------------
>  1 file changed, 23 insertions(+), 26 deletions(-)
>
> diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el
> index 46e2a4901c..4a642bb9c5 100644
> --- a/lisp/emacs-lisp/bindat.el
> +++ b/lisp/emacs-lisp/bindat.el
> @@ -440,20 +440,27 @@ bindat--pack-str
>        (aset bindat-raw (+ bindat-idx i) (aref v i)))
>      (setq bindat-idx (+ bindat-idx len))))
>  
> -(defun bindat--pack-strz (v)
> +(defun bindat--pack-strz (len v)
>    (let* ((v (string-to-unibyte v))
> -         (len (length v)))
> -    (dotimes (i len)
> -      (when (= (aref v i) 0)
> -        ;; Alternatively we could pretend that this was the end of
> -        ;; the string and stop packing, but then bindat-length would
> -        ;; 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 zeroed first.
> -    (aset bindat-raw (+ bindat-idx len) 0)
> -    (setq bindat-idx (+ bindat-idx len 1))))
> +         (vlen (length v)))
> +    (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).
> +        (bindat--pack-str len v)
> +      (dotimes (i vlen)
> +        (when (= (aref v i) 0)
> +          ;; Alternatively we could pretend that this was the end of
> +          ;; the string and stop packing, but then bindat-length would
> +          ;; 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)
>    (let ((bnum (1- (* 8 len))) j m)
> @@ -482,7 +489,8 @@ bindat--pack-item
>     ('u24r (bindat--pack-u24r v))
>     ('u32r (bindat--pack-u32r v))
>     ('bits (bindat--pack-bits len v))
> -   ((or 'str 'strz) (bindat--pack-str len v))
> +   ('str (bindat--pack-str len v))
> +   ('strz (bindat--pack-strz len v))
>     ('vec
>      (let ((l (length v)) (vlen 1))
>        (if (consp vectype)
> @@ -699,18 +707,7 @@ bindat--type
>                              ((numberp len) len)
>                              ;; General expression support.
>                              (t `(or ,len (1+ (length ,val)))))))
> -    (`(pack . ,args)
> -     ;; 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).
> -     (cond ; Same optimizations as 'length above.
> -      ((null len) `(bindat--pack-strz . ,args))
> -      ((numberp len) `(bindat--pack-str ,len . ,args))
> -      (t (macroexp-let2 nil len len
> -           `(if ,len
> -                (bindat--pack-str ,len . ,args)
> -              (bindat--pack-strz . ,args))))))))
> +    (`(pack . ,args) `(bindat--pack-strz ,len . ,args))))
>  
>  (cl-defmethod bindat--type (op (_ (eql 'bits))  len)
>    (bindat--pcase op
> -- 
> 2.36.1
>
>
> From 9ebda68264adca6f60f780d44995c4213d2c12c2 Mon Sep 17 00:00:00 2001
> From: Richard Hansen <rhansen@rhansen.org>
> Date: Thu, 16 Jun 2022 15:21:57 -0400
> Subject: [PATCH v2 2/2] 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.
> ---
>  doc/lispref/processes.texi           | 30 ++++++++++++++--------------
>  lisp/emacs-lisp/bindat.el            | 13 ++++++------
>  test/lisp/emacs-lisp/bindat-tests.el | 12 +++++------
>  3 files changed, 27 insertions(+), 28 deletions(-)
>
> diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
> index b9200aedde..d038d52d44 100644
> --- a/doc/lispref/processes.texi
> +++ b/doc/lispref/processes.texi
> @@ -3509,23 +3509,23 @@ Bindat Types
>  (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 string if
> +the length of 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}]
> diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el
> index 4a642bb9c5..0ecac3d52a 100644
> --- a/lisp/emacs-lisp/bindat.el
> +++ b/lisp/emacs-lisp/bindat.el
> @@ -443,11 +443,14 @@ bindat--pack-str
>  (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 @@ bindat--pack-strz
>            ;; 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)
> diff --git a/test/lisp/emacs-lisp/bindat-tests.el 
> b/test/lisp/emacs-lisp/bindat-tests.el
> index cc223ad14e..0c03c51e2e 100644
> --- a/test/lisp/emacs-lisp/bindat-tests.el
> +++ b/test/lisp/emacs-lisp/bindat-tests.el
> @@ -172,14 +172,14 @@ bindat-test--str-strz-prealloc
>                  ((((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")






reply via email to

[Prev in Thread] Current Thread [Next in Thread]