Changes in common/str.c [28c39f3:0600976] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • common/str.c

    r28c39f3 r0600976  
    156156static inline int _char_continuation_bytes(char32_t c)
    157157{
     158        if ((c & ~LO_MASK_32(7)) == 0)
     159                return 0;
     160
    158161        if ((c & ~LO_MASK_32(11)) == 0)
    159162                return 1;
     
    207210char32_t str_decode(const char *str, size_t *offset, size_t size)
    208211{
    209         if (*offset + 1 > size)
     212        if (*offset >= size)
    210213                return 0;
    211214
     
    223226        /* Determine code length */
    224227
    225         unsigned int cbytes = _continuation_bytes(b0);
    226         unsigned int b0_bits = 6 - cbytes;  /* Data bits in first byte */
    227 
    228         if (*offset + cbytes > size)
     228        int cbytes = _continuation_bytes(b0);
     229        int b0_bits = 6 - cbytes;  /* Data bits in first byte */
     230
     231        if (cbytes < 0 || *offset + cbytes > size)
    229232                return U_SPECIAL;
    230233
     
    232235
    233236        /* Decode continuation bytes */
    234         while (cbytes > 0) {
    235                 uint8_t b = (uint8_t) str[(*offset)++];
     237        for (int i = 0; i < cbytes; i++) {
     238                uint8_t b = (uint8_t) str[*offset];
    236239
    237240                if (!_is_continuation_byte(b))
    238241                        return U_SPECIAL;
    239242
     243                (*offset)++;
     244
    240245                /* Shift data bits to ch */
    241246                ch = (ch << CONT_BITS) | (char32_t) (b & LO_MASK_8(CONT_BITS));
    242                 cbytes--;
    243         }
     247        }
     248
     249        /*
     250         * Reject non-shortest form encodings.
     251         * See https://www.unicode.org/versions/corrigendum1.html
     252         */
     253        if (cbytes != _char_continuation_bytes(ch))
     254                return U_SPECIAL;
    244255
    245256        return ch;
     
    345356
    346357/* Convert in place any bytes that don't form a valid character into U_SPECIAL. */
    347 static void _repair_string(char *str, size_t n)
    348 {
    349         for (; *str && n > 0; str++, n--) {
    350                 int cont = _continuation_bytes(*str);
    351                 if (cont == 0)
     358static void _sanitize_string(char *str, size_t n)
     359{
     360        uint8_t *b = (uint8_t *) str;
     361
     362        for (; *b && n > 0; b++, n--) {
     363                int cont = _continuation_bytes(b[0]);
     364                if (__builtin_expect(cont, 0) == 0)
    352365                        continue;
    353366
    354367                if (cont < 0 || n <= (size_t) cont) {
    355                         *str = U_SPECIAL;
     368                        b[0] = U_SPECIAL;
    356369                        continue;
    357370                }
    358371
     372                /* Check continuation bytes. */
    359373                for (int i = 1; i <= cont; i++) {
    360                         if (!_is_continuation_byte(str[i])) {
    361                                 *str = U_SPECIAL;
     374                        if (!_is_continuation_byte(b[i])) {
     375                                b[0] = U_SPECIAL;
    362376                                continue;
    363377                        }
     378                }
     379
     380                /*
     381                 * Check for non-shortest form encoding.
     382                 * See https://www.unicode.org/versions/corrigendum1.html
     383                 */
     384
     385                switch (cont) {
     386                case 1:
     387                        /* 0b110!!!!x 0b10xxxxxx */
     388                        if (!(b[0] & 0b00011110))
     389                                b[0] = U_SPECIAL;
     390
     391                        continue;
     392                case 2:
     393                        /* 0b1110!!!! 0b10!xxxxx 0b10xxxxxx */
     394                        if (!(b[0] & 0b00001111) && !(b[1] & 0b00100000))
     395                                b[0] = U_SPECIAL;
     396
     397                        continue;
     398                case 3:
     399                        /* 0b11110!!! 0b10!!xxxx 0b10xxxxxx 0b10xxxxxx */
     400                        if (!(b[0] & 0b00000111) && !(b[1] & 0b00110000))
     401                                b[0] = U_SPECIAL;
     402
     403                        continue;
    364404                }
    365405        }
     
    881921static void _str_cpyn(char *dest, size_t size, const char *src)
    882922{
     923        assert(dest && src && size);
     924
     925        if (!dest || !src || !size)
     926                return;
     927
     928        if (size == STR_NO_LIMIT)
     929                return _str_cpy(dest, src);
     930
    883931        char *dest_top = dest + size - 1;
     932        assert(size == 1 || dest < dest_top);
    884933
    885934        while (*src && dest < dest_top)
     
    907956        assert(src != NULL);
    908957        assert(dest != NULL);
     958        assert(size == STR_NO_LIMIT || dest + size > dest);
    909959
    910960        /* Copy data. */
     
    912962
    913963        /* In-place translate invalid bytes to U_SPECIAL. */
    914         _repair_string(dest, size);
     964        _sanitize_string(dest, size);
    915965}
    916966
     
    941991
    942992        /* In-place translate invalid bytes to U_SPECIAL. */
    943         _repair_string(dest, size);
     993        _sanitize_string(dest, size);
    944994}
    945995
     
    9601010        assert(dest != NULL);
    9611011        assert(size > 0);
     1012        assert(size == STR_NO_LIMIT || dest + size > dest);
    9621013
    9631014        size_t dstr_size = _str_nsize(dest, size);
    964         _str_cpyn(dest + dstr_size, size - dstr_size, src);
    965         _repair_string(dest + dstr_size, size - dstr_size);
     1015        if (dstr_size < size) {
     1016                _str_cpyn(dest + dstr_size, size - dstr_size, src);
     1017                _sanitize_string(dest + dstr_size, size - dstr_size);
     1018        }
    9661019}
    9671020
     
    15401593                return NULL;
    15411594
    1542         _str_cpy(dest, src);
    1543         _repair_string(dest, size);
     1595        memcpy(dest, src, size);
     1596        _sanitize_string(dest, size);
    15441597        return dest;
    15451598}
     
    15671620char *str_ndup(const char *src, size_t n)
    15681621{
    1569         size_t size = _str_nsize(src, n) + 1;
    1570 
    1571         char *dest = malloc(size);
     1622        size_t size = _str_nsize(src, n);
     1623
     1624        char *dest = malloc(size + 1);
    15721625        if (!dest)
    15731626                return NULL;
    15741627
    1575         _str_cpyn(dest, size, src);
    1576         _repair_string(dest, size);
     1628        memcpy(dest, src, size);
     1629        _sanitize_string(dest, size);
     1630        dest[size] = 0;
    15771631        return dest;
    15781632}
Note: See TracChangeset for help on using the changeset viewer.