[trace-engine] Fix bug writing arguments within inline names.

Change-Id: I5cbaa3cec12c0423546e3e6db76d8bea9257cfea
diff --git a/system/ulib/trace-engine/context.cpp b/system/ulib/trace-engine/context.cpp
index 5fb2401..c92233a 100644
--- a/system/ulib/trace-engine/context.cpp
+++ b/system/ulib/trace-engine/context.cpp
@@ -7,12 +7,12 @@
 #include <magenta/compiler.h>
 #include <magenta/syscalls.h>
 
-#include <mx/process.h>
-#include <mx/thread.h>
 #include <fbl/algorithm.h>
 #include <fbl/atomic.h>
 #include <fbl/intrusive_hash_table.h>
 #include <fbl/unique_ptr.h>
+#include <mx/process.h>
+#include <mx/thread.h>
 #include <trace-engine/fields.h>
 
 namespace trace {
@@ -169,7 +169,7 @@
 
 size_t SizeOfEncodedStringRef(const trace_string_ref_t* string_ref) {
     return trace_is_inline_string_ref(string_ref)
-               ? Pad(string_ref->encoded_value & TRACE_ENCODED_STRING_REF_LENGTH_MASK)
+               ? Pad(trace_inline_string_ref_length(string_ref))
                : 0u;
 }
 
@@ -277,41 +277,41 @@
     Payload& WriteArg(const trace_arg_t* arg) {
         switch (arg->value.type) {
         case TRACE_ARG_NULL:
-            WriteArgumentHeader(ArgumentType::kNull, &arg->name_ref, 0u, 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kNull, &arg->name_ref, 0u, 0u);
             break;
         case TRACE_ARG_INT32:
-            WriteArgumentHeader(ArgumentType::kInt32, &arg->name_ref, 0u,
-                                Int32ArgumentFields::Value::Make(arg->value.int32_value));
+            WriteArgumentHeaderAndName(ArgumentType::kInt32, &arg->name_ref, 0u,
+                                       Int32ArgumentFields::Value::Make(arg->value.int32_value));
             break;
         case TRACE_ARG_UINT32:
-            WriteArgumentHeader(ArgumentType::kUint32, &arg->name_ref, 0u,
-                                Uint32ArgumentFields::Value::Make(arg->value.uint32_value));
+            WriteArgumentHeaderAndName(ArgumentType::kUint32, &arg->name_ref, 0u,
+                                       Uint32ArgumentFields::Value::Make(arg->value.uint32_value));
             break;
         case TRACE_ARG_INT64:
-            WriteArgumentHeader(ArgumentType::kInt64, &arg->name_ref, WordsToBytes(1), 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kInt64, &arg->name_ref, WordsToBytes(1), 0u);
             WriteInt64(arg->value.int64_value);
             break;
         case TRACE_ARG_UINT64:
-            WriteArgumentHeader(ArgumentType::kUint64, &arg->name_ref, WordsToBytes(1), 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kUint64, &arg->name_ref, WordsToBytes(1), 0u);
             WriteUint64(arg->value.uint64_value);
             break;
         case TRACE_ARG_DOUBLE:
-            WriteArgumentHeader(ArgumentType::kDouble, &arg->name_ref, WordsToBytes(1), 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kDouble, &arg->name_ref, WordsToBytes(1), 0u);
             WriteDouble(arg->value.double_value);
             break;
         case TRACE_ARG_STRING:
-            WriteArgumentHeader(ArgumentType::kString, &arg->name_ref,
-                                SizeOfEncodedStringRef(&arg->value.string_value_ref),
-                                StringArgumentFields::Index::Make(
-                                    arg->value.string_value_ref.encoded_value));
+            WriteArgumentHeaderAndName(ArgumentType::kString, &arg->name_ref,
+                                       SizeOfEncodedStringRef(&arg->value.string_value_ref),
+                                       StringArgumentFields::Index::Make(
+                                           arg->value.string_value_ref.encoded_value));
             WriteStringRef(&arg->value.string_value_ref);
             break;
         case TRACE_ARG_POINTER:
-            WriteArgumentHeader(ArgumentType::kPointer, &arg->name_ref, WordsToBytes(1), 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kPointer, &arg->name_ref, WordsToBytes(1), 0u);
             WriteUint64(arg->value.pointer_value);
             break;
         case TRACE_ARG_KOID:
-            WriteArgumentHeader(ArgumentType::kKoid, &arg->name_ref, WordsToBytes(1), 0u);
+            WriteArgumentHeaderAndName(ArgumentType::kKoid, &arg->name_ref, WordsToBytes(1), 0u);
             WriteUint64(arg->value.koid_value);
             break;
         default:
@@ -329,14 +329,15 @@
     }
 
 private:
-    void WriteArgumentHeader(ArgumentType type,
-                             const trace_string_ref_t* name_ref,
-                             size_t content_size,
-                             uint64_t header_bits) {
+    void WriteArgumentHeaderAndName(ArgumentType type,
+                                    const trace_string_ref_t* name_ref,
+                                    size_t content_size,
+                                    uint64_t header_bits) {
         const size_t argument_size = sizeof(ArgumentHeader) +
                                      SizeOfEncodedStringRef(name_ref) +
                                      content_size;
         WriteUint64(MakeArgumentHeader(type, argument_size, name_ref) | header_bits);
+        WriteStringRef(name_ref);
     }
 
     uint64_t* ptr_;
diff --git a/system/ulib/trace-engine/include/trace-engine/types.h b/system/ulib/trace-engine/include/trace-engine/types.h
index 39540cb..94c8dbf 100644
--- a/system/ulib/trace-engine/include/trace-engine/types.h
+++ b/system/ulib/trace-engine/include/trace-engine/types.h
@@ -90,7 +90,7 @@
 // Returns the length of an inline string.
 // Only valid for inline strings.
 inline size_t trace_inline_string_ref_length(const trace_string_ref_t* string_ref) {
-    return string_ref->encoded_value & ~TRACE_ENCODED_STRING_REF_INLINE_FLAG;
+    return string_ref->encoded_value & TRACE_ENCODED_STRING_REF_LENGTH_MASK;
 }
 
 // Makes an empty string ref.
diff --git a/system/utest/trace/engine_tests.cpp b/system/utest/trace/engine_tests.cpp
index 35cecb0..8c086d9 100644
--- a/system/utest/trace/engine_tests.cpp
+++ b/system/utest/trace/engine_tests.cpp
@@ -6,11 +6,11 @@
 
 #include <threads.h>
 
-#include <mx/event.h>
 #include <fbl/function.h>
 #include <fbl/string.h>
 #include <fbl/string_printf.h>
 #include <fbl/vector.h>
+#include <mx/event.h>
 #include <trace-engine/instrumentation.h>
 
 namespace {
@@ -359,6 +359,34 @@
     END_TRACE_TEST;
 }
 
+bool test_event_with_inline_everything() {
+    BEGIN_TRACE_TEST;
+
+    fixture_start_tracing();
+
+    trace_string_ref_t cat = trace_make_inline_c_string_ref("cat");
+    trace_string_ref_t name = trace_make_inline_c_string_ref("name");
+    trace_thread_ref_t thread = trace_make_inline_thread_ref(123, 456);
+    trace_arg_t args[] = {
+        trace_make_arg(trace_make_inline_c_string_ref("argname"),
+                       trace_make_string_arg_value(trace_make_inline_c_string_ref("argvalue")))};
+
+    {
+        auto context = trace::TraceContext::Acquire();
+
+        trace_context_write_instant_event_record(context.get(), mx_ticks_get(),
+                                                 &thread, &cat, &name,
+                                                 TRACE_SCOPE_GLOBAL,
+                                                 args, fbl::count_of(args));
+    }
+
+    ASSERT_RECORDS(R"X(Event(ts: <>, pt: <>, category: "cat", name: "name", Instant(scope: global), {argname: string("argvalue")})
+)X",
+                   "");
+
+    END_TRACE_TEST;
+}
+
 // NOTE: The functions for writing trace records are exercised by other trace tests.
 
 } // namespace
@@ -377,4 +405,5 @@
 RUN_TEST(test_register_string_literal_multiple_threads)
 RUN_TEST(test_register_string_literal_table_overflow)
 RUN_TEST(test_maximum_record_length)
+RUN_TEST(test_event_with_inline_everything)
 END_TEST_CASE(engine_tests)