[Lldb-commits] [Diffusion] rL234178: We have an issue where if you use a C function right now that has no prototype…

Greg Clayton clayborg at gmail.com
Thu Apr 9 10:53:33 PDT 2015


This probably fails after my recent change to ClangExpressionDeclMap::GetFunctionAddress() from revision 234178.

The problem was that you might have an expression like:

(lldb) p (int)printf("%i\n", 123)

And we would mangle printf as a C++ function and get "_Z...printf..." which of course doesn't exist as a mangled name. Prior to my fix, this function would always do:


        Mangled mangled(name, is_mangled);
                
        CPPLanguageRuntime::MethodName method_name(mangled.GetDemangledName());

        llvm::StringRef basename = method_name.GetBasename();
            
        if (!basename.empty())
        {
            FindCodeSymbolInContext(ConstString(basename), m_parser_vars->m_sym_ctx, sc_list);
            sc_list_size = sc_list.GetSize();
        }


This is just plain wrong. It needs to be:

        Mangled mangled(name, is_mangled);
                
        CPPLanguageRuntime::MethodName method_name(mangled.GetDemangledName());

        // the C++ context must be empty before we can think of searching for symbol by a simple basename
        if (method_name.GetContext().empty())
        {
            llvm::StringRef basename = method_name.GetBasename();
            
            if (!basename.empty())
            {
                FindCodeSymbolInContext(ConstString(basename), m_parser_vars->m_sym_ctx, sc_list);
                sc_list_size = sc_list.GetSize();
            }
        }

Note that we now check for the method's context (namespace and containing classes) to be empty. So this works for "_Z...printf..." because the context is empty and the basename is "printf".

The problem with ignoring if the context is empty is you can end up getting some mangled name like:

_ZNSt3__16vectorIcNS_9allocatorIcEEEixEm

which demangles to:

std::__1::vector<char, std::__1::allocator<char> >::operator[](unsigned long)

The "method_name.GetContext()" returns "std::__1::vector<char, std::__1::allocator<char> >"
and "method_name.GetBasename()" returns "operator[]"

Now if we don't check for the context being empty, we are happy to accept _any_ function whose basename is "operator[]". So if the exact mangled name is not in your program because you never used that function so the template was never instantiated or used, then we will search for any function whose basename is "operator[]" which will match std::basic_string<char>::operator[] since all C++ standard libraries explicitly instantiate std::string. So now your function would happily run using the completely wrong function.

In your first case "myInt::myInt(int)" will give a context of "myInt" and we won't try to lookup "myInt" by basename. So the bug here is that you have no symbol for _ZN5myIntC1Ei in your executable's symbol table and you probably should. 

Same goes for "_ZN3fooC1Ei" which demangles to "foo::foo(int)". 

If you have a class like:

template <class T>
namespace my_stuff {
    class my_class {
        static void foo();
    }
}

Any you don't instantiate this template and yet you still have "foo::foo(int) like the second example, you really don't want to have a call to "my_stuff::my_class::foo()" actually fall "foo::foo()" because we grab the basename from "my_stuff::my_class::foo()" and have it just call any function whose basename if "foo".

So my fix needs to stay in and we need to figure out why there is no symbol for constructors that are supposed to exist, or we need to change the code so that those symbols do exist. I know constructors have "in charge" and "not in charge" constructors and maybe the test case code only generates on of them and then the expression tries to use the other?

Dump the symbol table of the "a.out" file and see what symbols it has. That should tell us more. We will need to see the mangled names, so use the following command:

(lldb) image dump symtab --show-mangled-names a.out

Greg

> On Apr 9, 2015, at 10:20 AM, Ilia K <ki.stfu at gmail.com> wrote:
> 
> Hello @clayborg,
> 
> The same thing on my Linux machine:
> 
>  1: test_with_dwarf_and_run_command (TestDataFormatterSynthVal.DataFormatterSynthValueTestCase)
>     Test using Python synthetic children provider to provide a value. ... (myInt) x = 3
>  (myInt) x = 3
>  error: call to a function 'myInt::myInt(int)' ('_ZN5myIntC1Ei') that is not present in the target
>  error: The expression could not be prepared to run in the target
>  FAILURE
> 
>  ======================================================================
>  FAIL: test_with_dwarf_and_run_command (TestDataFormatterSynthVal.DataFormatterSynthValueTestCase)
>     Test using Python synthetic children provider to provide a value.
>  ----------------------------------------------------------------------
>  Traceback (most recent call last):
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 696, in wrapper
>      func(*args, **kwargs)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 479, in wrapper
>      return func(self, *args, **kwargs)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py", line 27, in test_with_dwarf_and_run_command
>      self.data_formatter_commands()
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py", line 92, in data_formatter_commands
>      self.expect("expression struct S { myInt theInt{12}; }; S()", substrs = ['(theInt = 12)'])
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 2108, in expect
>      self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error, inHistory=inHistory)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 2034, in runCmd
>      msg if msg else CMD_MSG(cmd))
>  AssertionError: False is not True : Command 'expression struct S { myInt theInt{12}; }; S()' returns successfully
>  Config=x86_64-clang
>  ----------------------------------------------------------------------
> 
> and
> 
>  error: call to a function 'foo::foo(int)' ('_ZN3fooC1Ei') that is not present in the target
>  error: The expression could not be prepared to run in the target
>  FAILURE
> 
>  ======================================================================
>  FAIL: test_with_dwarf (TestFormatters.ExprFormattersTestCase)
>     Test expr + formatters for good interoperability.
>  ----------------------------------------------------------------------
>  Traceback (most recent call last):
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 543, in wrapper
>      func(*args, **kwargs)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 479, in wrapper
>      return func(self, *args, **kwargs)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/expression_command/formatters/TestFormatters.py", line 33, in test_with_dwarf
>      self.do_my_test()
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/expression_command/formatters/TestFormatters.py", line 60, in do_my_test
>      substrs = ['(int) a = 47', '(bar) b = {', '(int) i = 94', '(baz) b = {', '(int) k = 99'])
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 2108, in expect
>      self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error, inHistory=inHistory)
>    File "/home/testuser/build/workspace/LLDB_master_release_Linux/llvm_master/tools/lldb/test/lldbtest.py", line 2034, in runCmd
>      msg if msg else CMD_MSG(cmd))
>  AssertionError: False is not True : Command 'expression --show-types -- *(new foo(47))' returns successfully
>  Config=x86_64-clang
>  ----------------------------------------------------------------------
> 
> Thanks,
> Ilia
> 
> 
> USERS
>  tberghammer (Auditor)
>  ki.stfu (Auditor)
> 
> http://reviews.llvm.org/rL234178
> 
> EMAIL PREFERENCES
>  http://reviews.llvm.org/settings/panel/emailpreferences/
> 
> 





More information about the lldb-commits mailing list