Fix a bug caused by my alias refactoring where, if an alias was defined in terms of another alias, trying to run the nested command would actually cause a crash in the command interpreter

llvm-svn: 264096
This commit is contained in:
Enrico Granata 2016-03-22 21:07:54 +00:00
parent 00294b34a3
commit 660764a060
6 changed files with 116 additions and 2 deletions

View File

@ -93,9 +93,16 @@ public:
lldb::CommandObjectSP GetUnderlyingCommand() { return m_underlying_command_sp; }
OptionArgVectorSP GetOptionArguments() { return m_option_args_sp; }
const char* GetOptionString() { return m_option_string.c_str(); }
// this takes an alias - potentially nested (i.e. an alias to an alias)
// and expands it all the way to a non-alias command
std::pair<lldb::CommandObjectSP, OptionArgVectorSP>
Desugar ();
private:
lldb::CommandObjectSP m_underlying_command_sp;
std::string m_option_string;
OptionArgVectorSP m_option_args_sp ;
LazyBool m_is_dashdash_alias;
};

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,60 @@
"""
Test that an alias can reference other aliases without crashing.
"""
from __future__ import print_function
import os, time
import re
import lldb
from lldbsuite.test.lldbtest import *
import lldbsuite.test.lldbutil as lldbutil
class NestedAliasTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break inside main().
self.line = line_number('main.cpp', '// break here')
def test_nested_alias(self):
"""Test that an alias can reference other aliases without crashing."""
self.build()
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
# Break in main() aftre the variables are assigned values.
lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['stopped', 'stop reason = breakpoint'])
# The breakpoint should have a hit count of 1.
self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
substrs = [' resolved, hit count = 1'])
# This is the function to remove the custom aliases in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd('command unalias read', check=False)
self.runCmd('command unalias rd', check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
self.runCmd('command alias read memory read -f A')
self.runCmd('command alias rd read -c 3')
self.expect('memory read -f A -c 3 `&my_ptr[0]`', substrs=['deadbeef', 'main.cpp:', 'feedbeef'])
self.expect('rd `&my_ptr[0]`', substrs=['deadbeef', 'main.cpp:', 'feedbeef'])
self.expect('memory read -f A -c 3 `&my_ptr[0]`', substrs=['deadfeed'], matching=False)
self.expect('rd `&my_ptr[0]`', substrs=['deadfeed'], matching=False)

View File

@ -0,0 +1,22 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
int main (int argc, char const *argv[])
{
void* my_ptr[] = {
reinterpret_cast<void*>(0xDEADBEEF),
reinterpret_cast<void*>(main),
reinterpret_cast<void*>(0xFEEDBEEF),
reinterpret_cast<void*>(0xFEEDDEAD),
reinterpret_cast<void*>(0xDEADFEED)
};
return 0; // break here
}

View File

@ -85,6 +85,7 @@ CommandAlias::CommandAlias (CommandInterpreter &interpreter,
syntax,
flags),
m_underlying_command_sp(),
m_option_string(options_args ? options_args : ""),
m_option_args_sp(new OptionArgVector),
m_is_dashdash_alias(eLazyBoolCalculate)
{
@ -238,6 +239,24 @@ CommandAlias::IsDashDashCommand ()
return (m_is_dashdash_alias == eLazyBoolYes);
}
std::pair<lldb::CommandObjectSP, OptionArgVectorSP>
CommandAlias::Desugar ()
{
auto underlying = GetUnderlyingCommand();
if (!underlying)
return {nullptr,nullptr};
if (underlying->IsAlias())
{
auto desugared = ((CommandAlias*)underlying.get())->Desugar();
auto options = GetOptionArguments();
options->insert(options->begin(), desugared.second->begin(), desugared.second->end());
return {desugared.first,options};
}
return {underlying,GetOptionArguments()};
}
// allow CommandAlias objects to provide their own help, but fallback to the info
// for the underlying command if no customization has been provided
const char*

View File

@ -1359,8 +1359,9 @@ CommandInterpreter::BuildAliasResult (const char *alias_name,
if (alias_cmd_obj && alias_cmd_obj->IsAlias())
{
OptionArgVectorSP option_arg_vector_sp = ((CommandAlias*)alias_cmd_obj)->GetOptionArguments();
alias_cmd_obj = ((CommandAlias*)alias_cmd_obj)->GetUnderlyingCommand().get();
std::pair<CommandObjectSP, OptionArgVectorSP> desugared = ((CommandAlias*)alias_cmd_obj)->Desugar();
OptionArgVectorSP option_arg_vector_sp = desugared.second;
alias_cmd_obj = desugared.first.get();
std::string alias_name_str = alias_name;
if ((cmd_args.GetArgumentCount() == 0)
|| (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0))