@@ -779,6 +779,11 @@ const char* translate_utf8_utf8_utf8(int64_t context, const char* in, int32_t in
779779 for (int32_t in_for = 0 ; in_for < in_len; in_for += len_char_in) {
780780 // Updating len to char in this position
781781 len_char_in = gdv_fn_utf8_char_length (in[in_for]);
782+ // A truncated or invalid lead byte at the tail would make the copy below read
783+ // past IN, and a zero width would spin the loop forever; consume one byte.
784+ if (len_char_in == 0 || in_for + len_char_in > in_len) {
785+ len_char_in = 1 ;
786+ }
782787 // Making copy to std::string with length for this char position
783788 std::string insert_copy_key (in + in_for, len_char_in);
784789 if (subs_list.find (insert_copy_key) != subs_list.end ()) {
@@ -790,10 +795,6 @@ const char* translate_utf8_utf8_utf8(int64_t context, const char* in, int32_t in
790795 }
791796 } else {
792797 for (int32_t from_for = 0 ; from_for <= from_len; from_for += len_char_from) {
793- // Updating len to char in this position
794- len_char_from = gdv_fn_utf8_char_length (from[from_for]);
795- // Making copy to std::string with length for this char position
796- std::string copy_from_compare (from + from_for, len_char_from);
797798 if (from_for == from_len) {
798799 // If it's not in the FROM list, just add it to the map and the result.
799800 std::string insert_copy_value (in + in_for, len_char_in);
@@ -806,6 +807,15 @@ const char* translate_utf8_utf8_utf8(int64_t context, const char* in, int32_t in
806807 break ;
807808 }
808809
810+ // Updating len to char in this position
811+ len_char_from = gdv_fn_utf8_char_length (from[from_for]);
812+ // Clamp a truncated or invalid lead byte to the remaining bytes so the copy
813+ // below never reads past FROM and the loop always advances.
814+ if (len_char_from == 0 || from_for + len_char_from > from_len) {
815+ len_char_from = 1 ;
816+ }
817+ // Making copy to std::string with length for this char position
818+ std::string copy_from_compare (from + from_for, len_char_from);
809819 if (insert_copy_key != copy_from_compare) {
810820 // If this character does not exist in FROM list, don't need treatment
811821 continue ;
@@ -818,6 +828,10 @@ const char* translate_utf8_utf8_utf8(int64_t context, const char* in, int32_t in
818828 // If exist and the start_compare is in range, add to map with the
819829 // corresponding TO in position start_compare
820830 len_char_to = gdv_fn_utf8_char_length (to[start_compare]);
831+ // Clamp a truncated or invalid lead byte to the remaining bytes of TO.
832+ if (len_char_to == 0 || start_compare + len_char_to > to_len) {
833+ len_char_to = 1 ;
834+ }
821835 std::string insert_copy_value (to + start_compare, len_char_to);
822836 // Insert in map to next loops
823837 subs_list.insert (
0 commit comments