Prevent undefined behaviour in herodotus_reader_copy() - libgrapheme - unicode string library
 (HTM) git clone git://git.suckless.org/libgrapheme
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 004bdcf210baf1a63772bb7eca452bb0aeba010b
 (DIR) parent ef3e52a7f560f66df8ed1e2487872a1e62c5cedb
 (HTM) Author: Laslo Hunhold <dev@frign.de>
       Date:   Sat,  8 Oct 2022 13:13:03 +0200
       
       Prevent undefined behaviour in herodotus_reader_copy()
       
       The first part usually catches harmless cases like "NULL + 0", but the
       last part prevents integer overflow in some really crazy cases that
       are unlikely but can still happen.
       
       Signed-off-by: Laslo Hunhold <dev@frign.de>
       
       Diffstat:
         M src/util.c                          |      20 +++++++++++++++-----
       
       1 file changed, 15 insertions(+), 5 deletions(-)
       ---
 (DIR) diff --git a/src/util.c b/src/util.c
       @@ -37,23 +37,33 @@ herodotus_reader_copy(const HERODOTUS_READER *src, HERODOTUS_READER *dest)
                 */
                dest->type = src->type;
                if (src->type == HERODOTUS_TYPE_CODEPOINT) {
       -                dest->src = ((const uint_least32_t *)(src->src)) + src->off;
       +                dest->src = (src->src == NULL) ? NULL :
       +                            ((const uint_least32_t *)(src->src)) + src->off;
                } else { /* src->type == HERODOTUS_TYPE_UTF8 */
       -                dest->src = ((const char *)(src->src)) + src->off;
       +                dest->src = (src->src == NULL) ? NULL :
       +                            ((const char *)(src->src)) + src->off;
                }
                if (src->srclen == SIZE_MAX) {
                        dest->srclen = SIZE_MAX;
                } else {
       -                dest->srclen = src->srclen - src->off;
       +                dest->srclen = (src->off < src->srclen) ? src->srclen - src->off : 0;
                }
                dest->off = 0;
                dest->terminated_by_null = src->terminated_by_null;
        
                for (i = 0; i < LEN(src->soft_limit); i++) {
                        if (src->soft_limit[i] == SIZE_MAX) {
       -                        dest->soft_limit[i] = src->soft_limit[i];
       +                        dest->soft_limit[i] = SIZE_MAX;
                        } else {
       -                        dest->soft_limit[i] = src->soft_limit[i] - src->off;
       +                        /*
       +                         * if we have a degenerate case where the offset is
       +                         * higher than the soft-limit, we simply clamp the
       +                         * soft-limit to zero given we can't decide here
       +                         * to release the limit and, instead, we just
       +                         * prevent any more reads
       +                         */
       +                        dest->soft_limit[i] = (src->off < src->soft_limit[i]) ?
       +                                src->soft_limit[i] - src->off : 0;
                        }
                }
        }