# HG changeset patch # User Bruno Haible # Date 1552087639 -3600 # Node ID cc3fed3b77889680afd492aefd0bd71154c21e87 # Parent 8da9577294dafd839a9561ab164efa95c6def786 unilbrk/u*-possible-linebreaks: Fix undefined behaviour. Reported by Jeffrey Walton . * lib/unilbrk/u8-possible-linebreaks.c (u8_possible_linebreaks): Don't invoke memset with a zero size. * lib/unilbrk/u16-possible-linebreaks.c (u16_possible_linebreaks): Likewise. * lib/unilbrk/u32-possible-linebreaks.c (u32_possible_linebreaks): Adjust accordingly. diff -r 8da9577294da -r cc3fed3b7788 ChangeLog --- a/ChangeLog Sat Mar 09 00:01:47 2019 +0100 +++ b/ChangeLog Sat Mar 09 00:27:19 2019 +0100 @@ -1,3 +1,14 @@ +2019-03-08 Bruno Haible + + unilbrk/u*-possible-linebreaks: Fix undefined behaviour. + Reported by Jeffrey Walton . + * lib/unilbrk/u8-possible-linebreaks.c (u8_possible_linebreaks): Don't + invoke memset with a zero size. + * lib/unilbrk/u16-possible-linebreaks.c (u16_possible_linebreaks): + Likewise. + * lib/unilbrk/u32-possible-linebreaks.c (u32_possible_linebreaks): + Adjust accordingly. + 2019-03-08 Bruno Haible unistr/*, uniconv/*: Fix undefined behaviour. diff -r 8da9577294da -r cc3fed3b7788 lib/unilbrk/u16-possible-linebreaks.c --- a/lib/unilbrk/u16-possible-linebreaks.c Sat Mar 09 00:01:47 2019 +0100 +++ b/lib/unilbrk/u16-possible-linebreaks.c Sat Mar 09 00:27:19 2019 +0100 @@ -30,135 +30,139 @@ void u16_possible_linebreaks (const uint16_t *s, size_t n, const char *encoding, char *p) { - int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); - const uint16_t *s_end = s + n; - int last_prop = LBP_BK; /* line break property of last non-space character */ - char *seen_space = NULL; /* Was a space seen after the last non-space character? */ - char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ - - /* Don't break inside multibyte characters. */ - memset (p, UC_BREAK_PROHIBITED, n); - - while (s < s_end) + if (n > 0) { - ucs4_t uc; - int count = u16_mbtouc_unsafe (&uc, s, s_end - s); - int prop = unilbrkprop_lookup (uc); + int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); + const uint16_t *s_end = s + n; + int last_prop = LBP_BK; /* line break property of last non-space character */ + char *seen_space = NULL; /* Was a space seen after the last non-space character? */ + char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ - if (prop == LBP_BK) + /* Don't break inside multibyte characters. */ + memset (p, UC_BREAK_PROHIBITED, n); + + do { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else - { - char *q; + ucs4_t uc; + int count = u16_mbtouc_unsafe (&uc, s, s_end - s); + int prop = unilbrkprop_lookup (uc); - /* Resolve property values whose behaviour is not fixed. */ - switch (prop) + if (prop == LBP_BK) { - case LBP_AI: - /* Resolve ambiguous. */ - prop = LBP_AI_REPLACEMENT; - break; - case LBP_CB: - /* This is arbitrary. */ - prop = LBP_ID; - break; - case LBP_SA: - /* We don't handle complex scripts yet. - Treat LBP_SA like LBP_XX. */ - case LBP_XX: - /* This is arbitrary. */ - prop = LBP_AL; - break; - } - - /* Deal with spaces and combining characters. */ - q = p; - if (prop == LBP_SP) - { - /* Don't break just before a space. */ - *p = UC_BREAK_PROHIBITED; - seen_space2 = seen_space; - seen_space = p; - } - else if (prop == LBP_ZW) - { - /* Don't break just before a zero-width space. */ - *p = UC_BREAK_PROHIBITED; - last_prop = LBP_ZW; + /* Mandatory break. */ + *p = UC_BREAK_MANDATORY; + last_prop = LBP_BK; seen_space = NULL; seen_space2 = NULL; } - else if (prop == LBP_CM) + else { - /* Don't break just before a combining character, except immediately after a - zero-width space. */ - if (last_prop == LBP_ZW) + char *q; + + /* Resolve property values whose behaviour is not fixed. */ + switch (prop) + { + case LBP_AI: + /* Resolve ambiguous. */ + prop = LBP_AI_REPLACEMENT; + break; + case LBP_CB: + /* This is arbitrary. */ + prop = LBP_ID; + break; + case LBP_SA: + /* We don't handle complex scripts yet. + Treat LBP_SA like LBP_XX. */ + case LBP_XX: + /* This is arbitrary. */ + prop = LBP_AL; + break; + } + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + /* Don't break just before a space. */ + *p = UC_BREAK_PROHIBITED; + seen_space2 = seen_space; + seen_space = p; + } + else if (prop == LBP_ZW) + { + /* Don't break just before a zero-width space. */ + *p = UC_BREAK_PROHIBITED; + last_prop = LBP_ZW; + seen_space = NULL; + seen_space2 = NULL; + } + else if (prop == LBP_CM) + { + /* Don't break just before a combining character, except immediately + after a zero-width space. */ + if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *p = UC_BREAK_POSSIBLE; + /* A combining character turns a preceding space into LBP_ID. */ + last_prop = LBP_ID; + } + else + { + *p = UC_BREAK_PROHIBITED; + /* A combining character turns a preceding space into LBP_ID. */ + if (seen_space != NULL) + { + q = seen_space; + seen_space = seen_space2; + prop = LBP_ID; + goto lookup_via_table; + } + } } else { - *p = UC_BREAK_PROHIBITED; - /* A combining character turns a preceding space into LBP_ID. */ - if (seen_space != NULL) + lookup_via_table: + /* prop must be usable as an index for table 7.3 of UTR #14. */ + if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) + abort (); + + if (last_prop == LBP_BK) + { + /* Don't break at the beginning of a line. */ + *q = UC_BREAK_PROHIBITED; + } + else if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *q = UC_BREAK_POSSIBLE; + } + else { - q = seen_space; - seen_space = seen_space2; - prop = LBP_ID; - goto lookup_via_table; + switch (unilbrk_table [last_prop] [prop]) + { + case D: + *q = UC_BREAK_POSSIBLE; + break; + case I: + *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); + break; + case P: + *q = UC_BREAK_PROHIBITED; + break; + default: + abort (); + } } + last_prop = prop; + seen_space = NULL; + seen_space2 = NULL; } } - else - { - lookup_via_table: - /* prop must be usable as an index for table 7.3 of UTR #14. */ - if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) - abort (); - if (last_prop == LBP_BK) - { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; - } - else if (last_prop == LBP_ZW) - { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; - } - else - { - switch (unilbrk_table [last_prop] [prop]) - { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: - *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); - } - } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; - } + s += count; + p += count; } - - s += count; - p += count; + while (s < s_end); } } diff -r 8da9577294da -r cc3fed3b7788 lib/unilbrk/u32-possible-linebreaks.c --- a/lib/unilbrk/u32-possible-linebreaks.c Sat Mar 09 00:01:47 2019 +0100 +++ b/lib/unilbrk/u32-possible-linebreaks.c Sat Mar 09 00:27:19 2019 +0100 @@ -28,131 +28,135 @@ void u32_possible_linebreaks (const uint32_t *s, size_t n, const char *encoding, char *p) { - int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); - const uint32_t *s_end = s + n; - int last_prop = LBP_BK; /* line break property of last non-space character */ - char *seen_space = NULL; /* Was a space seen after the last non-space character? */ - char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ + if (n > 0) + { + int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); + const uint32_t *s_end = s + n; + int last_prop = LBP_BK; /* line break property of last non-space character */ + char *seen_space = NULL; /* Was a space seen after the last non-space character? */ + char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ - while (s < s_end) - { - ucs4_t uc = *s; - int prop = unilbrkprop_lookup (uc); - - if (prop == LBP_BK) + do { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else - { - char *q; + ucs4_t uc = *s; + int prop = unilbrkprop_lookup (uc); - /* Resolve property values whose behaviour is not fixed. */ - switch (prop) + if (prop == LBP_BK) { - case LBP_AI: - /* Resolve ambiguous. */ - prop = LBP_AI_REPLACEMENT; - break; - case LBP_CB: - /* This is arbitrary. */ - prop = LBP_ID; - break; - case LBP_SA: - /* We don't handle complex scripts yet. - Treat LBP_SA like LBP_XX. */ - case LBP_XX: - /* This is arbitrary. */ - prop = LBP_AL; - break; - } - - /* Deal with spaces and combining characters. */ - q = p; - if (prop == LBP_SP) - { - /* Don't break just before a space. */ - *p = UC_BREAK_PROHIBITED; - seen_space2 = seen_space; - seen_space = p; - } - else if (prop == LBP_ZW) - { - /* Don't break just before a zero-width space. */ - *p = UC_BREAK_PROHIBITED; - last_prop = LBP_ZW; + /* Mandatory break. */ + *p = UC_BREAK_MANDATORY; + last_prop = LBP_BK; seen_space = NULL; seen_space2 = NULL; } - else if (prop == LBP_CM) + else { - /* Don't break just before a combining character, except immediately after a - zero-width space. */ - if (last_prop == LBP_ZW) + char *q; + + /* Resolve property values whose behaviour is not fixed. */ + switch (prop) + { + case LBP_AI: + /* Resolve ambiguous. */ + prop = LBP_AI_REPLACEMENT; + break; + case LBP_CB: + /* This is arbitrary. */ + prop = LBP_ID; + break; + case LBP_SA: + /* We don't handle complex scripts yet. + Treat LBP_SA like LBP_XX. */ + case LBP_XX: + /* This is arbitrary. */ + prop = LBP_AL; + break; + } + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + /* Don't break just before a space. */ + *p = UC_BREAK_PROHIBITED; + seen_space2 = seen_space; + seen_space = p; + } + else if (prop == LBP_ZW) + { + /* Don't break just before a zero-width space. */ + *p = UC_BREAK_PROHIBITED; + last_prop = LBP_ZW; + seen_space = NULL; + seen_space2 = NULL; + } + else if (prop == LBP_CM) + { + /* Don't break just before a combining character, except immediately + after a zero-width space. */ + if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *p = UC_BREAK_POSSIBLE; + /* A combining character turns a preceding space into LBP_ID. */ + last_prop = LBP_ID; + } + else + { + *p = UC_BREAK_PROHIBITED; + /* A combining character turns a preceding space into LBP_ID. */ + if (seen_space != NULL) + { + q = seen_space; + seen_space = seen_space2; + prop = LBP_ID; + goto lookup_via_table; + } + } } else { - *p = UC_BREAK_PROHIBITED; - /* A combining character turns a preceding space into LBP_ID. */ - if (seen_space != NULL) + lookup_via_table: + /* prop must be usable as an index for table 7.3 of UTR #14. */ + if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) + abort (); + + if (last_prop == LBP_BK) + { + /* Don't break at the beginning of a line. */ + *q = UC_BREAK_PROHIBITED; + } + else if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *q = UC_BREAK_POSSIBLE; + } + else { - q = seen_space; - seen_space = seen_space2; - prop = LBP_ID; - goto lookup_via_table; + switch (unilbrk_table [last_prop] [prop]) + { + case D: + *q = UC_BREAK_POSSIBLE; + break; + case I: + *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); + break; + case P: + *q = UC_BREAK_PROHIBITED; + break; + default: + abort (); + } } + last_prop = prop; + seen_space = NULL; + seen_space2 = NULL; } } - else - { - lookup_via_table: - /* prop must be usable as an index for table 7.3 of UTR #14. */ - if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) - abort (); - if (last_prop == LBP_BK) - { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; - } - else if (last_prop == LBP_ZW) - { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; - } - else - { - switch (unilbrk_table [last_prop] [prop]) - { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: - *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); - } - } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; - } + s++; + p++; } - - s++; - p++; + while (s < s_end); } } diff -r 8da9577294da -r cc3fed3b7788 lib/unilbrk/u8-possible-linebreaks.c --- a/lib/unilbrk/u8-possible-linebreaks.c Sat Mar 09 00:01:47 2019 +0100 +++ b/lib/unilbrk/u8-possible-linebreaks.c Sat Mar 09 00:27:19 2019 +0100 @@ -30,136 +30,140 @@ void u8_possible_linebreaks (const uint8_t *s, size_t n, const char *encoding, char *p) { - int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); - const uint8_t *s_end = s + n; - int last_prop = LBP_BK; /* line break property of last non-space character */ - char *seen_space = NULL; /* Was a space seen after the last non-space character? */ - char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ - - /* Don't break inside multibyte characters. */ - memset (p, UC_BREAK_PROHIBITED, n); - - while (s < s_end) + if (n > 0) { - ucs4_t uc; - int count = u8_mbtouc_unsafe (&uc, s, s_end - s); - int prop = unilbrkprop_lookup (uc); + int LBP_AI_REPLACEMENT = (is_cjk_encoding (encoding) ? LBP_ID : LBP_AL); + const uint8_t *s_end = s + n; + int last_prop = LBP_BK; /* line break property of last non-space character */ + char *seen_space = NULL; /* Was a space seen after the last non-space character? */ + char *seen_space2 = NULL; /* At least two spaces after the last non-space? */ - if (prop == LBP_BK) + /* Don't break inside multibyte characters. */ + memset (p, UC_BREAK_PROHIBITED, n); + + do { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else - { - char *q; + ucs4_t uc; + int count = u8_mbtouc_unsafe (&uc, s, s_end - s); + int prop = unilbrkprop_lookup (uc); - /* Resolve property values whose behaviour is not fixed. */ - switch (prop) + if (prop == LBP_BK) { - case LBP_AI: - /* Resolve ambiguous. */ - prop = LBP_AI_REPLACEMENT; - break; - case LBP_CB: - /* This is arbitrary. */ - prop = LBP_ID; - break; - case LBP_SA: - /* We don't handle complex scripts yet. - Treat LBP_SA like LBP_XX. */ - case LBP_XX: - /* This is arbitrary. */ - prop = LBP_AL; - break; - } - - /* Deal with spaces and combining characters. */ - q = p; - if (prop == LBP_SP) - { - /* Don't break just before a space. */ - *p = UC_BREAK_PROHIBITED; - seen_space2 = seen_space; - seen_space = p; - } - else if (prop == LBP_ZW) - { - /* Don't break just before a zero-width space. */ - *p = UC_BREAK_PROHIBITED; - last_prop = LBP_ZW; + /* Mandatory break. */ + *p = UC_BREAK_MANDATORY; + last_prop = LBP_BK; seen_space = NULL; seen_space2 = NULL; } - else if (prop == LBP_CM) + else { - /* Don't break just before a combining character, except immediately after a - zero-width space. */ - if (last_prop == LBP_ZW) + char *q; + + /* Resolve property values whose behaviour is not fixed. */ + switch (prop) + { + case LBP_AI: + /* Resolve ambiguous. */ + prop = LBP_AI_REPLACEMENT; + break; + case LBP_CB: + /* This is arbitrary. */ + prop = LBP_ID; + break; + case LBP_SA: + /* We don't handle complex scripts yet. + Treat LBP_SA like LBP_XX. */ + case LBP_XX: + /* This is arbitrary. */ + prop = LBP_AL; + break; + } + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + /* Don't break just before a space. */ + *p = UC_BREAK_PROHIBITED; + seen_space2 = seen_space; + seen_space = p; + } + else if (prop == LBP_ZW) + { + /* Don't break just before a zero-width space. */ + *p = UC_BREAK_PROHIBITED; + last_prop = LBP_ZW; + seen_space = NULL; + seen_space2 = NULL; + } + else if (prop == LBP_CM) + { + /* Don't break just before a combining character, except immediately + after a zero-width space. */ + if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *p = UC_BREAK_POSSIBLE; + /* A combining character turns a preceding space into LBP_ID. */ + last_prop = LBP_ID; + } + else + { + *p = UC_BREAK_PROHIBITED; + /* A combining character turns a preceding space into LBP_ID. */ + if (seen_space != NULL) + { + q = seen_space; + seen_space = seen_space2; + prop = LBP_ID; + goto lookup_via_table; + } + } } else { - *p = UC_BREAK_PROHIBITED; - /* A combining character turns a preceding space into LBP_ID. */ - if (seen_space != NULL) + lookup_via_table: + /* prop must be usable as an index for table 7.3 of UTR #14. */ + if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) + abort (); + + if (last_prop == LBP_BK) + { + /* Don't break at the beginning of a line. */ + *q = UC_BREAK_PROHIBITED; + } + else if (last_prop == LBP_ZW) + { + /* Break after zero-width space. */ + *q = UC_BREAK_POSSIBLE; + } + else { - q = seen_space; - seen_space = seen_space2; - prop = LBP_ID; - goto lookup_via_table; + switch (unilbrk_table [last_prop] [prop]) + { + case D: + *q = UC_BREAK_POSSIBLE; + break; + case I: + *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); + break; + case P: + *q = UC_BREAK_PROHIBITED; + break; + default: + abort (); + } } + last_prop = prop; + seen_space = NULL; + seen_space2 = NULL; } } - else - { - lookup_via_table: - /* prop must be usable as an index for table 7.3 of UTR #14. */ - if (!(prop >= 0 && prop < sizeof (unilbrk_table) / sizeof (unilbrk_table[0]))) - abort (); - if (last_prop == LBP_BK) - { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; - } - else if (last_prop == LBP_ZW) - { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; - } - else - { - switch (unilbrk_table [last_prop] [prop]) - { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: - *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); - } - } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; - } + s += count; + p += count; } - - s += count; - p += count; + while (s < s_end); } }