17
17
#include " llvm/Support/ErrorHandling.h"
18
18
19
19
#include < map>
20
+ #include < thread>
20
21
#include < type_traits>
21
22
22
23
template <typename T,
@@ -78,6 +79,13 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
78
79
// is initialized or enabled.
79
80
// #define LLDB_REPRO_INSTR_TRACE
80
81
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
+
81
89
#define LLDB_REGISTER_CONSTRUCTOR (Class, Signature ) \
82
90
R.Register<Class * Signature>(&construct<Class Signature>::record, " " , \
83
91
#Class, #Class, #Signature)
@@ -325,6 +333,7 @@ class Deserializer {
325
333
}
326
334
327
335
template <typename T> const T &HandleReplayResult (const T &t) {
336
+ CheckSequence (Deserialize<unsigned >());
328
337
unsigned result = Deserialize<unsigned >();
329
338
if (is_trivially_serializable<T>::value)
330
339
return t;
@@ -334,6 +343,7 @@ class Deserializer {
334
343
335
344
// / Store the returned value in the index-to-object mapping.
336
345
template <typename T> T &HandleReplayResult (T &t) {
346
+ CheckSequence (Deserialize<unsigned >());
337
347
unsigned result = Deserialize<unsigned >();
338
348
if (is_trivially_serializable<T>::value)
339
349
return t;
@@ -343,6 +353,7 @@ class Deserializer {
343
353
344
354
// / Store the returned value in the index-to-object mapping.
345
355
template <typename T> T *HandleReplayResult (T *t) {
356
+ CheckSequence (Deserialize<unsigned >());
346
357
unsigned result = Deserialize<unsigned >();
347
358
if (is_trivially_serializable<T>::value)
348
359
return t;
@@ -352,6 +363,7 @@ class Deserializer {
352
363
// / All returned types are recorded, even when the function returns a void.
353
364
// / The latter requires special handling.
354
365
void HandleReplayResultVoid () {
366
+ CheckSequence (Deserialize<unsigned >());
355
367
unsigned result = Deserialize<unsigned >();
356
368
assert (result == 0 );
357
369
(void )result;
@@ -361,6 +373,10 @@ class Deserializer {
361
373
return m_index_to_object.GetAllObjects ();
362
374
}
363
375
376
+ void SetExpectedSequence (unsigned sequence) {
377
+ m_expected_sequence = sequence;
378
+ }
379
+
364
380
private:
365
381
template <typename T> T Read (ValueTag) {
366
382
assert (HasData (sizeof (T)));
@@ -402,11 +418,17 @@ class Deserializer {
402
418
return *(new UnderlyingT (Deserialize<UnderlyingT>()));
403
419
}
404
420
421
+ // / Verify that the given sequence number matches what we expect.
422
+ void CheckSequence (unsigned sequence);
423
+
405
424
// / Mapping of indices to objects.
406
425
IndexToObject m_index_to_object;
407
426
408
427
// / Buffer containing the serialized data.
409
428
llvm::StringRef m_buffer;
429
+
430
+ // / The result's expected sequence number.
431
+ llvm::Optional<unsigned > m_expected_sequence;
410
432
};
411
433
412
434
// / Partial specialization for C-style strings. We read the string value
@@ -600,8 +622,8 @@ class Serializer {
600
622
// / objects (in which case we serialize their index).
601
623
template <typename T> void Serialize (T *t) {
602
624
#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 " ;
605
627
#endif
606
628
if (std::is_fundamental<T>::value) {
607
629
Serialize (*t);
@@ -616,8 +638,8 @@ class Serializer {
616
638
// / to objects (in which case we serialize their index).
617
639
template <typename T> void Serialize (T &t) {
618
640
#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 " ;
621
643
#endif
622
644
if (is_trivially_serializable<T>::value) {
623
645
m_stream.write (reinterpret_cast <const char *>(&t), sizeof (T));
@@ -637,8 +659,8 @@ class Serializer {
637
659
638
660
void Serialize (const char *t) {
639
661
#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 " ;
642
664
#endif
643
665
const size_t size = t ? strlen (t) : std::numeric_limits<size_t >::max ();
644
666
Serialize (size);
@@ -737,19 +759,23 @@ class Recorder {
737
759
if (!ShouldCapture ())
738
760
return ;
739
761
762
+ std::lock_guard<std::mutex> lock (g_mutex);
763
+ unsigned sequence = GetSequenceNumber ();
740
764
unsigned id = registry.GetID (uintptr_t (f));
741
765
742
766
#ifdef LLDB_REPRO_INSTR_TRACE
743
767
Log (id);
744
768
#endif
745
769
770
+ serializer.SerializeAll (sequence);
746
771
serializer.SerializeAll (id);
747
772
serializer.SerializeAll (args...);
748
773
749
774
if (std::is_class<typename std::remove_pointer<
750
775
typename std::remove_reference<Result>::type>::type>::value) {
751
776
m_result_recorded = false ;
752
777
} else {
778
+ serializer.SerializeAll (sequence);
753
779
serializer.SerializeAll (0 );
754
780
m_result_recorded = true ;
755
781
}
@@ -763,16 +789,20 @@ class Recorder {
763
789
if (!ShouldCapture ())
764
790
return ;
765
791
792
+ std::lock_guard<std::mutex> lock (g_mutex);
793
+ unsigned sequence = GetSequenceNumber ();
766
794
unsigned id = registry.GetID (uintptr_t (f));
767
795
768
796
#ifdef LLDB_REPRO_INSTR_TRACE
769
797
Log (id);
770
798
#endif
771
799
800
+ serializer.SerializeAll (sequence);
772
801
serializer.SerializeAll (id);
773
802
serializer.SerializeAll (args...);
774
803
775
804
// Record result.
805
+ serializer.SerializeAll (sequence);
776
806
serializer.SerializeAll (0 );
777
807
m_result_recorded = true ;
778
808
}
@@ -798,7 +828,9 @@ class Recorder {
798
828
if (update_boundary)
799
829
UpdateBoundary ();
800
830
if (m_serializer && ShouldCapture ()) {
831
+ std::lock_guard<std::mutex> lock (g_mutex);
801
832
assert (!m_result_recorded);
833
+ m_serializer->SerializeAll (GetSequenceNumber ());
802
834
m_serializer->SerializeAll (r);
803
835
m_result_recorded = true ;
804
836
}
@@ -808,6 +840,7 @@ class Recorder {
808
840
template <typename Result, typename T>
809
841
Result Replay (Deserializer &deserializer, Registry ®istry, uintptr_t addr,
810
842
bool update_boundary) {
843
+ deserializer.SetExpectedSequence (deserializer.Deserialize <unsigned >());
811
844
unsigned actual_id = registry.GetID (addr);
812
845
unsigned id = deserializer.Deserialize <unsigned >();
813
846
registry.CheckID (id, actual_id);
@@ -818,6 +851,7 @@ class Recorder {
818
851
}
819
852
820
853
void Replay (Deserializer &deserializer, Registry ®istry, uintptr_t addr) {
854
+ deserializer.SetExpectedSequence (deserializer.Deserialize <unsigned >());
821
855
unsigned actual_id = registry.GetID (addr);
822
856
unsigned id = deserializer.Deserialize <unsigned >();
823
857
registry.CheckID (id, actual_id);
@@ -833,7 +867,14 @@ class Recorder {
833
867
834
868
bool ShouldCapture () { return m_local_boundary; }
835
869
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
+
836
874
private:
875
+ static unsigned GetNextSequenceNumber () { return g_sequence++; }
876
+ unsigned GetSequenceNumber () const ;
877
+
837
878
template <typename T> friend struct replay ;
838
879
void UpdateBoundary () {
839
880
if (m_local_boundary)
@@ -842,8 +883,8 @@ class Recorder {
842
883
843
884
#ifdef LLDB_REPRO_INSTR_TRACE
844
885
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 " ;
847
888
}
848
889
#endif
849
890
@@ -859,8 +900,17 @@ class Recorder {
859
900
// / Whether the return value was recorded explicitly.
860
901
bool m_result_recorded;
861
902
903
+ // / The sequence number for this pair of function and result.
904
+ unsigned m_sequence;
905
+
862
906
// / 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;
864
914
};
865
915
866
916
// / 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> {
1002
1052
1003
1053
static Result replay (Recorder &recorder, Deserializer &deserializer,
1004
1054
Registry ®istry, char *str) {
1055
+ deserializer.SetExpectedSequence (deserializer.Deserialize <unsigned >());
1005
1056
deserializer.Deserialize <unsigned >();
1006
1057
Class *c = deserializer.Deserialize <Class *>();
1007
1058
deserializer.Deserialize <const char *>();
@@ -1023,6 +1074,7 @@ struct invoke_char_ptr<Result (Class::*)(Args...)> {
1023
1074
1024
1075
static Result replay (Recorder &recorder, Deserializer &deserializer,
1025
1076
Registry ®istry, char *str) {
1077
+ deserializer.SetExpectedSequence (deserializer.Deserialize <unsigned >());
1026
1078
deserializer.Deserialize <unsigned >();
1027
1079
Class *c = deserializer.Deserialize <Class *>();
1028
1080
deserializer.Deserialize <const char *>();
@@ -1043,6 +1095,7 @@ struct invoke_char_ptr<Result (*)(Args...)> {
1043
1095
1044
1096
static Result replay (Recorder &recorder, Deserializer &deserializer,
1045
1097
Registry ®istry, char *str) {
1098
+ deserializer.SetExpectedSequence (deserializer.Deserialize <unsigned >());
1046
1099
deserializer.Deserialize <unsigned >();
1047
1100
deserializer.Deserialize <const char *>();
1048
1101
size_t l = deserializer.Deserialize <size_t >();
0 commit comments