Change Integrity audit logging to use OS_LOG_TYPE_ERROR.
https://bugs.webkit.org/show_bug.cgi?id=241742

Reviewed by Yusuke Suzuki.

On OS(DARWIN), Integrity audit code now uses an OSLogPrintStream to achieve this
logging with type OS_LOG_TYPE_ERROR.  On other ports, we just route the logging
to WTF::dataFile() instead.

Also removed __VA_ARGS__ support when !VA_OPT_SUPPORTED.  This never worked in the first
place.  Ports without VA_OPT_SUPPORTED will have to live with degraded logging.

Added WTFReportBacktraceWithPrefixAndPrintStream and WTFPrintBacktraceWithPrefixAndPrintStream
to support this new Integrity audit logging.  Removed the old WTFPrintBacktraceWithPrefix
because it was never used by external clients.  It was only used by as an internal support
function by other stack dumper functions.

* Source/JavaScriptCore/tools/Integrity.cpp:
(JSC::Integrity::logFile):
(JSC::Integrity::logF):
(JSC::Integrity::logLnF):
(JSC::Integrity::verifyCell):
* Source/JavaScriptCore/tools/Integrity.h:
* Source/WTF/wtf/Assertions.cpp:
* Source/WTF/wtf/Assertions.h:

Canonical link: https://commits.webkit.org/251666@main


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@295661 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/tools/Integrity.cpp b/Source/JavaScriptCore/tools/Integrity.cpp
index d4623298..f511e70 100644
--- a/Source/JavaScriptCore/tools/Integrity.cpp
+++ b/Source/JavaScriptCore/tools/Integrity.cpp
@@ -34,6 +34,8 @@
 #include "JSGlobalObject.h"
 #include "Options.h"
 #include "VMInspectorInlines.h"
+#include <wtf/DataLog.h>
+#include <wtf/OSLogPrintStream.h>
 
 namespace JSC {
 namespace Integrity {
@@ -42,6 +44,40 @@
 static constexpr bool verbose = false;
 }
 
+PrintStream& logFile()
+{
+#if OS(DARWIN)
+    static PrintStream* s_file;
+    static std::once_flag once;
+    std::call_once(once, [] {
+        // We want to use OS_LOG_TYPE_ERROR because we want to guarantee that the log makes it into
+        // the file system, and is not potentially stuck in some memory buffer. Integrity audit logs
+        // are used for debugging error states. So, this is an appropriate use of OS_LOG_TYPE_ERROR.
+        s_file = OSLogPrintStream::open("com.apple.JavaScriptCore", "Integrity", OS_LOG_TYPE_ERROR).release();
+    });
+    return *s_file;
+#else
+    return WTF::dataFile();
+#endif
+}
+
+void logF(const char* format, ...)
+{
+    va_list argList;
+    va_start(argList, format);
+    logFile().vprintf(format, argList);
+    va_end(argList);
+}
+
+void logLnF(const char* format, ...)
+{
+    va_list argList;
+    va_start(argList, format);
+    logFile().vprintf(format, argList);
+    va_end(argList);
+    logFile().println();
+}
+
 Random::Random(VM& vm)
 {
     reloadAndCheckShouldAuditSlow(vm);
@@ -140,19 +176,19 @@
 
 #define AUDIT_VERIFY(cond, format, ...) do { \
         IA_ASSERT_WITH_ACTION(cond, { \
-            WTFLogAlways("    cell %p", cell); \
+            Integrity::logLnF("    cell %p", cell); \
             if (action == Action::LogAndCrash) \
-                RELEASE_ASSERT((cond), ##__VA_ARGS__); \
+                RELEASE_ASSERT((cond)); \
             else \
                 return false; \
-        }, format, ##__VA_ARGS__); \
+        }); \
     } while (false)
 
 #else // not (COMPILER(MSVC) || !VA_OPT_SUPPORTED)
 
 #define AUDIT_VERIFY(cond, format, ...) do { \
         IA_ASSERT_WITH_ACTION(cond, { \
-            WTFLogAlways("    cell %p", cell); \
+            Integrity::logLnF("    cell %p", cell); \
             if (action == Action::LogAndCrash) \
                 RELEASE_ASSERT((cond) __VA_OPT__(,) __VA_ARGS__); \
             else \
@@ -290,14 +326,14 @@
 bool verifyCell(JSCell* cell)
 {
     bool valid = Analyzer::analyzeCell(cell, Analyzer::Action::LogOnly);
-    WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID");
+    Integrity::logLnF("Cell %p is %s", cell, valid ? "VALID" : "INVALID");
     return valid;
 }
 
 bool verifyCell(VM& vm, JSCell* cell)
 {
     bool valid = Analyzer::analyzeCell(vm, cell, Analyzer::Action::LogOnly);
-    WTFLogAlways("Cell %p is %s", cell, valid ? "VALID" : "INVALID");
+    Integrity::logLnF("Cell %p is %s", cell, valid ? "VALID" : "INVALID");
     return valid;
 }
 
diff --git a/Source/JavaScriptCore/tools/Integrity.h b/Source/JavaScriptCore/tools/Integrity.h
index e499de0..86e59ae 100644
--- a/Source/JavaScriptCore/tools/Integrity.h
+++ b/Source/JavaScriptCore/tools/Integrity.h
@@ -48,6 +48,10 @@
 typedef const struct OpaqueJSValue* JSValueRef;
 typedef struct OpaqueJSValue* JSObjectRef;
 
+namespace WTF {
+class PrintStream;
+}
+
 namespace JSC {
 
 class JSCell;
@@ -177,34 +181,33 @@
 #if COMPILER(MSVC) || !VA_OPT_SUPPORTED
 
 #define IA_LOG(assertion, format, ...) do { \
-        WTFLogAlways("Integrity ERROR: %s @ %s:%d\n", #assertion, __FILE__, __LINE__); \
-        WTFLogAlways("    " format, ##__VA_ARGS__); \
+        Integrity::logLnF("ERROR: %s @ %s:%d", #assertion, __FILE__, __LINE__); \
     } while (false)
 
 #define IA_ASSERT_WITH_ACTION(assertion, action, ...) do { \
         if (UNLIKELY(!(assertion))) { \
             IA_LOG(assertion, __VA_ARGS__); \
-            WTFReportBacktraceWithPrefix("    "); \
+            WTFReportBacktraceWithPrefixAndPrintStream(Integrity::logFile(), "    "); \
             action; \
         } \
     } while (false)
 
 #define IA_ASSERT(assertion, ...) \
     IA_ASSERT_WITH_ACTION(assertion, { \
-        RELEASE_ASSERT((assertion), ##__VA_ARGS__); \
-    }, ## __VA_ARGS__)
+        RELEASE_ASSERT((assertion)); \
+    })
 
 #else // not (COMPILER(MSVC) || !VA_OPT_SUPPORTED)
 
 #define IA_LOG(assertion, format, ...) do { \
-        WTFLogAlways("Integrity ERROR: %s @ %s:%d\n", #assertion, __FILE__, __LINE__); \
-        WTFLogAlways("    " format __VA_OPT__(,) __VA_ARGS__); \
+        Integrity::logLnF("ERROR: %s @ %s:%d", #assertion, __FILE__, __LINE__); \
+        Integrity::logLnF("    " format __VA_OPT__(,) __VA_ARGS__); \
     } while (false)
 
 #define IA_ASSERT_WITH_ACTION(assertion, action, ...) do { \
         if (UNLIKELY(!(assertion))) { \
             IA_LOG(assertion, __VA_ARGS__); \
-            WTFReportBacktraceWithPrefix("    "); \
+            WTFReportBacktraceWithPrefixAndPrintStream(Integrity::logFile(), "    "); \
             action; \
         } \
     } while (false)
@@ -216,6 +219,10 @@
 
 #endif // COMPILER(MSVC) || !VA_OPT_SUPPORTED
 
+JS_EXPORT_PRIVATE WTF::PrintStream& logFile();
+JS_EXPORT_PRIVATE void logF(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
+JS_EXPORT_PRIVATE void logLnF(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
+
 } // namespace Integrity
 
 } // namespace JSC
diff --git a/Source/WTF/wtf/Assertions.cpp b/Source/WTF/wtf/Assertions.cpp
index 7069959..d565848 100644
--- a/Source/WTF/wtf/Assertions.cpp
+++ b/Source/WTF/wtf/Assertions.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2021 Apple Inc.  All rights reserved.
+ * Copyright (C) 2003-2022 Apple Inc.  All rights reserved.
  * Copyright (C) 2007-2009 Torch Mobile, Inc.
  * Copyright (C) 2011 University of Szeged. All rights reserved.
  *
@@ -280,13 +280,19 @@
 
 void WTFReportBacktraceWithPrefix(const char* prefix)
 {
+    CrashLogPrintStream out;
+    WTFReportBacktraceWithPrefixAndPrintStream(out, prefix);
+}
+
+void WTFReportBacktraceWithPrefixAndPrintStream(PrintStream& out, const char* prefix)
+{
     static constexpr int framesToShow = 31;
     static constexpr int framesToSkip = 2;
     void* samples[framesToShow + framesToSkip];
     int frames = framesToShow + framesToSkip;
 
     WTFGetBacktrace(samples, &frames);
-    WTFPrintBacktraceWithPrefix(samples + framesToSkip, frames - framesToSkip, prefix);
+    WTFPrintBacktraceWithPrefixAndPrintStream(out, samples + framesToSkip, frames - framesToSkip, prefix);
 }
 
 void WTFReportBacktrace()
@@ -300,16 +306,16 @@
     WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip);
 }
 
-void WTFPrintBacktraceWithPrefix(void** stack, int size, const char* prefix)
+void WTFPrintBacktraceWithPrefixAndPrintStream(PrintStream& out, void** stack, int size, const char* prefix)
 {
-    CrashLogPrintStream out;
     StackTrace stackTrace(stack, size, prefix);
     out.print(stackTrace);
 }
 
 void WTFPrintBacktrace(void** stack, int size)
 {
-    WTFPrintBacktraceWithPrefix(stack, size, "");
+    CrashLogPrintStream out;
+    WTFPrintBacktraceWithPrefixAndPrintStream(out, stack, size, "");
 }
 
 #if !defined(NDEBUG) || !(OS(DARWIN) || PLATFORM(PLAYSTATION))
diff --git a/Source/WTF/wtf/Assertions.h b/Source/WTF/wtf/Assertions.h
index 9443e64..8e1e742 100644
--- a/Source/WTF/wtf/Assertions.h
+++ b/Source/WTF/wtf/Assertions.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2019 Apple Inc.  All rights reserved.
+ * Copyright (C) 2003-2022 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -154,6 +154,9 @@
 enum class WTFLogChannelState : uint8_t { Off, On, OnWithAccumulation };
 #undef Always
 enum class WTFLogLevel : uint8_t { Always, Error, Warning, Info, Debug };
+namespace WTF {
+class PrintStream;
+}
 #else
 typedef uint8_t WTFLogChannelState;
 typedef uint8_t WTFLogLevel;
@@ -228,7 +231,10 @@
 WTF_EXPORT_PRIVATE void WTFGetBacktrace(void** stack, int* size);
 WTF_EXPORT_PRIVATE void WTFReportBacktraceWithPrefix(const char*);
 WTF_EXPORT_PRIVATE void WTFReportBacktrace(void);
-WTF_EXPORT_PRIVATE void WTFPrintBacktraceWithPrefix(void** stack, int size, const char* prefix);
+#ifdef __cplusplus
+WTF_EXPORT_PRIVATE void WTFReportBacktraceWithPrefixAndPrintStream(WTF::PrintStream&, const char*);
+void WTFPrintBacktraceWithPrefixAndPrintStream(WTF::PrintStream&, void** stack, int size, const char* prefix);
+#endif
 WTF_EXPORT_PRIVATE void WTFPrintBacktrace(void** stack, int size);
 #if !RELEASE_LOG_DISABLED
 WTF_EXPORT_PRIVATE void WTFReleaseLogStackTrace(WTFLogChannel*);