Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix a crasher in StackFrame::GetValueForVariableExpressionPath()
There was a crash that would happen if an IDE would ask for a child of a shared pointer via any SB API call that ends up calling StackFrame::GetValueForVariableExpressionPath(). The previous code expects an error to be set describing why the synthetic child of a type was not able to be found, but we have some synthetic child providers that weren't setting the error and returning an empty value object shared pointer. This fixes that to ensure we don't lose our debug session by crashing, fully tests GetValueForVariableExpressionPath functionality, and ensures we don't crash on GetValueForVariableExpressionPath() in the future. Differential Revision: https://reviews.llvm.org/D59200 llvm-svn: 355850
- Loading branch information
Greg Clayton
committed
Mar 11, 2019
1 parent
06ae025
commit 0d6f681
Showing
4 changed files
with
129 additions
and
1 deletion.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
lldb/packages/Python/lldbsuite/test/functionalities/var_path/Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
LEVEL = ../../make | ||
|
||
CXX_SOURCES := main.cpp | ||
|
||
include $(LEVEL)/Makefile.rules |
103 changes: 103 additions & 0 deletions
103
lldb/packages/Python/lldbsuite/test/functionalities/var_path/TestVarPath.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
""" | ||
Make sure the getting a variable path works and doesn't crash. | ||
""" | ||
|
||
from __future__ import print_function | ||
|
||
|
||
import os | ||
import time | ||
import re | ||
import lldb | ||
import lldbsuite.test.lldbutil as lldbutil | ||
from lldbsuite.test.lldbtest import * | ||
|
||
|
||
class TestVarPath(TestBase): | ||
|
||
mydir = TestBase.compute_mydir(__file__) | ||
|
||
# If your test case doesn't stress debug info, the | ||
# set this to true. That way it won't be run once for | ||
# each debug info format. | ||
NO_DEBUG_INFO_TESTCASE = True | ||
|
||
def test_frame_var(self): | ||
self.build() | ||
self.do_test() | ||
|
||
def setUp(self): | ||
# Call super's setUp(). | ||
TestBase.setUp(self) | ||
|
||
def verify_point(self, frame, var_name, var_typename, x_value, y_value): | ||
v = frame.GetValueForVariablePath(var_name) | ||
self.assertTrue(v.GetError().Success(), "Make sure we find '%s'" % (var_name)) | ||
self.assertTrue(v.GetType().GetName() == var_typename, | ||
"Make sure '%s' has type '%s'" % (var_name, var_typename)) | ||
|
||
if '*' in var_typename: | ||
valid_prefix = var_name + '->' | ||
invalid_prefix = var_name + '.' | ||
else: | ||
valid_prefix = var_name + '.' | ||
invalid_prefix = var_name + '->' | ||
|
||
valid_x_path = valid_prefix + 'x' | ||
valid_y_path = valid_prefix + 'y' | ||
invalid_x_path = invalid_prefix + 'x' | ||
invalid_y_path = invalid_prefix + 'y' | ||
invalid_m_path = invalid_prefix + 'm' | ||
|
||
v = frame.GetValueForVariablePath(valid_x_path) | ||
self.assertTrue(v.GetError().Success(), "Make sure we find '%s'" % (valid_x_path)) | ||
self.assertTrue(v.GetValue() == str(x_value), "Make sure '%s' has a value of %i" % (valid_x_path, x_value)) | ||
self.assertTrue(v.GetType().GetName() == "int", "Make sure '%s' has type 'int'" % (valid_x_path)) | ||
v = frame.GetValueForVariablePath(invalid_x_path) | ||
self.assertTrue(v.GetError().Fail(), "Make sure we don't find '%s'" % (invalid_x_path)) | ||
|
||
v = frame.GetValueForVariablePath(valid_y_path) | ||
self.assertTrue(v.GetError().Success(), "Make sure we find '%s'" % (valid_y_path)) | ||
self.assertTrue(v.GetValue() == str(y_value), "Make sure '%s' has a value of %i" % (valid_y_path, y_value)) | ||
self.assertTrue(v.GetType().GetName() == "int", "Make sure '%s' has type 'int'" % (valid_y_path)) | ||
v = frame.GetValueForVariablePath(invalid_y_path) | ||
self.assertTrue(v.GetError().Fail(), "Make sure we don't find '%s'" % (invalid_y_path)) | ||
|
||
v = frame.GetValueForVariablePath(invalid_m_path) | ||
self.assertTrue(v.GetError().Fail(), "Make sure we don't find '%s'" % (invalid_m_path)) | ||
|
||
def do_test(self): | ||
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( | ||
self, "// Set a breakpoint here", lldb.SBFileSpec("main.cpp")) | ||
|
||
frame = thread.GetFrameAtIndex(0) | ||
v = frame.GetValueForVariablePath('no_such_variable') | ||
self.assertTrue(v.GetError().Fail(), "Make sure we don't find 'no_such_variable'") | ||
|
||
# Test an instance | ||
self.verify_point(frame, 'pt', 'Point', 1, 2) | ||
# Test a pointer | ||
self.verify_point(frame, 'pt_ptr', 'Point *', 3030, 4040) | ||
# Test using a pointer as an array | ||
self.verify_point(frame, 'pt_ptr[-1]', 'Point', 1010, 2020) | ||
self.verify_point(frame, 'pt_ptr[0]', 'Point', 3030, 4040) | ||
self.verify_point(frame, 'pt_ptr[1]', 'Point', 5050, 6060) | ||
# Test arrays | ||
v = frame.GetValueForVariablePath('points') | ||
self.assertTrue(v.GetError().Success(), | ||
"Make sure we find 'points'") | ||
self.verify_point(frame, 'points[0]', 'Point', 1010, 2020) | ||
self.verify_point(frame, 'points[1]', 'Point', 3030, 4040) | ||
self.verify_point(frame, 'points[2]', 'Point', 5050, 6060) | ||
# Test a reference | ||
self.verify_point(frame, 'pt_ref', 'Point &', 1, 2) | ||
v = frame.GetValueForVariablePath('pt_sp') | ||
self.assertTrue(v.GetError().Success(), "Make sure we find 'pt_sp'") | ||
# Make sure we don't crash when looking for non existant child | ||
# in type with synthetic children. This used to cause a crash. | ||
v = frame.GetValueForVariablePath('pt_sp->not_valid_child') | ||
self.assertTrue(v.GetError().Fail(), | ||
"Make sure we don't find 'pt_sp->not_valid_child'") | ||
|
||
|
||
|
15 changes: 15 additions & 0 deletions
15
lldb/packages/Python/lldbsuite/test/functionalities/var_path/main.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include <memory> | ||
|
||
struct Point { | ||
int x, y; | ||
}; | ||
|
||
int main() { | ||
Point pt = { 1, 2 }; | ||
Point points[] = {{1010,2020}, {3030,4040}, {5050,6060}}; | ||
Point *pt_ptr = &points[1]; | ||
Point &pt_ref = pt; | ||
std::shared_ptr<Point> pt_sp(new Point{111,222}); | ||
return 0; // Set a breakpoint here | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters