>From fa418ebbdf307d0efc1e61677045f48de5a93398 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 9 Mar 2019 00:27:19 +0100 Subject: [PATCH 4/4] 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. --- ChangeLog | 11 ++ lib/unilbrk/u16-possible-linebreaks.c | 212 +++++++++++++++++----------------- lib/unilbrk/u32-possible-linebreaks.c | 204 ++++++++++++++++---------------- lib/unilbrk/u8-possible-linebreaks.c | 212 +++++++++++++++++----------------- 4 files changed, 331 insertions(+), 308 deletions(-) diff --git a/ChangeLog b/ChangeLog index 687357e..a67ed92 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 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. Reported by Jeffrey Walton . * lib/unistr/u-cpy.h (FUNC): Don't invoke memcpy with a zero size. diff --git a/lib/unilbrk/u16-possible-linebreaks.c b/lib/unilbrk/u16-possible-linebreaks.c index 3ee91ad..0a91368 100644 --- a/lib/unilbrk/u16-possible-linebreaks.c +++ b/lib/unilbrk/u16-possible-linebreaks.c @@ -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) - { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else - { - char *q; + /* Don't break inside multibyte characters. */ + memset (p, UC_BREAK_PROHIBITED, n); - /* 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; - } + do + { + ucs4_t uc; + int count = u16_mbtouc_unsafe (&uc, s, s_end - s); + int prop = unilbrkprop_lookup (uc); - /* 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) + if (prop == LBP_BK) { - /* 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) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + 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; } - else + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { + /* Don't break just before a space. */ *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; - } + seen_space2 = seen_space; + seen_space = p; } - } - 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) + else if (prop == LBP_ZW) { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; + /* 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 (last_prop == LBP_ZW) + else if (prop == LBP_CM) { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; + /* 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 { - switch (unilbrk_table [last_prop] [prop]) + 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) { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: + /* Don't break at the beginning of a line. */ *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); } + 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; } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; } - } - s += count; - p += count; + s += count; + p += count; + } + while (s < s_end); } } diff --git a/lib/unilbrk/u32-possible-linebreaks.c b/lib/unilbrk/u32-possible-linebreaks.c index cdd00c8..9a0bafa 100644 --- a/lib/unilbrk/u32-possible-linebreaks.c +++ b/lib/unilbrk/u32-possible-linebreaks.c @@ -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? */ - - while (s < s_end) + if (n > 0) { - ucs4_t uc = *s; - int prop = unilbrkprop_lookup (uc); + 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 (prop == LBP_BK) - { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else + do { - 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) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + 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; } - else + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { + /* Don't break just before a space. */ *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; - } + seen_space2 = seen_space; + seen_space = p; } - } - 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) + else if (prop == LBP_ZW) { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; + /* 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 (last_prop == LBP_ZW) + else if (prop == LBP_CM) { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; + /* 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 { - switch (unilbrk_table [last_prop] [prop]) + 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) { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: + /* Don't break at the beginning of a line. */ *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); } + 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; } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; } - } - s++; - p++; + s++; + p++; + } + while (s < s_end); } } diff --git a/lib/unilbrk/u8-possible-linebreaks.c b/lib/unilbrk/u8-possible-linebreaks.c index 1e2224b..79efcb2 100644 --- a/lib/unilbrk/u8-possible-linebreaks.c +++ b/lib/unilbrk/u8-possible-linebreaks.c @@ -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) - { - /* Mandatory break. */ - *p = UC_BREAK_MANDATORY; - last_prop = LBP_BK; - seen_space = NULL; - seen_space2 = NULL; - } - else - { - char *q; + /* Don't break inside multibyte characters. */ + memset (p, UC_BREAK_PROHIBITED, n); - /* 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; - } + do + { + ucs4_t uc; + int count = u8_mbtouc_unsafe (&uc, s, s_end - s); + int prop = unilbrkprop_lookup (uc); - /* Deal with spaces and combining characters. */ - q = p; - if (prop == LBP_SP) + if (prop == LBP_BK) { - /* 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) { - /* Break after zero-width space. */ - *p = UC_BREAK_POSSIBLE; - /* A combining character turns a preceding space into LBP_ID. */ - last_prop = LBP_ID; + 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; } - else + + /* Deal with spaces and combining characters. */ + q = p; + if (prop == LBP_SP) { + /* Don't break just before a space. */ *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; - } + seen_space2 = seen_space; + seen_space = p; } - } - 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) + else if (prop == LBP_ZW) { - /* Don't break at the beginning of a line. */ - *q = UC_BREAK_PROHIBITED; + /* 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 (last_prop == LBP_ZW) + else if (prop == LBP_CM) { - /* Break after zero-width space. */ - *q = UC_BREAK_POSSIBLE; + /* 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 { - switch (unilbrk_table [last_prop] [prop]) + 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) { - case D: - *q = UC_BREAK_POSSIBLE; - break; - case I: - *q = (seen_space != NULL ? UC_BREAK_POSSIBLE : UC_BREAK_PROHIBITED); - break; - case P: + /* Don't break at the beginning of a line. */ *q = UC_BREAK_PROHIBITED; - break; - default: - abort (); } + 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; } - last_prop = prop; - seen_space = NULL; - seen_space2 = NULL; } - } - s += count; - p += count; + s += count; + p += count; + } + while (s < s_end); } } -- 2.7.4