From 2d25613e3422fa134428f10b70be9867cb0f3d37 Mon Sep 17 00:00:00 2001 From: Peter Somogyi Date: Thu, 10 Feb 2022 12:14:46 +0100 Subject: [PATCH] HBASE-26741 Incorrect exception handling in shell (#4101) Override eval_input in HIRB to modify exception handling logic. Signed-off-by: Josh Elser --- LICENSE.txt | 29 ++++++- NOTICE.txt | 2 +- hbase-shell/src/main/ruby/irb/hirb.rb | 104 ++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index a49fc5ef2ce0..c30fe2b3d32a 100755 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -252,7 +252,7 @@ under the terms of the MIT license. THE SOFTWARE. ---- -This project incorporates portions of the 'Protocol Buffers' project avaialble +This project incorporates portions of the 'Protocol Buffers' project available under a '3-clause BSD' license. Copyright 2008, Google Inc. @@ -612,3 +612,30 @@ available under the Creative Commons By Attribution 3.0 License. this trademark restriction does not form part of this License. Creative Commons may be contacted at https://creativecommons.org/. + +---- +This project incorporates portions of the 'Ruby' project available +under a '2-clause BSD' license. + + Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/NOTICE.txt b/NOTICE.txt index 8c97c343031c..41ed32c1c691 100755 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ Apache HBase -Copyright 2007-2020 The Apache Software Foundation +Copyright 2007-2022 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/hbase-shell/src/main/ruby/irb/hirb.rb b/hbase-shell/src/main/ruby/irb/hirb.rb index 33419b9f49a9..28f311ca36a1 100644 --- a/hbase-shell/src/main/ruby/irb/hirb.rb +++ b/hbase-shell/src/main/ruby/irb/hirb.rb @@ -56,6 +56,110 @@ def output_value # after all output. super unless @context.last_value.nil? end + + # Copied from irb.rb and overrides the rescue Exception block so the + # Shell::exception_handler can deal with the exceptions. + def eval_input + @scanner.set_prompt do + |ltype, indent, continue, line_no| + if ltype + f = @context.prompt_s + elsif continue + f = @context.prompt_c + elsif indent > 0 + f = @context.prompt_n + else + f = @context.prompt_i + end + f = "" unless f + if @context.prompting? + @context.io.prompt = p = prompt(f, ltype, indent, line_no) + else + @context.io.prompt = p = "" + end + if @context.auto_indent_mode + unless ltype + ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size + + indent * 2 - p.size + ind += 2 if continue + @context.io.prompt = p + " " * ind if ind > 0 + end + end + end + + @scanner.set_input(@context.io) do + signal_status(:IN_INPUT) do + if l = @context.io.gets + print l if @context.verbose? + else + if @context.ignore_eof? and @context.io.readable_after_eof? + l = "\n" + if @context.verbose? + printf "Use \"exit\" to leave %s\n", @context.ap_name + end + else + print "\n" + end + end + l + end + end + + @scanner.each_top_level_statement do |line, line_no| + signal_status(:IN_EVAL) do + begin + line.untaint + @context.evaluate(line, line_no) + output_value if @context.echo? + exc = nil + rescue Interrupt => exc + rescue SystemExit, SignalException + raise + rescue Exception + # HBASE-26741: Raise exception so Shell::exception_handler can catch it. + # This modifies this copied method from JRuby so that the HBase shell can + # manage the exception and set a proper exit code on the process. + raise + end + if exc + if exc.backtrace && exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && + !(SyntaxError === exc) + irb_bug = true + else + irb_bug = false + end + + messages = [] + lasts = [] + levels = 0 + if exc.backtrace + count = 0 + exc.backtrace.each do |m| + m = @context.workspace.filter_backtrace(m) or next unless irb_bug + m = sprintf("%9d: from %s", (count += 1), m) + if messages.size < @context.back_trace_limit + messages.push(m) + elsif lasts.size < @context.back_trace_limit + lasts.push(m).shift + levels += 1 + end + end + end + attr = STDOUT.tty? ? ATTR_TTY : ATTR_PLAIN + print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n" + unless lasts.empty? + puts lasts.reverse + printf "... %d levels...\n", levels if levels > 0 + end + puts messages.reverse + messages = exc.to_s.split(/\n/) + print "#{attr[1]}#{exc.class} (#{attr[4]}#{messages.shift}#{attr[0, 1]})#{attr[]}\n" + puts messages.map {|s| "#{attr[1]}#{s}#{attr[]}\n"} + print "Maybe IRB bug!\n" if irb_bug + end + end + end + end end ##