Skip to content

Commit bcb4baf

Browse files
author
git apple-llvm automerger
committed
Merge commit 'f2c339ca8b76' from apple/stable/20200714 into swift/main
2 parents 9ee130a + f2c339c commit bcb4baf

File tree

4 files changed

+144
-15
lines changed

4 files changed

+144
-15
lines changed

lldb/include/lldb/Utility/ReproducerInstrumentation.h

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/Support/ErrorHandling.h"
1818

1919
#include <map>
20+
#include <thread>
2021
#include <type_traits>
2122

2223
template <typename T,
@@ -78,6 +79,13 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
7879
// is initialized or enabled.
7980
// #define LLDB_REPRO_INSTR_TRACE
8081

82+
#ifdef LLDB_REPRO_INSTR_TRACE
83+
inline llvm::raw_ostream &this_thread_id() {
84+
size_t tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
85+
return llvm::errs().write_hex(tid) << " :: ";
86+
}
87+
#endif
88+
8189
#define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \
8290
R.Register<Class * Signature>(&construct<Class Signature>::record, "", \
8391
#Class, #Class, #Signature)
@@ -325,6 +333,7 @@ class Deserializer {
325333
}
326334

327335
template <typename T> const T &HandleReplayResult(const T &t) {
336+
CheckSequence(Deserialize<unsigned>());
328337
unsigned result = Deserialize<unsigned>();
329338
if (is_trivially_serializable<T>::value)
330339
return t;
@@ -334,6 +343,7 @@ class Deserializer {
334343

335344
/// Store the returned value in the index-to-object mapping.
336345
template <typename T> T &HandleReplayResult(T &t) {
346+
CheckSequence(Deserialize<unsigned>());
337347
unsigned result = Deserialize<unsigned>();
338348
if (is_trivially_serializable<T>::value)
339349
return t;
@@ -343,6 +353,7 @@ class Deserializer {
343353

344354
/// Store the returned value in the index-to-object mapping.
345355
template <typename T> T *HandleReplayResult(T *t) {
356+
CheckSequence(Deserialize<unsigned>());
346357
unsigned result = Deserialize<unsigned>();
347358
if (is_trivially_serializable<T>::value)
348359
return t;
@@ -352,6 +363,7 @@ class Deserializer {
352363
/// All returned types are recorded, even when the function returns a void.
353364
/// The latter requires special handling.
354365
void HandleReplayResultVoid() {
366+
CheckSequence(Deserialize<unsigned>());
355367
unsigned result = Deserialize<unsigned>();
356368
assert(result == 0);
357369
(void)result;
@@ -361,6 +373,10 @@ class Deserializer {
361373
return m_index_to_object.GetAllObjects();
362374
}
363375

376+
void SetExpectedSequence(unsigned sequence) {
377+
m_expected_sequence = sequence;
378+
}
379+
364380
private:
365381
template <typename T> T Read(ValueTag) {
366382
assert(HasData(sizeof(T)));
@@ -402,11 +418,17 @@ class Deserializer {
402418
return *(new UnderlyingT(Deserialize<UnderlyingT>()));
403419
}
404420

421+
/// Verify that the given sequence number matches what we expect.
422+
void CheckSequence(unsigned sequence);
423+
405424
/// Mapping of indices to objects.
406425
IndexToObject m_index_to_object;
407426

408427
/// Buffer containing the serialized data.
409428
llvm::StringRef m_buffer;
429+
430+
/// The result's expected sequence number.
431+
llvm::Optional<unsigned> m_expected_sequence;
410432
};
411433

412434
/// Partial specialization for C-style strings. We read the string value
@@ -600,8 +622,8 @@ class Serializer {
600622
/// objects (in which case we serialize their index).
601623
template <typename T> void Serialize(T *t) {
602624
#ifdef LLDB_REPRO_INSTR_TRACE
603-
llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
604-
<< stringify_args(t) << "\n";
625+
this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
626+
<< stringify_args(t) << "\n";
605627
#endif
606628
if (std::is_fundamental<T>::value) {
607629
Serialize(*t);
@@ -616,8 +638,8 @@ class Serializer {
616638
/// to objects (in which case we serialize their index).
617639
template <typename T> void Serialize(T &t) {
618640
#ifdef LLDB_REPRO_INSTR_TRACE
619-
llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
620-
<< stringify_args(t) << "\n";
641+
this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
642+
<< stringify_args(t) << "\n";
621643
#endif
622644
if (is_trivially_serializable<T>::value) {
623645
m_stream.write(reinterpret_cast<const char *>(&t), sizeof(T));
@@ -637,8 +659,8 @@ class Serializer {
637659

638660
void Serialize(const char *t) {
639661
#ifdef LLDB_REPRO_INSTR_TRACE
640-
llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
641-
<< stringify_args(t) << "\n";
662+
this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
663+
<< stringify_args(t) << "\n";
642664
#endif
643665
const size_t size = t ? strlen(t) : std::numeric_limits<size_t>::max();
644666
Serialize(size);
@@ -737,19 +759,23 @@ class Recorder {
737759
if (!ShouldCapture())
738760
return;
739761

762+
std::lock_guard<std::mutex> lock(g_mutex);
763+
unsigned sequence = GetSequenceNumber();
740764
unsigned id = registry.GetID(uintptr_t(f));
741765

742766
#ifdef LLDB_REPRO_INSTR_TRACE
743767
Log(id);
744768
#endif
745769

770+
serializer.SerializeAll(sequence);
746771
serializer.SerializeAll(id);
747772
serializer.SerializeAll(args...);
748773

749774
if (std::is_class<typename std::remove_pointer<
750775
typename std::remove_reference<Result>::type>::type>::value) {
751776
m_result_recorded = false;
752777
} else {
778+
serializer.SerializeAll(sequence);
753779
serializer.SerializeAll(0);
754780
m_result_recorded = true;
755781
}
@@ -763,16 +789,20 @@ class Recorder {
763789
if (!ShouldCapture())
764790
return;
765791

792+
std::lock_guard<std::mutex> lock(g_mutex);
793+
unsigned sequence = GetSequenceNumber();
766794
unsigned id = registry.GetID(uintptr_t(f));
767795

768796
#ifdef LLDB_REPRO_INSTR_TRACE
769797
Log(id);
770798
#endif
771799

800+
serializer.SerializeAll(sequence);
772801
serializer.SerializeAll(id);
773802
serializer.SerializeAll(args...);
774803

775804
// Record result.
805+
serializer.SerializeAll(sequence);
776806
serializer.SerializeAll(0);
777807
m_result_recorded = true;
778808
}
@@ -798,7 +828,9 @@ class Recorder {
798828
if (update_boundary)
799829
UpdateBoundary();
800830
if (m_serializer && ShouldCapture()) {
831+
std::lock_guard<std::mutex> lock(g_mutex);
801832
assert(!m_result_recorded);
833+
m_serializer->SerializeAll(GetSequenceNumber());
802834
m_serializer->SerializeAll(r);
803835
m_result_recorded = true;
804836
}
@@ -808,6 +840,7 @@ class Recorder {
808840
template <typename Result, typename T>
809841
Result Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr,
810842
bool update_boundary) {
843+
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
811844
unsigned actual_id = registry.GetID(addr);
812845
unsigned id = deserializer.Deserialize<unsigned>();
813846
registry.CheckID(id, actual_id);
@@ -818,6 +851,7 @@ class Recorder {
818851
}
819852

820853
void Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr) {
854+
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
821855
unsigned actual_id = registry.GetID(addr);
822856
unsigned id = deserializer.Deserialize<unsigned>();
823857
registry.CheckID(id, actual_id);
@@ -833,7 +867,14 @@ class Recorder {
833867

834868
bool ShouldCapture() { return m_local_boundary; }
835869

870+
/// Mark the current thread as a private thread and pretend that everything
871+
/// on this thread is behind happening behind the API boundary.
872+
static void PrivateThread() { g_global_boundary = true; }
873+
836874
private:
875+
static unsigned GetNextSequenceNumber() { return g_sequence++; }
876+
unsigned GetSequenceNumber() const;
877+
837878
template <typename T> friend struct replay;
838879
void UpdateBoundary() {
839880
if (m_local_boundary)
@@ -842,8 +883,8 @@ class Recorder {
842883

843884
#ifdef LLDB_REPRO_INSTR_TRACE
844885
void Log(unsigned id) {
845-
llvm::errs() << "Recording " << id << ": " << m_pretty_func << " ("
846-
<< m_pretty_args << ")\n";
886+
this_thread_id() << "Recording " << id << ": " << m_pretty_func << " ("
887+
<< m_pretty_args << ")\n";
847888
}
848889
#endif
849890

@@ -859,8 +900,17 @@ class Recorder {
859900
/// Whether the return value was recorded explicitly.
860901
bool m_result_recorded;
861902

903+
/// The sequence number for this pair of function and result.
904+
unsigned m_sequence;
905+
862906
/// Whether we're currently across the API boundary.
863-
static bool g_global_boundary;
907+
static thread_local bool g_global_boundary;
908+
909+
/// Global mutex to protect concurrent access.
910+
static std::mutex g_mutex;
911+
912+
/// Unique, monotonically increasing sequence number.
913+
static std::atomic<unsigned> g_sequence;
864914
};
865915

866916
/// To be used as the "Runtime ID" of a constructor. It also invokes the
@@ -1002,6 +1052,7 @@ struct invoke_char_ptr<Result (Class::*)(Args...) const> {
10021052

10031053
static Result replay(Recorder &recorder, Deserializer &deserializer,
10041054
Registry &registry, char *str) {
1055+
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
10051056
deserializer.Deserialize<unsigned>();
10061057
Class *c = deserializer.Deserialize<Class *>();
10071058
deserializer.Deserialize<const char *>();
@@ -1023,6 +1074,7 @@ struct invoke_char_ptr<Result (Class::*)(Args...)> {
10231074

10241075
static Result replay(Recorder &recorder, Deserializer &deserializer,
10251076
Registry &registry, char *str) {
1077+
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
10261078
deserializer.Deserialize<unsigned>();
10271079
Class *c = deserializer.Deserialize<Class *>();
10281080
deserializer.Deserialize<const char *>();
@@ -1043,6 +1095,7 @@ struct invoke_char_ptr<Result (*)(Args...)> {
10431095

10441096
static Result replay(Recorder &recorder, Deserializer &deserializer,
10451097
Registry &registry, char *str) {
1098+
deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
10461099
deserializer.Deserialize<unsigned>();
10471100
deserializer.Deserialize<const char *>();
10481101
size_t l = deserializer.Deserialize<size_t>();

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "lldb/Interpreter/CommandReturnObject.h"
3333
#include "lldb/Target/Thread.h"
3434
#include "lldb/Target/ThreadPlan.h"
35+
#include "lldb/Utility/ReproducerInstrumentation.h"
3536
#include "lldb/Utility/Timer.h"
3637
#include "llvm/ADT/STLExtras.h"
3738
#include "llvm/ADT/StringRef.h"
@@ -430,6 +431,7 @@ ScriptInterpreterPythonImpl::Locker::Locker(
430431
: ScriptInterpreterLocker(),
431432
m_teardown_session((on_leave & TearDownSession) == TearDownSession),
432433
m_python_interpreter(py_interpreter) {
434+
repro::Recorder::PrivateThread();
433435
DoAcquireLock();
434436
if ((on_entry & InitSession) == InitSession) {
435437
if (!DoInitSession(on_entry, in, out, err)) {

lldb/source/Utility/ReproducerInstrumentation.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "lldb/Utility/ReproducerInstrumentation.h"
1010
#include "lldb/Utility/Reproducer.h"
11+
#include <limits>
1112
#include <stdio.h>
1213
#include <stdlib.h>
1314
#include <thread>
@@ -84,6 +85,16 @@ template <> const char **Deserializer::Deserialize<const char **>() {
8485
return r;
8586
}
8687

88+
void Deserializer::CheckSequence(unsigned sequence) {
89+
if (m_expected_sequence && *m_expected_sequence != sequence)
90+
llvm::report_fatal_error(
91+
"The result does not match the preceding "
92+
"function. This is probably the result of concurrent "
93+
"use of the SB API during capture, which is currently not "
94+
"supported.");
95+
m_expected_sequence.reset();
96+
}
97+
8798
bool Registry::Replay(const FileSpec &file) {
8899
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
89100
if (auto err = error_or_file.getError())
@@ -107,6 +118,7 @@ bool Registry::Replay(Deserializer &deserializer) {
107118
setvbuf(stdout, nullptr, _IONBF, 0);
108119

109120
while (deserializer.HasData(1)) {
121+
unsigned sequence = deserializer.Deserialize<unsigned>();
110122
unsigned id = deserializer.Deserialize<unsigned>();
111123

112124
#ifndef LLDB_REPRO_INSTR_TRACE
@@ -115,6 +127,7 @@ bool Registry::Replay(Deserializer &deserializer) {
115127
llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
116128
#endif
117129

130+
deserializer.SetExpectedSequence(sequence);
118131
GetReplayer(id)->operator()(deserializer);
119132
}
120133

@@ -181,21 +194,24 @@ unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {
181194

182195
Recorder::Recorder()
183196
: m_serializer(nullptr), m_pretty_func(), m_pretty_args(),
184-
m_local_boundary(false), m_result_recorded(true) {
197+
m_local_boundary(false), m_result_recorded(true),
198+
m_sequence(std::numeric_limits<unsigned>::max()) {
185199
if (!g_global_boundary) {
186200
g_global_boundary = true;
187201
m_local_boundary = true;
202+
m_sequence = GetNextSequenceNumber();
188203
}
189204
}
190205

191206
Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args)
192207
: m_serializer(nullptr), m_pretty_func(pretty_func),
193208
m_pretty_args(pretty_args), m_local_boundary(false),
194-
m_result_recorded(true) {
209+
m_result_recorded(true),
210+
m_sequence(std::numeric_limits<unsigned>::max()) {
195211
if (!g_global_boundary) {
196212
g_global_boundary = true;
197213
m_local_boundary = true;
198-
214+
m_sequence = GetNextSequenceNumber();
199215
LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})",
200216
m_pretty_func, m_pretty_args);
201217
}
@@ -206,6 +222,11 @@ Recorder::~Recorder() {
206222
UpdateBoundary();
207223
}
208224

225+
unsigned Recorder::GetSequenceNumber() const {
226+
assert(m_sequence != std::numeric_limits<unsigned>::max());
227+
return m_sequence;
228+
}
229+
209230
void InstrumentationData::Initialize(Serializer &serializer,
210231
Registry &registry) {
211232
InstanceImpl().emplace(serializer, registry);
@@ -227,4 +248,6 @@ llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
227248
return g_instrumentation_data;
228249
}
229250

230-
bool lldb_private::repro::Recorder::g_global_boundary;
251+
thread_local bool lldb_private::repro::Recorder::g_global_boundary = false;
252+
std::atomic<unsigned> lldb_private::repro::Recorder::g_sequence;
253+
std::mutex lldb_private::repro::Recorder::g_mutex;

0 commit comments

Comments
 (0)