From 8f799cd8b15f5d10bf52f126251fb8833452b48b Mon Sep 17 00:00:00 2001
From: Ilya Verbin <iverbin@tarantool.org>
Date: Fri, 8 Jul 2022 20:23:25 +0300
Subject: [PATCH] lua-yaml: encode malformed error messages in base64

If MP_ERROR contains an error message with invalid UTF-8 sequences,
encode it in Base64 to obtain printable string.

Closes #6781
Closes #6934

NO_DOC=bugfix
---
 .../gh-6934-nonprintable-error-message.md       |  4 ++++
 .../gh_6934_nonprintable_error_message_test.lua | 17 +++++++++++++++++
 third_party/lua-yaml/lyaml.cc                   |  8 ++++++++
 3 files changed, 29 insertions(+)
 create mode 100644 changelogs/unreleased/gh-6934-nonprintable-error-message.md
 create mode 100644 test/box-luatest/gh_6934_nonprintable_error_message_test.lua

diff --git a/changelogs/unreleased/gh-6934-nonprintable-error-message.md b/changelogs/unreleased/gh-6934-nonprintable-error-message.md
new file mode 100644
index 0000000000..fc9f9ae0c8
--- /dev/null
+++ b/changelogs/unreleased/gh-6934-nonprintable-error-message.md
@@ -0,0 +1,4 @@
+## bugfix/core
+
+* Fixed tarantool terminations on error messages with invalid UTF-8
+  sequences (gh-6781 and gh-6934).
diff --git a/test/box-luatest/gh_6934_nonprintable_error_message_test.lua b/test/box-luatest/gh_6934_nonprintable_error_message_test.lua
new file mode 100644
index 0000000000..a71b2fa327
--- /dev/null
+++ b/test/box-luatest/gh_6934_nonprintable_error_message_test.lua
@@ -0,0 +1,17 @@
+local console = require('console')
+local t = require('luatest')
+local g = t.group()
+
+-- Check that an error message with invalid UTF-8 sequences is encoded to Base64
+
+g.test_bad_utf8_in_error_msg1 = function()
+    local res = console.eval("box.error.new(box.error.ILLEGAL_PARAMS, 'bad: \x80')")
+    local ref = "---\n- !!binary SWxsZWdhbCBwYXJhbWV0ZXJzLCBiYWQ6IIA=\n...\n"
+    t.assert_equals(res, ref)
+end
+
+g.test_bad_utf8_in_error_msg2 = function()
+    local res = console.eval("require('net.box').self:call('bad: \x8a')")
+    local ref = "---\n- error: !!binary UHJvY2VkdXJlICdiYWQ6IIonIGlzIG5vdCBkZWZpbmVk\n...\n"
+    t.assert_equals(res, ref)
+end
diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc
index 0e576f28a6..d3ad2fe32d 100644
--- a/third_party/lua-yaml/lyaml.cc
+++ b/third_party/lua-yaml/lyaml.cc
@@ -711,6 +711,14 @@ static int dump_node(struct lua_yaml_dumper *dumper)
       case MP_ERROR:
          str = field.errorval->errmsg;
          len = strlen(str);
+         if (!utf8_check_printable(str, len)) {
+            is_binary = 1;
+            lua_pop(dumper->L, 1);
+            lua_pushlstring(dumper->L, str, len);
+            tobase64(dumper->L, -1);
+            str = lua_tolstring(dumper->L, -1, &len);
+            tag = (yaml_char_t *) LUAYAML_TAG_PREFIX "binary";
+         }
          break;
       case MP_DATETIME:
          len = datetime_to_string(field.dateval, buf, sizeof(buf));
-- 
GitLab