From ad79f6b4d9deceb9af2c49ad160487b4faf00b7e Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Tue, 20 Jan 2015 13:45:10 +0300
Subject: [PATCH] Fix #643: exception handling in console

---
 src/lua/console.lua       | 33 +++++++++++++++++++++------------
 test/app/console.result   |  4 +++-
 test/app/console.test.lua | 10 +++++++++-
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/src/lua/console.lua b/src/lua/console.lua
index 11fd8000f8..dc0541f68c 100644
--- a/src/lua/console.lua
+++ b/src/lua/console.lua
@@ -24,19 +24,28 @@ local function format(status, ...)
     local function wrapnull(v)
         return v == nil and formatter.NULL or v
     end
-    if not status then
-        local v = ...
-        return formatter.encode({{error = wrapnull(v) }})
-    end
-    local count = select('#', ...)
-    if count == 0 then
-        return "---\n...\n"
-    end
-    local res = {}
-    for i=1,count,1 do
-        table.insert(res, wrapnull(select(i, ...)))
+    local err
+    if status then
+        local count = select('#', ...)
+        if count == 0 then
+            return "---\n...\n"
+        end
+        local res = {}
+        for i=1,count,1 do
+            table.insert(res, wrapnull(select(i, ...)))
+        end
+        -- serializer can raise an exception
+        status, err = pcall(formatter.encode, res)
+        if status then
+            return err
+        else
+            err = 'console: an exception occurred during formatting result: '..
+                tostring(err)
+        end
+    else
+        err = wrapnull(...)
     end
-    return formatter.encode(res)
+    return formatter.encode({{error = err }})
 end
 
 --
diff --git a/test/app/console.result b/test/app/console.result
index 40596ba7e4..0f603e1514 100644
--- a/test/app/console.result
+++ b/test/app/console.result
@@ -1,5 +1,5 @@
 TAP version 13
-1..26
+1..28
 ok - console.listen started
 ok - Handshake
 ok - connect to console
@@ -18,6 +18,8 @@ ok - remote eval
 ok - remote state.remote.host
 ok - remote state.remote.port
 ok - remote state.prompt
+ok - exception handling
+ok - exception handling
 ok - remote disconnect
 ok - console.listen stopped
 ok - console.listen uri support
diff --git a/test/app/console.test.lua b/test/app/console.test.lua
index 680edb1463..483b3e4ecd 100755
--- a/test/app/console.test.lua
+++ b/test/app/console.test.lua
@@ -20,7 +20,7 @@ local EOL = "\n%.%.%.\n"
 
 test = tap.test("console")
 
-test:plan(26)
+test:plan(28)
 
 -- Start console and connect to it
 local server = console.listen(CONSOLE_SOCKET)
@@ -98,6 +98,14 @@ test:is(state.remote.port, IPROTO_SOCKET, "remote state.remote.port")
 test:is(state.prompt, string.format("%s:%s", "unix/", IPROTO_SOCKET),
         "remote state.prompt")
 
+-- Check exception handling (gh-643)
+client:write("error('test')\n")
+test:ok(yaml.decode(client:read(EOL))[1].error:match('test') ~= nil,
+    "exception handling")
+client:write("setmetatable({}, { __serialize = function() error('test') end})\n")
+test:ok(yaml.decode(client:read(EOL))[1].error:match('test') ~= nil,
+    "exception handling")
+
 -- Disconnect from iproto
 client:write("~.\n")
 -- Check that iproto console has been disconnected
-- 
GitLab