[Lldb-commits] [lldb] e687aa8 - [lldb/Reproducers] Fix passive replay for (char*, size_t) functions.

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Mon Apr 20 13:26:24 PDT 2020


Author: Jonas Devlieghere
Date: 2020-04-20T13:26:11-07:00
New Revision: e687aa82826385454a3d3a192a46b7a9d4eddae1

URL: https://github.com/llvm/llvm-project/commit/e687aa82826385454a3d3a192a46b7a9d4eddae1
DIFF: https://github.com/llvm/llvm-project/commit/e687aa82826385454a3d3a192a46b7a9d4eddae1.diff

LOG: [lldb/Reproducers] Fix passive replay for (char*, size_t) functions.

Several SB API functions return strings using (char*, size_t) output
arguments. During capture, we serialize an empty string for the char*
because the memory can be uninitialized.

During active replay, we have custom replay redirects that ensure that
we don't override the buffer from which we're reading, but rather write
to a buffer on the heap with the given length. This is sufficient for
the active reproducer use case, where we only care about the side
effects of the API calls, not the values actually returned.

This approach does not not work for passive replay because here we
ignore all the incoming arguments, and re-execute the current function
with the arguments deserialized from the reproducer. This means that
these function will update the deserialized copy of the arguments,
rather than whatever was passed in by the SWIG wrapper.

To solve this problem, this patch extends the reproducer instrumentation
to handle this special case for passive replay. We nog ignore the
replayer in the registry and the incoming char pointer, and instead
reinvoke the current method on the deserialized class, and populate the
output argument.

Differential revision: https://reviews.llvm.org/D77759

Added: 
    

Modified: 
    lldb/include/lldb/Utility/ReproducerInstrumentation.h
    lldb/source/API/SBDebugger.cpp
    lldb/source/API/SBFileSpec.cpp
    lldb/source/API/SBProcess.cpp
    lldb/source/API/SBStructuredData.cpp
    lldb/source/API/SBThread.cpp
    lldb/unittests/Utility/ReproducerInstrumentationTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Utility/ReproducerInstrumentation.h b/lldb/include/lldb/Utility/ReproducerInstrumentation.h
index 1e027c3952fe..346eac52501a 100644
--- a/lldb/include/lldb/Utility/ReproducerInstrumentation.h
+++ b/lldb/include/lldb/Utility/ReproducerInstrumentation.h
@@ -97,25 +97,25 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
   R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::record,   \
              #Result, #Class, #Method, #Signature)
 
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(Result, Class, Method)          \
+#define LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(Result, Class, Method)            \
   R.Register(                                                                  \
       &invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::record,   \
-      &char_ptr_redirect<Result (*)(char *, size_t)>::method<(                 \
-          &Class::Method)>::record,                                            \
+      &invoke_char_ptr<Result (*)(char *,                                      \
+                                  size_t)>::method<(&Class::Method)>::record,  \
       #Result, #Class, #Method, "(char*, size_t");
 
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT(Result, Class, Method)                 \
+#define LLDB_REGISTER_CHAR_PTR_METHOD(Result, Class, Method)                   \
   R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<(              \
                  &Class::Method)>::record,                                     \
-             &char_ptr_redirect<Result (Class::*)(char *, size_t)>::method<(   \
+             &invoke_char_ptr<Result (Class::*)(char *, size_t)>::method<(     \
                  &Class::Method)>::record,                                     \
              #Result, #Class, #Method, "(char*, size_t");
 
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(Result, Class, Method)           \
+#define LLDB_REGISTER_CHAR_PTR_METHOD_CONST(Result, Class, Method)             \
   R.Register(&invoke<Result (Class::*)(char *, size_t)                         \
                          const>::method<(&Class::Method)>::record,             \
-             &char_ptr_redirect<Result (Class::*)(char *, size_t)              \
-                                    const>::method<(&Class::Method)>::record,  \
+             &invoke_char_ptr<Result (Class::*)(char *, size_t)                \
+                                  const>::method<(&Class::Method)>::record,    \
              #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_CONSTRUCT_(T, Class, ...)                                         \
@@ -167,6 +167,40 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
 #define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method)               \
   LLDB_RECORD_(Result (*)(), (&Class::Method), lldb_private::repro::EmptyArg())
 
+#define LLDB_RECORD_CHAR_PTR_(T1, T2, StrOut, ...)                             \
+  lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,                \
+                                          stringify_args(__VA_ARGS__));        \
+  if (lldb_private::repro::InstrumentationData _data =                         \
+          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::invoke<T1>::method<(T2)>::record, \
+                       __VA_ARGS__);                                           \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::invoke_char_ptr<T1>::method<T2>::replay(   \
+            _recorder, *_deserializer, _data.GetRegistry(), StrOut);           \
+      }                                                                        \
+    }                                                                          \
+  }
+
+#define LLDB_RECORD_CHAR_PTR_METHOD(Result, Class, Method, Signature, StrOut,  \
+                                    ...)                                       \
+  LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature, (&Class::Method), StrOut,  \
+                        this, __VA_ARGS__)
+
+#define LLDB_RECORD_CHAR_PTR_METHOD_CONST(Result, Class, Method, Signature,    \
+                                          StrOut, ...)                         \
+  LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature const, (&Class::Method),    \
+                        StrOut, this, __VA_ARGS__)
+
+#define LLDB_RECORD_CHAR_PTR_STATIC_METHOD(Result, Class, Method, Signature,   \
+                                           StrOut, ...)                        \
+  LLDB_RECORD_CHAR_PTR_(Result(*) Signature, (&Class::Method), StrOut,         \
+                        __VA_ARGS__)
+
 #define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true);
 
 /// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record
@@ -946,34 +980,79 @@ template <typename... Args> struct invoke<void (*)(Args...)> {
   };
 };
 
-template <typename Signature> struct char_ptr_redirect;
-template <typename Result, typename Class>
-struct char_ptr_redirect<Result (Class::*)(char *, size_t) const> {
-  template <Result (Class::*m)(char *, size_t) const> struct method {
+/// Special handling for functions returning strings as (char*, size_t).
+/// {
+
+/// For inline replay, we ignore the arguments and use the ones from the
+/// serializer instead. This doesn't work for methods that use a char* and a
+/// size to return a string. For one these functions have a custom replayer to
+/// prevent override the input buffer. Furthermore, the template-generated
+/// deserialization is not easy to hook into.
+///
+/// The specializations below hand-implement the serialization logic for the
+/// inline replay. Instead of using the function from the registry, it uses the
+/// one passed into the macro.
+template <typename Signature> struct invoke_char_ptr;
+template <typename Result, typename Class, typename... Args>
+struct invoke_char_ptr<Result (Class::*)(Args...) const> {
+  template <Result (Class::*m)(Args...) const> struct method {
     static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
+
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, char *str) {
+      deserializer.Deserialize<unsigned>();
+      Class *c = deserializer.Deserialize<Class *>();
+      deserializer.Deserialize<const char *>();
+      size_t l = deserializer.Deserialize<size_t>();
+      return recorder.ReplayResult(
+          std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
+    }
   };
 };
-template <typename Result, typename Class>
-struct char_ptr_redirect<Result (Class::*)(char *, size_t)> {
-  template <Result (Class::*m)(char *, size_t)> struct method {
+
+template <typename Signature> struct invoke_char_ptr;
+template <typename Result, typename Class, typename... Args>
+struct invoke_char_ptr<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {
     static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
+
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, char *str) {
+      deserializer.Deserialize<unsigned>();
+      Class *c = deserializer.Deserialize<Class *>();
+      deserializer.Deserialize<const char *>();
+      size_t l = deserializer.Deserialize<size_t>();
+      return recorder.ReplayResult(
+          std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
+    }
   };
 };
-template <typename Result>
-struct char_ptr_redirect<Result (*)(char *, size_t)> {
-  template <Result (*m)(char *, size_t)> struct method {
+
+template <typename Result, typename... Args>
+struct invoke_char_ptr<Result (*)(Args...)> {
+  template <Result (*m)(Args...)> struct method {
     static Result record(char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (*m)(buffer, l);
     }
+
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry, char *str) {
+      deserializer.Deserialize<unsigned>();
+      deserializer.Deserialize<const char *>();
+      size_t l = deserializer.Deserialize<size_t>();
+      return recorder.ReplayResult(
+          std::move(deserializer.HandleReplayResult((*m)(str, l))), true);
+    }
   };
 };
+/// }
 
 } // namespace repro
 } // namespace lldb_private

diff  --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 5654ec59b4fd..bd5e256de2ac 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -596,8 +596,9 @@ SBSourceManager SBDebugger::GetSourceManager() {
 }
 
 bool SBDebugger::GetDefaultArchitecture(char *arch_name, size_t arch_name_len) {
-  LLDB_RECORD_STATIC_METHOD(bool, SBDebugger, GetDefaultArchitecture,
-                            (char *, size_t), "", arch_name_len);
+  LLDB_RECORD_CHAR_PTR_STATIC_METHOD(bool, SBDebugger, GetDefaultArchitecture,
+                                     (char *, size_t), arch_name, "",
+                                     arch_name_len);
 
   if (arch_name && arch_name_len) {
     ArchSpec default_arch = Target::GetDefaultArchitecture();
@@ -1668,8 +1669,8 @@ template <> void RegisterMethods<SBDebugger>(Registry &R) {
                  FileSP)>::method<&SBDebugger::SetErrorFile>::record,
              &SetFileRedirect);
 
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(bool, SBDebugger,
-                                         GetDefaultArchitecture);
+  LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(bool, SBDebugger,
+                                       GetDefaultArchitecture);
 
   LLDB_REGISTER_CONSTRUCTOR(SBDebugger, ());
   LLDB_REGISTER_CONSTRUCTOR(SBDebugger, (const lldb::DebuggerSP &));

diff  --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp
index e9b3da94b1e2..7bfb665df4fb 100644
--- a/lldb/source/API/SBFileSpec.cpp
+++ b/lldb/source/API/SBFileSpec.cpp
@@ -143,8 +143,8 @@ void SBFileSpec::SetDirectory(const char *directory) {
 }
 
 uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const {
-  LLDB_RECORD_METHOD_CONST(uint32_t, SBFileSpec, GetPath, (char *, size_t), "",
-                           dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD_CONST(uint32_t, SBFileSpec, GetPath,
+                                    (char *, size_t), dst_path, "", dst_len);
 
   uint32_t result = m_opaque_up->GetPath(dst_path, dst_len);
 
@@ -216,7 +216,7 @@ void RegisterMethods<SBFileSpec>(Registry &R) {
   LLDB_REGISTER_METHOD_CONST(bool, SBFileSpec, GetDescription,
                              (lldb::SBStream &));
   LLDB_REGISTER_METHOD(void, SBFileSpec, AppendPathComponent, (const char *));
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(uint32_t, SBFileSpec, GetPath);
+  LLDB_REGISTER_CHAR_PTR_METHOD_CONST(uint32_t, SBFileSpec, GetPath);
 }
 
 }

diff  --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index ab216015741f..d7b7fd7cacad 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -271,8 +271,8 @@ size_t SBProcess::PutSTDIN(const char *src, size_t src_len) {
 }
 
 size_t SBProcess::GetSTDOUT(char *dst, size_t dst_len) const {
-  LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetSTDOUT, (char *, size_t), "",
-                           dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT,
+                                    (char *, size_t), dst, "", dst_len);
 
   size_t bytes_read = 0;
   ProcessSP process_sp(GetSP());
@@ -285,8 +285,8 @@ size_t SBProcess::GetSTDOUT(char *dst, size_t dst_len) const {
 }
 
 size_t SBProcess::GetSTDERR(char *dst, size_t dst_len) const {
-  LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetSTDERR, (char *, size_t), "",
-                           dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR,
+                                    (char *, size_t), dst, "", dst_len);
 
   size_t bytes_read = 0;
   ProcessSP process_sp(GetSP());
@@ -299,8 +299,8 @@ size_t SBProcess::GetSTDERR(char *dst, size_t dst_len) const {
 }
 
 size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
-  LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData,
-                           (char *, size_t), "", dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData,
+                                    (char *, size_t), dst, "", dst_len);
 
   size_t bytes_read = 0;
   ProcessSP process_sp(GetSP());
@@ -1440,9 +1440,9 @@ void RegisterMethods<SBProcess>(Registry &R) {
                        GetMemoryRegions, ());
   LLDB_REGISTER_METHOD(lldb::SBProcessInfo, SBProcess, GetProcessInfo, ());
 
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetSTDOUT);
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetSTDERR);
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetAsyncProfileData);
+  LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT);
+  LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR);
+  LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData);
 }
 
 }

diff  --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp
index 897ce9853a2b..2ae3005fd8d1 100644
--- a/lldb/source/API/SBStructuredData.cpp
+++ b/lldb/source/API/SBStructuredData.cpp
@@ -196,8 +196,8 @@ bool SBStructuredData::GetBooleanValue(bool fail_value) const {
 }
 
 size_t SBStructuredData::GetStringValue(char *dst, size_t dst_len) const {
-  LLDB_RECORD_METHOD_CONST(size_t, SBStructuredData, GetStringValue,
-                           (char *, size_t), "", dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBStructuredData, GetStringValue,
+                                    (char *, size_t), dst, "", dst_len);
 
   return (m_impl_up ? m_impl_up->GetStringValue(dst, dst_len) : 0);
 }
@@ -236,8 +236,7 @@ template <> void RegisterMethods<SBStructuredData>(Registry &R) {
                              (uint64_t));
   LLDB_REGISTER_METHOD_CONST(double, SBStructuredData, GetFloatValue, (double));
   LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, GetBooleanValue, (bool));
-  LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBStructuredData,
-                                        GetStringValue);
+  LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBStructuredData, GetStringValue);
 }
 
 } // namespace repro

diff  --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index c7786534076e..0d50aceee5e4 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -312,8 +312,8 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
 }
 
 size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
-  LLDB_RECORD_METHOD(size_t, SBThread, GetStopDescription, (char *, size_t), "",
-                     dst_len);
+  LLDB_RECORD_CHAR_PTR_METHOD(size_t, SBThread, GetStopDescription,
+                              (char *, size_t), dst, "", dst_len);
 
   std::unique_lock<std::recursive_mutex> lock;
   ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
@@ -1448,7 +1448,7 @@ void RegisterMethods<SBThread>(Registry &R) {
   LLDB_REGISTER_METHOD(lldb::SBThread, SBThread, GetCurrentExceptionBacktrace,
                        ());
   LLDB_REGISTER_METHOD(bool, SBThread, SafeToCallFunctions, ());
-  LLDB_REGISTER_CHAR_PTR_REDIRECT(size_t, SBThread, GetStopDescription);
+  LLDB_REGISTER_CHAR_PTR_METHOD(size_t, SBThread, GetStopDescription);
 }
 
 }

diff  --git a/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp b/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
index 02e4e7e3420b..1ed00a77249f 100644
--- a/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
+++ b/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
@@ -134,7 +134,7 @@ class InstrumentedFoo : public Instrumented {
   int C(float *c);
   float GetC();
   int D(const char *d) const;
-  void GetD(char *buffer, size_t length);
+  size_t GetD(char *buffer, size_t length);
   static void E(double e);
   double GetE();
   static int F();
@@ -257,10 +257,11 @@ int InstrumentedFoo::D(const char *d) const {
   return 2;
 }
 
-void InstrumentedFoo::GetD(char *buffer, size_t length) {
-  LLDB_RECORD_METHOD(void, InstrumentedFoo, GetD, (char *, size_t), buffer,
-                     length);
+size_t InstrumentedFoo::GetD(char *buffer, size_t length) {
+  LLDB_RECORD_CHAR_PTR_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t),
+                              buffer, "", length);
   ::snprintf(buffer, length, "%s", m_d.c_str());
+  return m_d.size();
 }
 
 void InstrumentedFoo::E(double e) {
@@ -374,7 +375,7 @@ TestingRegistry::TestingRegistry() {
   LLDB_REGISTER_METHOD(int, InstrumentedFoo, GetA, ());
   LLDB_REGISTER_METHOD(int &, InstrumentedFoo, GetB, ());
   LLDB_REGISTER_METHOD(float, InstrumentedFoo, GetC, ());
-  LLDB_REGISTER_METHOD(void, InstrumentedFoo, GetD, (char *, size_t));
+  LLDB_REGISTER_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t));
   LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
   LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
 }
@@ -814,6 +815,9 @@ TEST(PassiveReplayTest, InstrumentedFoo) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
   }
@@ -839,6 +843,9 @@ TEST(PassiveReplayTest, InstrumentedFoo) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
   }
@@ -920,6 +927,9 @@ TEST(PassiveReplayTest, InstrumentedBar) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 
@@ -951,6 +961,9 @@ TEST(PassiveReplayTest, InstrumentedBar) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 
@@ -985,6 +998,9 @@ TEST(PassiveReplayTest, InstrumentedBarRef) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 
@@ -1016,6 +1032,9 @@ TEST(PassiveReplayTest, InstrumentedBarRef) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 
@@ -1050,6 +1069,9 @@ TEST(PassiveReplayTest, InstrumentedBarPtr) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 
@@ -1081,6 +1103,9 @@ TEST(PassiveReplayTest, InstrumentedBarPtr) {
     EXPECT_EQ(foo.GetA(), 100);
     EXPECT_EQ(foo.GetB(), 200);
     EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    char buffer[100];
+    foo.GetD(buffer, 100);
+    EXPECT_STREQ(buffer, "bar");
     EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
     EXPECT_EQ(foo.GetF(), true);
 


        


More information about the lldb-commits mailing list