Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2020-01-21 20:30:20 +0300
committerAnna Henningsen <anna@addaleax.net>2020-01-24 00:38:58 +0300
commit9cc747bfcea131797fbf0fcc805f1d7fa244b7da (patch)
tree2b9a0df517ed3da88b9ddeca6fda35851d43c913 /src
parentf6c6236d956be763ffe8eb1420e19eaab2962e8d (diff)
src: add C++-style sprintf utility
Add an utility that handles C++-style strings and objects well. PR-URL: https://github.com/nodejs/node/pull/31446 Fixes: https://github.com/nodejs/node/issues/28761 Fixes: https://github.com/nodejs/node/issues/31218 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/debug_utils-inl.h90
-rw-r--r--src/debug_utils.cc2
-rw-r--r--src/debug_utils.h14
-rw-r--r--src/inspector_io.cc2
-rw-r--r--src/inspector_profiler.cc2
-rw-r--r--src/node.cc2
-rw-r--r--src/node_http2.cc6
-rw-r--r--src/node_messaging.cc2
-rw-r--r--src/node_platform.cc2
-rw-r--r--src/node_report.cc2
-rw-r--r--src/node_wasi.cc4
-rw-r--r--src/node_watchdog.cc2
-rw-r--r--src/node_worker.cc2
-rw-r--r--src/spawn_sync.cc2
-rw-r--r--src/tls_wrap.cc2
-rw-r--r--src/tracing/agent.cc2
16 files changed, 120 insertions, 18 deletions
diff --git a/src/debug_utils-inl.h b/src/debug_utils-inl.h
new file mode 100644
index 00000000000..69b49d9c50d
--- /dev/null
+++ b/src/debug_utils-inl.h
@@ -0,0 +1,90 @@
+#ifndef SRC_DEBUG_UTILS_INL_H_
+#define SRC_DEBUG_UTILS_INL_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include "debug_utils.h"
+
+#include <type_traits>
+
+namespace node {
+
+struct ToStringHelper {
+ template <typename T>
+ static std::string Convert(
+ const T& value,
+ std::string(T::* to_string)() const = &T::ToString) {
+ return (value.*to_string)();
+ }
+ template <typename T,
+ typename test_for_number = typename std::
+ enable_if<std::is_arithmetic<T>::value, bool>::type,
+ typename dummy = bool>
+ static std::string Convert(const T& value) { return std::to_string(value); }
+ static std::string Convert(const char* value) { return value; }
+ static std::string Convert(const std::string& value) { return value; }
+ static std::string Convert(bool value) { return value ? "true" : "false"; }
+};
+
+template <typename T>
+std::string ToString(const T& value) {
+ return ToStringHelper::Convert(value);
+}
+
+inline std::string SPrintFImpl(const char* format) {
+ const char* p = strchr(format, '%');
+ if (LIKELY(p == nullptr)) return format;
+ CHECK_EQ(p[1], '%'); // Only '%%' allowed when there are no arguments.
+
+ return std::string(format, p + 1) + SPrintFImpl(p + 2);
+}
+
+template <typename Arg, typename... Args>
+std::string COLD_NOINLINE SPrintFImpl( // NOLINT(runtime/string)
+ const char* format, Arg&& arg, Args&&... args) {
+ const char* p = strchr(format, '%');
+ CHECK_NOT_NULL(p); // If you hit this, you passed in too many arguments.
+ std::string ret(format, p);
+ // Ignore long / size_t modifiers
+ while (strchr("lz", *++p) != nullptr) {}
+ switch (*p) {
+ case '%': {
+ return ret + '%' + SPrintFImpl(p + 1,
+ std::forward<Arg>(arg),
+ std::forward<Args>(args)...);
+ }
+ default: {
+ return ret + '%' + SPrintFImpl(p,
+ std::forward<Arg>(arg),
+ std::forward<Args>(args)...);
+ }
+ case 'd':
+ case 'i':
+ case 'u':
+ case 's': ret += ToString(arg); break;
+ case 'p': {
+ CHECK(std::is_pointer<typename std::remove_reference<Arg>::type>::value);
+ char out[20];
+ int n = snprintf(out,
+ sizeof(out),
+ "%p",
+ *reinterpret_cast<const void* const*>(&arg));
+ CHECK_GE(n, 0);
+ ret += out;
+ break;
+ }
+ }
+ return ret + SPrintFImpl(p + 1, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+std::string COLD_NOINLINE SPrintF( // NOLINT(runtime/string)
+ const char* format, Args&&... args) {
+ return SPrintFImpl(format, std::forward<Args>(args)...);
+}
+
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_DEBUG_UTILS_INL_H_
diff --git a/src/debug_utils.cc b/src/debug_utils.cc
index 8dd51b39319..b41cdd7a3f3 100644
--- a/src/debug_utils.cc
+++ b/src/debug_utils.cc
@@ -1,4 +1,4 @@
-#include "debug_utils.h"
+#include "debug_utils-inl.h" // NOLINT(build/include)
#include "env-inl.h"
#ifdef __POSIX__
diff --git a/src/debug_utils.h b/src/debug_utils.h
index db01cacba6a..08d23bb7703 100644
--- a/src/debug_utils.h
+++ b/src/debug_utils.h
@@ -22,6 +22,17 @@
namespace node {
+template <typename T>
+inline std::string ToString(const T& value);
+
+// C++-style variant of sprintf() that:
+// - Returns an std::string
+// - Handles \0 bytes correctly
+// - Supports %p and %s. %d, %i and %u are aliases for %s.
+// - Accepts any class that has a ToString() method for stringification.
+template <typename... Args>
+inline std::string SPrintF(const char* format, Args&&... args);
+
template <typename... Args>
inline void FORCE_INLINE Debug(Environment* env,
DebugCategory cat,
@@ -29,7 +40,8 @@ inline void FORCE_INLINE Debug(Environment* env,
Args&&... args) {
if (!UNLIKELY(env->debug_enabled(cat)))
return;
- fprintf(stderr, format, std::forward<Args>(args)...);
+ std::string out = SPrintF(format, std::forward<Args>(args)...);
+ fwrite(out.data(), out.size(), 1, stderr);
}
inline void FORCE_INLINE Debug(Environment* env,
diff --git a/src/inspector_io.cc b/src/inspector_io.cc
index 76e481c9530..ed9035136c5 100644
--- a/src/inspector_io.cc
+++ b/src/inspector_io.cc
@@ -4,7 +4,7 @@
#include "inspector/main_thread_interface.h"
#include "inspector/node_string.h"
#include "base_object-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "node.h"
#include "node_crypto.h"
#include "node_internals.h"
diff --git a/src/inspector_profiler.cc b/src/inspector_profiler.cc
index e0d02d6952a..f9d3c2b512f 100644
--- a/src/inspector_profiler.cc
+++ b/src/inspector_profiler.cc
@@ -1,6 +1,6 @@
#include "inspector_profiler.h"
#include "base_object-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "diagnosticfilename-inl.h"
#include "memory_tracker-inl.h"
#include "node_file.h"
diff --git a/src/node.cc b/src/node.cc
index d46c78a927b..0cb89044e58 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -23,7 +23,7 @@
// ========== local headers ==========
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node_binding.h"
diff --git a/src/node_http2.cc b/src/node_http2.cc
index e0d6398f2a4..e48bf091408 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -1,5 +1,5 @@
#include "aliased_buffer.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "memory_tracker-inl.h"
#include "node.h"
#include "node_buffer.h"
@@ -1959,7 +1959,7 @@ std::string Http2Stream::diagnostic_name() const {
// Notify the Http2Stream that a new block of HEADERS is being processed.
void Http2Stream::StartHeaders(nghttp2_headers_category category) {
- Debug(this, "starting headers, category: %d", id_, category);
+ Debug(this, "starting headers, category: %d", category);
CHECK(!this->IsDestroyed());
session_->DecrementCurrentSessionMemory(current_headers_length_);
current_headers_length_ = 0;
@@ -2217,7 +2217,7 @@ int Http2Stream::DoWrite(WriteWrap* req_wrap,
req_wrap->Done(UV_EOF);
return 0;
}
- Debug(this, "queuing %d buffers to send", id_, nbufs);
+ Debug(this, "queuing %d buffers to send", nbufs);
for (size_t i = 0; i < nbufs; ++i) {
// Store the req_wrap on the last write info in the queue, so that it is
// only marked as finished once all buffers associated with it are finished.
diff --git a/src/node_messaging.cc b/src/node_messaging.cc
index ebad6c67508..99f42c04245 100644
--- a/src/node_messaging.cc
+++ b/src/node_messaging.cc
@@ -1,7 +1,7 @@
#include "node_messaging.h"
#include "async_wrap-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "memory_tracker-inl.h"
#include "node_contextify.h"
#include "node_buffer.h"
diff --git a/src/node_platform.cc b/src/node_platform.cc
index 4be929c7ee3..b30f907a02d 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -2,7 +2,7 @@
#include "node_internals.h"
#include "env-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include <algorithm> // find_if(), find(), move()
#include <cmath> // llround()
#include <memory> // unique_ptr(), shared_ptr(), make_shared()
diff --git a/src/node_report.cc b/src/node_report.cc
index 9b32352326b..c29f866f4a8 100644
--- a/src/node_report.cc
+++ b/src/node_report.cc
@@ -1,6 +1,6 @@
#include "env-inl.h"
#include "node_report.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "diagnosticfilename-inl.h"
#include "node_internals.h"
#include "node_metadata.h"
diff --git a/src/node_wasi.cc b/src/node_wasi.cc
index 277b171224c..20872c58d60 100644
--- a/src/node_wasi.cc
+++ b/src/node_wasi.cc
@@ -1,6 +1,6 @@
#include "env-inl.h"
#include "base_object-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "memory_tracker-inl.h"
#include "node_mem-inl.h"
#include "util-inl.h"
@@ -1063,7 +1063,7 @@ void WASI::PathFilestatGet(const FunctionCallbackInfo<Value>& args) {
CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, buf_ptr);
ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This());
Debug(wasi,
- "path_filestat_get(%d, %d, %d, %d, %d)\n",
+ "path_filestat_get(%d, %d, %d)\n",
fd,
path_ptr,
path_len);
diff --git a/src/node_watchdog.cc b/src/node_watchdog.cc
index a0f73e973f6..4ab625ce65b 100644
--- a/src/node_watchdog.cc
+++ b/src/node_watchdog.cc
@@ -21,7 +21,7 @@
#include <algorithm>
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "env-inl.h"
#include "node_errors.h"
#include "node_internals.h"
diff --git a/src/node_worker.cc b/src/node_worker.cc
index 078b6ac5bbf..9acec1a8cbc 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -1,5 +1,5 @@
#include "node_worker.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "memory_tracker-inl.h"
#include "node_errors.h"
#include "node_buffer.h"
diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc
index 0751bc21a7e..3b277ad70ad 100644
--- a/src/spawn_sync.cc
+++ b/src/spawn_sync.cc
@@ -20,7 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "spawn_sync.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "env-inl.h"
#include "node_internals.h"
#include "string_bytes.h"
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
index 10ebc4ccd9a..82274fde6db 100644
--- a/src/tls_wrap.cc
+++ b/src/tls_wrap.cc
@@ -21,7 +21,7 @@
#include "tls_wrap.h"
#include "async_wrap-inl.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h" // Buffer
#include "node_crypto.h" // SecureContext
diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
index 3d19c6c7584..7d265dcb0c4 100644
--- a/src/tracing/agent.cc
+++ b/src/tracing/agent.cc
@@ -3,7 +3,7 @@
#include <string>
#include "trace_event.h"
#include "tracing/node_trace_buffer.h"
-#include "debug_utils.h"
+#include "debug_utils-inl.h"
#include "env-inl.h"
namespace node {