Skip to content

Commit 22968c8

Browse files
committed
Produce a summary for non-decodable strings.
Currently when LLDB encounters an uninitialized string the summary formatter will fail and the user sees something like: ``` (String) s = { _guts = { _object = (_countAndFlagsBits = 18374403900871474942, _object = 0xfefefefefefefefe) } } ``` with this patch this becomes (String) s = <could not decode string: unexpected discriminator>
1 parent 4b0b1f9 commit 22968c8

File tree

4 files changed

+76
-26
lines changed

4 files changed

+76
-26
lines changed

lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,25 @@ static bool makeStringGutsSummary(
135135
static ConstString g__storage("_storage");
136136
static ConstString g__value("_value");
137137

138+
auto error = [&](std::string message) {
139+
stream << "<cannot decode string: " << message << ">";
140+
return true;
141+
};
142+
138143
ProcessSP process(valobj.GetProcessSP());
139144
if (!process)
140-
return false;
145+
return error("no live process");
141146

142147
auto ptrSize = process->GetAddressByteSize();
143148

144149
auto object_sp = valobj.GetChildMemberWithName(g__object, true);
145150
if (!object_sp)
146-
return false;
151+
return error("unexpected layout");
147152

148153
// We retrieve String contents by first extracting the
149154
// platform-independent 128-bit raw value representation from
150155
// _StringObject, then interpreting that.
151-
Status error;
156+
Status status;
152157
uint64_t raw0;
153158
uint64_t raw1;
154159

@@ -160,12 +165,12 @@ static bool makeStringGutsSummary(
160165
auto countAndFlagsBits = object_sp->GetChildAtNamePath(
161166
{g__countAndFlagsBits, g__value});
162167
if (!countAndFlagsBits)
163-
return false;
168+
return error("unexpected layout");
164169
raw0 = countAndFlagsBits->GetValueAsUnsigned(0);
165170

166171
auto object = object_sp->GetChildMemberWithName(g__object, true);
167172
if (!object)
168-
return false;
173+
return error("unexpected layout (object)");
169174
raw1 = object->GetValueAsUnsigned(0);
170175
} else if (ptrSize == 4) {
171176
// On 32-bit platforms, we emulate what `_StringObject.rawBits`
@@ -179,23 +184,23 @@ static bool makeStringGutsSummary(
179184

180185
auto count_sp = object_sp->GetChildAtNamePath({g__count, g__value});
181186
if (!count_sp)
182-
return false;
187+
return error("unexpected layout (count)");
183188
uint64_t count = count_sp->GetValueAsUnsigned(0);
184189

185190
auto discriminator_sp =
186191
object_sp->GetChildAtNamePath({g__discriminator, g__value});
187192
if (!discriminator_sp)
188-
return false;
193+
return error("unexpected layout (discriminator)");
189194
uint64_t discriminator = discriminator_sp->GetValueAsUnsigned(0) & 0xff;
190195

191196
auto flags_sp = object_sp->GetChildAtNamePath({g__flags, g__value});
192197
if (!flags_sp)
193-
return false;
198+
return error("unexpected layout (flags)");
194199
uint64_t flags = flags_sp->GetValueAsUnsigned(0) & 0xffff;
195200

196201
auto variant_sp = object_sp->GetChildMemberWithName(g__variant, true);
197202
if (!variant_sp)
198-
return false;
203+
return error("unexpected layout (variant)");
199204

200205
llvm::StringRef variantCase = variant_sp->GetValueAsCString();
201206

@@ -208,18 +213,18 @@ static bool makeStringGutsSummary(
208213
static ConstString g_bridged("bridged");
209214
auto anyobject_sp = variant_sp->GetChildMemberWithName(g_bridged, true);
210215
if (!anyobject_sp)
211-
return false;
216+
return error("unexpected layout (bridged)");
212217
payload_sp = anyobject_sp->GetChildAtIndex(0, true); // "instance"
213218
} else {
214-
// Unknown variant.
215-
return false;
219+
return error("unknown variant");
216220
}
217221
if (!payload_sp)
218-
return false;
222+
return error("no payload");
223+
219224
uint64_t pointerBits = payload_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
220225

221226
if (pointerBits == LLDB_INVALID_ADDRESS)
222-
return false;
227+
return error("invalid payload");
223228

224229
if ((discriminator & 0xB0) == 0xA0) {
225230
raw0 = count | (pointerBits << 32);
@@ -229,8 +234,7 @@ static bool makeStringGutsSummary(
229234
raw1 = pointerBits | (discriminator << 56);
230235
}
231236
} else {
232-
lldbassert(false && "Unsupported pointer bit-width");
233-
return false;
237+
return error("unsupported pointer size");
234238
}
235239

236240
// Copied from StringObject.swift
@@ -306,7 +310,7 @@ static bool makeStringGutsSummary(
306310
uint64_t count = (raw1 >> 56) & 0b1111;
307311
uint64_t maxCount = (ptrSize == 8 ? 15 : 10);
308312
if (count > maxCount)
309-
return false;
313+
return error("count > maxCount");
310314

311315
uint64_t rawBuffer[2] = {raw0, raw1};
312316
auto *buffer = (uint8_t *)&rawBuffer;
@@ -326,10 +330,16 @@ static bool makeStringGutsSummary(
326330
uint64_t count = raw0 & 0x0000FFFFFFFFFFFF;
327331
uint16_t flags = raw0 >> 48;
328332
lldb::addr_t objectAddress = (raw1 & 0x0FFFFFFFFFFFFFFF);
333+
// Catch a zero-initialized string.
334+
if (!objectAddress) {
335+
stream << "<uninitialized>";
336+
return true;
337+
}
338+
329339
if ((flags & 0x1000) != 0) { // Tail-allocated / biased address
330340
// Tail-allocation is only for natively stored or literals.
331341
if ((discriminator & 0b0111'0000) != 0)
332-
return false;
342+
return error("unexpected discriminator");
333343
uint64_t bias = (ptrSize == 8 ? 32 : 20);
334344
auto address = objectAddress + bias;
335345
applySlice(address, count, slice);
@@ -344,9 +354,9 @@ static bool makeStringGutsSummary(
344354
return false;
345355
uint64_t startOffset = (ptrSize == 8 ? 24 : 12);
346356
auto address = objectAddress + startOffset;
347-
lldb::addr_t start = process->ReadPointerFromMemory(address, error);
348-
if (error.Fail())
349-
return false;
357+
lldb::addr_t start = process->ReadPointerFromMemory(address, status);
358+
if (status.Fail())
359+
return error(status.AsCString());
350360

351361
applySlice(address, count, slice);
352362
return readStringFromAddress(
@@ -355,13 +365,13 @@ static bool makeStringGutsSummary(
355365

356366
// Native/shared strings should already have been handled.
357367
if ((discriminator & 0b0111'0000) == 0)
358-
return false;
368+
return error("unexpected discriminator");
359369

360370
if ((discriminator & 0b1110'0000) == 0b0100'0000) { // 010xxxxx: Bridged
361371
TypeSystemClangSP clang_ts_sp =
362372
ScratchTypeSystemClang::GetForTarget(process->GetTarget());
363373
if (!clang_ts_sp)
364-
return false;
374+
return error("no Clang type system");
365375

366376
CompilerType id_type = clang_ts_sp->GetBasicType(lldb::eBasicTypeObjCID);
367377

@@ -371,19 +381,19 @@ static bool makeStringGutsSummary(
371381
auto nsstring = ValueObject::CreateValueObjectFromData(
372382
"nsstring", DE, valobj.GetExecutionContextRef(), id_type);
373383
if (!nsstring || nsstring->GetError().Fail())
374-
return false;
384+
return error("could not create NSString value object");
375385

376386
return NSStringSummaryProvider(*nsstring.get(), stream, summary_options);
377387
}
378388

379389
if ((discriminator & 0b1111'1000) == 0b0001'1000) { // 0001xxxx: Foreign
380390
// Not currently generated: Foreign non-bridged strings are not currently
381391
// used in Swift.
382-
return false;
392+
return error("unexpected discriminator");
383393
}
384394

385395
// Invalid discriminator.
386-
return false;
396+
return error("invalid discriminator");
387397
}
388398

389399
bool lldb_private::formatters::swift::StringGuts_SummaryProvider(
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import unittest2
6+
7+
class TestSwiftTuple(TestBase):
8+
NO_DEBUG_INFO_TESTCASE = True
9+
@swiftTest
10+
def test(self):
11+
"""Test the String formatter under adverse conditions"""
12+
self.build()
13+
lldbutil.run_to_source_breakpoint(
14+
self, 'break here', lldb.SBFileSpec('main.swift'))
15+
16+
# FIXME: It would be even better if this were an error.
17+
self.expect("frame variable zero", substrs=['<uninitialized>'])
18+
self.expect("frame variable random", substrs=['cannot decode string'])
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
func main() {
2+
var zero : String = "zero"
3+
withUnsafeMutablePointer(to: &zero) {
4+
$0.withMemoryRebound(to: UInt64.self, capacity: 2) { raw in
5+
raw[0] = 0
6+
raw[1] = 0
7+
}
8+
}
9+
var random : String = "random"
10+
withUnsafeMutablePointer(to: &random) {
11+
$0.withMemoryRebound(to: UInt64.self, capacity: 2) { raw in
12+
raw[0] = 0xfefefefefefefefe
13+
raw[1] = 0xfefefefefefefefe
14+
}
15+
}
16+
print("break here")
17+
}
18+
19+
main()

0 commit comments

Comments
 (0)