Skip to content

Commit c90480c

Browse files
Merge branch 'main' into orc-drop-debugobjectregistrar
2 parents 851ceb0 + 550522d commit c90480c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2730
-1312
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV);
5858
DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State,
5959
SVal BufV, QualType Ty);
6060

61+
void markAllDynamicExtentLive(ProgramStateRef State, SymbolReaper &SymReaper);
62+
6163
} // namespace ento
6264
} // namespace clang
6365

clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,12 @@ ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR,
128128
return State->set<DynamicExtentMap>(MR->StripCasts(), Size);
129129
}
130130

131+
void markAllDynamicExtentLive(ProgramStateRef State, SymbolReaper &SymReaper) {
132+
for (const auto &I : State->get<DynamicExtentMap>())
133+
if (SymbolRef Sym = I.second.getAsSymbol())
134+
if (SymReaper.isLiveRegion(I.first))
135+
SymReaper.markLive(Sym);
136+
}
137+
131138
} // namespace ento
132139
} // namespace clang

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,11 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
10791079
getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper,
10801080
DiagnosticStmt, *this, K);
10811081

1082+
// Extend lifetime of symbols used for dynamic extent while the parent region
1083+
// is live. In this way size information about memory allocations is not lost
1084+
// if the region remains live.
1085+
markAllDynamicExtentLive(CleanedState, SymReaper);
1086+
10821087
// For each node in CheckedSet, generate CleanedNodes that have the
10831088
// environment, the store, and the constraints cleaned up but have the
10841089
// user-supplied states as the predecessors.

clang/test/Analysis/ArrayBound/verbose-tests.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -381,30 +381,12 @@ int *symbolicExtent(int arg) {
381381
return 0;
382382
int *mem = (int*)malloc(arg);
383383

384-
// TODO: without the following reference to 'arg', the analyzer would discard
385-
// the range information about (the symbolic value of) 'arg'. This is
386-
// incorrect because while the variable itself is inaccessible, it becomes
387-
// the symbolic extent of 'mem', so we still want to reason about its
388-
// potential values.
389-
(void)arg;
390-
391384
mem[8] = -2;
392385
// expected-warning@-1 {{Out of bound access to memory after the end of the heap area}}
393386
// expected-note@-2 {{Access of 'int' element in the heap area at index 8}}
394387
return mem;
395388
}
396389

397-
int *symbolicExtentDiscardedRangeInfo(int arg) {
398-
// This is a copy of the case 'symbolicExtent' without the '(void)arg' hack.
399-
// TODO: if the analyzer can detect the out-of-bounds access within this
400-
// testcase, then remove this and the `(void)arg` hack from `symbolicExtent`.
401-
if (arg >= 5)
402-
return 0;
403-
int *mem = (int*)malloc(arg);
404-
mem[8] = -2;
405-
return mem;
406-
}
407-
408390
void symbolicIndex(int arg) {
409391
// expected-note@+2 {{Assuming 'arg' is >= 12}}
410392
// expected-note@+1 {{Taking true branch}}
@@ -426,9 +408,5 @@ int *nothingIsCertain(int x, int y) {
426408
// {{Access of 'int' element in the heap area at an overflowing index}}
427409
// but apparently the analyzer isn't smart enough to deduce this.
428410

429-
// Keep constraints alive. (Without this, the overeager garbage collection of
430-
// constraints would _also_ prevent the intended behavior in this testcase.)
431-
(void)x;
432-
433411
return mem;
434412
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,8 +1705,11 @@ void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration(
17051705
// For C++, we rely solely upon the one definition rule that says
17061706
// only one thing can exist at a given decl context. We ignore the
17071707
// file and line that things are declared on.
1708-
if (!die.IsValid() || !Language::LanguageIsCPlusPlus(language) ||
1709-
unique_typename.IsEmpty())
1708+
// FIXME: Rust pretends to be C++ for now, so use C++ name qualification rules
1709+
if (!Language::LanguageIsCPlusPlus(language) &&
1710+
language != lldb::eLanguageTypeRust)
1711+
return;
1712+
if (!die.IsValid() || unique_typename.IsEmpty())
17101713
return;
17111714
decl_declaration.Clear();
17121715
std::string qualified_name;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Helper library to traverse data emitted for Rust enums """
2+
from lldbsuite.test.lldbtest import *
3+
4+
DISCRIMINANT_MEMBER_NAME = "$discr$"
5+
VALUE_MEMBER_NAME = "value"
6+
7+
8+
class RustEnumValue:
9+
def __init__(self, value: lldb.SBValue):
10+
self.value = value
11+
12+
def getAllVariantTypes(self):
13+
result = []
14+
for i in range(self._inner().GetNumChildren()):
15+
result.append(self.getVariantByIndex(i).GetDisplayTypeName())
16+
return result
17+
18+
def _inner(self) -> lldb.SBValue:
19+
return self.value.GetChildAtIndex(0)
20+
21+
def getVariantByIndex(self, index):
22+
return (
23+
self._inner()
24+
.GetChildAtIndex(index)
25+
.GetChildMemberWithName(VALUE_MEMBER_NAME)
26+
)
27+
28+
@staticmethod
29+
def _getDiscriminantValueAsUnsigned(discr_sbvalue: lldb.SBValue):
30+
byte_size = discr_sbvalue.GetType().GetByteSize()
31+
error = lldb.SBError()
32+
33+
# when discriminant is u16 Clang emits 'unsigned char'
34+
# and LLDB seems to treat it as character type disalowing to call GetValueAsUnsigned
35+
if byte_size == 1:
36+
return discr_sbvalue.GetData().GetUnsignedInt8(error, 0)
37+
elif byte_size == 2:
38+
return discr_sbvalue.GetData().GetUnsignedInt16(error, 0)
39+
elif byte_size == 4:
40+
return discr_sbvalue.GetData().GetUnsignedInt32(error, 0)
41+
elif byte_size == 8:
42+
return discr_sbvalue.GetData().GetUnsignedInt64(error, 0)
43+
else:
44+
return discr_sbvalue.GetValueAsUnsigned()
45+
46+
def getCurrentVariantIndex(self):
47+
default_index = 0
48+
for i in range(self._inner().GetNumChildren()):
49+
variant: lldb.SBValue = self._inner().GetChildAtIndex(i)
50+
discr = variant.GetChildMemberWithName(DISCRIMINANT_MEMBER_NAME)
51+
if discr.IsValid():
52+
discr_unsigned_value = RustEnumValue._getDiscriminantValueAsUnsigned(
53+
discr
54+
)
55+
if variant.GetName() == f"$variant${discr_unsigned_value}":
56+
return discr_unsigned_value
57+
else:
58+
default_index = i
59+
return default_index
60+
61+
def getFields(self):
62+
result = []
63+
for i in range(self._inner().GetNumChildren()):
64+
type: lldb.SBType = self._inner().GetType()
65+
result.append(type.GetFieldAtIndex(i).GetName())
66+
return result
67+
68+
def getCurrentValue(self) -> lldb.SBValue:
69+
return self.getVariantByIndex(self.getCurrentVariantIndex())
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Test that lldb recognizes enum variant emitted by Rust compiler """
2+
import logging
3+
4+
import lldb
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
from RustEnumValue import RustEnumValue
8+
9+
10+
class TestRustEnumStructs(TestBase):
11+
def setUp(self):
12+
TestBase.setUp(self)
13+
src_dir = self.getSourceDir()
14+
yaml_path = os.path.join(src_dir, "main.yaml")
15+
obj_path = self.getBuildArtifact("main.o")
16+
self.yaml2obj(yaml_path, obj_path)
17+
self.dbg.CreateTarget(obj_path)
18+
19+
def getFromGlobal(self, name):
20+
values = self.target().FindGlobalVariables(name, 1)
21+
self.assertEqual(values.GetSize(), 1)
22+
return RustEnumValue(values[0])
23+
24+
def test_enum_instance(self):
25+
# static ENUM_INSTANCE: A = A::A(B::B(10));
26+
value = self.getFromGlobal("ENUM_INSTANCE").getCurrentValue()
27+
self.assertEqual(value.GetType().GetDisplayTypeName(), "main::A::A")
28+
29+
value_b = RustEnumValue(value.GetChildAtIndex(0))
30+
self.assertEqual(
31+
value_b.getCurrentValue()
32+
.GetChildAtIndex(0)
33+
.GetData()
34+
.GetUnsignedInt8(lldb.SBError(), 0),
35+
10,
36+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// Command:
2+
/// rustc -g --emit=obj --crate-type=bin -C panic=abort -C link-arg=-nostdlib main.rs && obj2yaml main.o -o main.yaml
3+
4+
pub enum A {
5+
A(B),
6+
}
7+
8+
pub enum B {
9+
B(u8),
10+
}
11+
12+
static ENUM_INSTANCE: A = A::A(B::B(10));
13+
14+
pub fn main() {
15+
}

0 commit comments

Comments
 (0)