Changeset b31323f in mainline for common/str.c


Ignore:
Timestamp:
2025-04-17T14:29:23Z (5 days ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
ae787807
Parents:
65bf084
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-17 11:01:00)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2025-04-17 14:29:23)
Message:

Test, fix and extend string sanitization

File:
1 edited

Legend:

Unmodified
Added
Removed
  • common/str.c

    r65bf084 rb31323f  
    234234}
    235235
     236static bool _is_surrogate(const mbstate_t *mb, uint8_t b)
     237{
     238        return (mb->state == 0b1111110000001101 && b >= 0xa0);
     239}
     240
    236241#define _likely(expr) __builtin_expect((expr), true)
    237242#define _unlikely(expr) __builtin_expect((expr), false)
     
    299304                                        return CHAR_INVALID;
    300305
     306                                /* Reject surrogates */
     307                                if (_unlikely(ch >= 0xD800 && ch < 0xE000))
     308                                        return CHAR_INVALID;
     309
    301310                                return ch;
    302311                        }
     
    323332                                        return CHAR_INVALID;
    324333
     334                                /* Reject out-of-range characters. */
     335                                if (_unlikely(ch >= 0x110000))
     336                                        return CHAR_INVALID;
     337
    325338                                return ch;
    326339                        }
     
    339352                uint8_t b = s[*offset];
    340353
    341                 if (!_is_continuation(b) || _is_non_shortest(mb, b)) {
     354                if (!_is_continuation(b) || _is_non_shortest(mb, b) || _is_surrogate(mb, b)) {
    342355                        mb->state = 0;
    343356                        return CHAR_INVALID;
     
    523536}
    524537
    525 /* Convert in place any bytes that don't form a valid character into U_SPECIAL. */
    526 static void _sanitize_string(char *str, size_t n)
     538/* Convert in place any bytes that don't form a valid character into replacement. */
     539static size_t _str_sanitize(char *str, size_t n, uint8_t replacement)
    527540{
    528541        uint8_t *b = (uint8_t *) str;
    529 
    530         for (; *b && n > 0; b++, n--) {
     542        size_t count = 0;
     543
     544        for (; n > 0 && b[0]; b++, n--) {
    531545                int cont = _continuation_bytes(b[0]);
    532546                if (__builtin_expect(cont, 0) == 0)
     
    534548
    535549                if (cont < 0 || n <= (size_t) cont) {
    536                         b[0] = U_SPECIAL;
     550                        b[0] = replacement;
     551                        count++;
    537552                        continue;
    538553                }
    539554
    540555                /* Check continuation bytes. */
     556                bool valid = true;
    541557                for (int i = 1; i <= cont; i++) {
    542558                        if (!_is_continuation(b[i])) {
    543                                 b[0] = U_SPECIAL;
    544                                 continue;
     559                                valid = false;
     560                                break;
    545561                        }
     562                }
     563
     564                if (!valid) {
     565                        b[0] = replacement;
     566                        count++;
     567                        continue;
    546568                }
    547569
     
    551573                 */
    552574
    553                 switch (cont) {
    554                 case 1:
    555                         /* 0b110!!!!x 0b10xxxxxx */
    556                         if (!(b[0] & 0b00011110))
    557                                 b[0] = U_SPECIAL;
    558 
    559                         continue;
    560                 case 2:
    561                         /* 0b1110!!!! 0b10!xxxxx 0b10xxxxxx */
    562                         if (!(b[0] & 0b00001111) && !(b[1] & 0b00100000))
    563                                 b[0] = U_SPECIAL;
    564 
    565                         continue;
    566                 case 3:
    567                         /* 0b11110!!! 0b10!!xxxx 0b10xxxxxx 0b10xxxxxx */
    568                         if (!(b[0] & 0b00000111) && !(b[1] & 0b00110000))
    569                                 b[0] = U_SPECIAL;
    570 
     575                /* 0b110!!!!x 0b10xxxxxx */
     576                if (cont == 1 && !(b[0] & 0b00011110)) {
     577                        b[0] = replacement;
     578                        count++;
    571579                        continue;
    572580                }
    573         }
     581
     582                /* 0b1110!!!! 0b10!xxxxx 0b10xxxxxx */
     583                if (cont == 2 && !(b[0] & 0b00001111) && !(b[1] & 0b00100000)) {
     584                        b[0] = replacement;
     585                        count++;
     586                        continue;
     587                }
     588
     589                /* 0b11110!!! 0b10!!xxxx 0b10xxxxxx 0b10xxxxxx */
     590                if (cont == 3 && !(b[0] & 0b00000111) && !(b[1] & 0b00110000)) {
     591                        b[0] = replacement;
     592                        count++;
     593                        continue;
     594                }
     595
     596                /* Check for surrogate character encoding. */
     597                if (cont == 2 && b[0] == 0xED && b[1] >= 0xA0) {
     598                        b[0] = replacement;
     599                        count++;
     600                        continue;
     601                }
     602
     603                /* Check for out-of-range code points. */
     604                if (cont == 3 && (b[0] > 0xF4 || (b[0] == 0xF4 && b[1] >= 0x90))) {
     605                        b[0] = replacement;
     606                        count++;
     607                        continue;
     608                }
     609
     610                b += cont;
     611                n -= cont;
     612        }
     613
     614        return count;
     615}
     616
     617size_t str_sanitize(char *str, size_t n, uint8_t replacement)
     618{
     619        return _str_sanitize(str, n, replacement);
    574620}
    575621
     
    11301176
    11311177        /* In-place translate invalid bytes to U_SPECIAL. */
    1132         _sanitize_string(dest, size);
     1178        _str_sanitize(dest, size, U_SPECIAL);
    11331179}
    11341180
     
    11591205
    11601206        /* In-place translate invalid bytes to U_SPECIAL. */
    1161         _sanitize_string(dest, size);
     1207        _str_sanitize(dest, size, U_SPECIAL);
    11621208}
    11631209
     
    11831229        if (dstr_size < size) {
    11841230                _str_cpyn(dest + dstr_size, size - dstr_size, src);
    1185                 _sanitize_string(dest + dstr_size, size - dstr_size);
     1231                _str_sanitize(dest + dstr_size, size - dstr_size, U_SPECIAL);
    11861232        }
    11871233}
     
    17621808
    17631809        memcpy(dest, src, size);
    1764         _sanitize_string(dest, size);
     1810        _str_sanitize(dest, size, U_SPECIAL);
    17651811        return dest;
    17661812}
     
    17951841
    17961842        memcpy(dest, src, size);
    1797         _sanitize_string(dest, size);
     1843        _str_sanitize(dest, size, U_SPECIAL);
    17981844        dest[size] = 0;
    17991845        return dest;
Note: See TracChangeset for help on using the changeset viewer.