Fix bug #3573: Out of bounds read in macro LBREAK_IF_REQUIRED
[claws.git] / src / codeconv.c
index 98981e135f92daf3a64e33703d135382e47b19bc..11b23112c8b127fd15a653f9c8c04086ac8eec1c 100644 (file)
@@ -155,10 +155,14 @@ void codeconv_set_strict(gboolean mode)
 static gint conv_jistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
 {
        const guchar *in = inbuf;
-       guchar *out = outbuf;
+       gchar *out = outbuf;
        JISState state = JIS_ASCII;
 
-       while (*in != '\0') {
+       /*
+        * Loop outputs up to 3 bytes in each pass (aux kanji) and we
+        * need 1 byte to terminate the output
+        */
+       while (*in != '\0' && (out - outbuf) < outlen - 4) {
                if (*in == ESC) {
                        in++;
                        if (*in == '$') {
@@ -291,10 +295,15 @@ static gint conv_jis_hantozen(guchar *outbuf, guchar jis_code, guchar sound_sym)
 static gint conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
 {
        const guchar *in = inbuf;
-       guchar *out = outbuf;
+       gchar *out = outbuf;
        JISState state = JIS_ASCII;
 
-       while (*in != '\0') {
+       /*
+        * Loop outputs up to 6 bytes in each pass (aux shift + aux
+        * kanji) and we need up to 4 bytes to terminate the output
+        * (ASCII shift + null)
+        */
+       while (*in != '\0' && (out - outbuf) < outlen - 10) {
                if (IS_ASCII(*in)) {
                        K_OUT();
                        *out++ = *in++;
@@ -380,9 +389,13 @@ static gint conv_euctojis(gchar *outbuf, gint outlen, const gchar *inbuf)
 static gint conv_sjistoeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
 {
        const guchar *in = inbuf;
-       guchar *out = outbuf;
+       gchar *out = outbuf;
 
-       while (*in != '\0') {
+       /*
+        * Loop outputs up to 2 bytes in each pass and we need 1 byte
+        * to terminate the output
+        */
+       while (*in != '\0' && (out - outbuf) < outlen - 3) {
                if (IS_ASCII(*in)) {
                        *out++ = *in++;
                } else if (issjiskanji1(*in)) {
@@ -467,7 +480,7 @@ static gint conv_euctoutf8(gchar *outbuf, gint outlen, const gchar *inbuf)
                if (cd == (iconv_t)-1) {
                        cd = iconv_open(CS_UTF_8, CS_EUC_JP);
                        if (cd == (iconv_t)-1) {
-                               g_warning("conv_euctoutf8(): %s\n",
+                               g_warning("conv_euctoutf8(): %s",
                                          g_strerror(errno));
                                iconv_ok = FALSE;
                                strncpy2(outbuf, inbuf, outlen);
@@ -524,7 +537,7 @@ static gint conv_utf8toeuc(gchar *outbuf, gint outlen, const gchar *inbuf)
                if (cd == (iconv_t)-1) {
                        cd = iconv_open(CS_EUC_JP, CS_UTF_8);
                        if (cd == (iconv_t)-1) {
-                               g_warning("conv_utf8toeuc(): %s\n",
+                               g_warning("conv_utf8toeuc(): %s",
                                          g_strerror(errno));
                                iconv_ok = FALSE;
                                strncpy2(outbuf, inbuf, outlen);
@@ -695,6 +708,8 @@ conv_get_fallback_for_private_encoding(const gchar *encoding)
 {
        if (encoding && (encoding[0] == 'X' || encoding[0] == 'x') &&
            encoding[1] == '-') {
+               if (!g_ascii_strcasecmp(encoding, CS_X_MACCYR))
+                       return CS_MACCYR;
                if (!g_ascii_strcasecmp(encoding, CS_X_GBK))
                        return CS_GBK;
        }
@@ -749,8 +764,17 @@ gchar *conv_codeset_strdup(const gchar *inbuf,
        size_t len;
        CodeConvFunc conv_func;
 
-       if (!strcmp2(src_code, dest_code))
+       if (!strcmp2(src_code, dest_code)) {
+               CharSet dest_charset = conv_get_charset_from_str(dest_code);
+               if (strict_mode && dest_charset == C_UTF_8) {
+                       /* ensure valid UTF-8 if target is UTF-8 */
+                       if (!g_utf8_validate(inbuf, -1, NULL)) {
+                               return NULL;
+                       }
+               }
+               /* otherwise, try for a lucky day */
                return g_strdup(inbuf);
+       }
 
        src_code = conv_get_fallback_for_private_encoding(src_code);
        conv_func = conv_get_code_conv_func(src_code, dest_code);
@@ -945,7 +969,7 @@ gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
                } else if (E2BIG == errno) {
                        EXPAND_BUF();
                } else {
-                       g_warning("conv_iconv_strdup(): %s\n",
+                       g_warning("conv_iconv_strdup(): %s",
                                  g_strerror(errno));
                        break;
                }
@@ -956,7 +980,7 @@ gchar *conv_iconv_strdup_with_cd(const gchar *inbuf, iconv_t cd)
                if (E2BIG == errno) {
                        EXPAND_BUF();
                } else {
-                       g_warning("conv_iconv_strdup(): %s\n",
+                       g_warning("conv_iconv_strdup(): %s",
                                  g_strerror(errno));
                        break;
                }
@@ -1013,6 +1037,7 @@ static const struct {
        {C_WINDOWS_1257,        CS_WINDOWS_1257},
        {C_WINDOWS_1258,        CS_WINDOWS_1258},
        {C_KOI8_R,              CS_KOI8_R},
+       {C_MACCYR,              CS_MACCYR},
        {C_KOI8_T,              CS_KOI8_T},
        {C_KOI8_U,              CS_KOI8_U},
        {C_ISO_2022_JP,         CS_ISO_2022_JP},
@@ -1559,9 +1584,7 @@ gchar *conv_unmime_header(const gchar *str, const gchar *default_encoding,
                                left = MAX_LINELEN - 1;                 \
                        }                                               \
                } else if (destp == (guchar *)dest && left < 7) {       \
-                       if (isspace(*(destp - 1)))                      \
-                               destp--;                                \
-                       else if (is_plain_text && isspace(*srcp))       \
+                       if (is_plain_text && isspace(*srcp))            \
                                srcp++;                                 \
                        if (*srcp) {                                    \
                                *destp++ = '\n';                        \
@@ -1675,7 +1698,7 @@ void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
                                                *dest = '\0';
                                                return;
                                        } else {
-                                               g_warning("conv_encode_header(): code conversion failed\n");
+                                               g_warning("conv_encode_header(): code conversion failed");
                                                conv_unreadable_8bit(part_str);
                                                out_str = g_strdup(part_str);
                                        }
@@ -1708,7 +1731,7 @@ void conv_encode_header_full(gchar *dest, gint len, const gchar *src,
                                out_str = conv_codeset_strdup
                                        (part_str, cur_encoding, out_encoding);
                                if (!out_str) {
-                                       g_warning("conv_encode_header(): code conversion failed\n");
+                                       g_warning("conv_encode_header(): code conversion failed");
                                        conv_unreadable_8bit(part_str);
                                        out_str = g_strdup(part_str);
                                }
@@ -1787,7 +1810,7 @@ gchar *conv_filename_to_utf8(const gchar *fs_file)
 
        utf8_file = g_filename_to_utf8(fs_file, -1, NULL, NULL, &error);
        if (error) {
-               g_warning("failed to convert encoding of file name: %s\n",
+               g_warning("failed to convert encoding of file name: %s",
                          error->message);
                g_error_free(error);
        }