diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index 31e9181985259..5e4200001cc53 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -69,7 +69,6 @@ "jit/LIROpsGenerated.h", # generated in $OBJDIR "jit/MIROpsGenerated.h", # generated in $OBJDIR "js/ProfilingCategoryList.h", # comes from mozglue/baseprofiler - "mozilla/glue/Debug.h", # comes from mozglue/misc, shadowed by "jscustomallocator.h", # provided by embedders; allowed to be missing "js-config.h", # generated in $OBJDIR "fdlibm.h", # fdlibm diff --git a/config/check_vanilla_allocations.py b/config/check_vanilla_allocations.py index 928f7cd6a757a..32e313d386043 100644 --- a/config/check_vanilla_allocations.py +++ b/config/check_vanilla_allocations.py @@ -147,10 +147,6 @@ def main(): "Decimal.o", # Ignore use of std::string in regexp AST debug output. "regexp-ast.o", - # mozglue/misc/Debug.cpp contains a call to `printf_stderr("%s", aStr.str().c_str())` - # where `aStr` is a `std::stringstream`. In inlined opt builds, this calls - # `operator new()` and `operator delete` for a temporary. - "Debug.o", ] all_ignored_files = set((f, 1) for f in ignored_files) diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index e435b7ed1dd7f..055086761e5b9 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -1464,13 +1464,16 @@ void CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents, #ifdef MOZ_DUMP_PAINTING template void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf) { + nsCString string(aObj->Name()); + string.Append('-'); + string.AppendInt((uint64_t)aObj); if (gfxUtils::sDumpPaintFile != stderr) { - gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile); - } else { - nsCString uri = gfxUtils::GetAsDataURI(aSurf); - nsPrintfCString string(R"(array["%s-%)" PRIu64 R"("]="%s";\n)", - aObj->Name(), uint64_t(aObj), uri.BeginReading()); - fprintf_stderr(gfxUtils::sDumpPaintFile, "%s", string.get()); + fprintf_stderr(gfxUtils::sDumpPaintFile, R"(array["%s"]=")", + string.BeginReading()); + } + gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile); + if (gfxUtils::sDumpPaintFile != stderr) { + fprintf_stderr(gfxUtils::sDumpPaintFile, R"(";)"); } } diff --git a/intl/lwbrk/nsUniscribeBreaker.cpp b/intl/lwbrk/nsUniscribeBreaker.cpp index 9e7a7595372fa..fcd1e282e17f6 100644 --- a/intl/lwbrk/nsUniscribeBreaker.cpp +++ b/intl/lwbrk/nsUniscribeBreaker.cpp @@ -126,20 +126,20 @@ void NS_GetComplexLineBreaks(const char16_t* aText, uint32_t aLength, } if (mismatch) { - nsCString line("uniscribe: "); // The logging here doesn't handle surrogates, but we only have tests using // Thai currently, which is BMP-only. + printf_stderr("uniscribe: "); for (uint32_t i = 0; i < aLength; ++i) { - if (aBreakBefore[i]) line.Append('#'); - line.Append(NS_ConvertUTF16toUTF8(aText + i, 1).get()); + if (aBreakBefore[i]) printf_stderr("#"); + printf_stderr("%s", NS_ConvertUTF16toUTF8(aText + i, 1).get()); } - printf_stderr("%s\n", line.get()); - line.Assign("brokered : "); + printf_stderr("\n"); + printf_stderr("brokered : "); for (uint32_t i = 0; i < aLength; ++i) { - if (brokeredBreaks[i]) line.Append('#'); - line.Append(NS_ConvertUTF16toUTF8(aText + i, 1).get()); + if (brokeredBreaks[i]) printf_stderr("#"); + printf_stderr("%s", NS_ConvertUTF16toUTF8(aText + i, 1).get()); } - printf_stderr("%s\n", line.get()); + printf_stderr("\n"); MOZ_CRASH("Brokered breaks did not match."); } #endif diff --git a/js/public/Printer.h b/js/public/Printer.h index 6143b3240f185..f62435ed06050 100644 --- a/js/public/Printer.h +++ b/js/public/Printer.h @@ -8,7 +8,6 @@ #define js_Printer_h #include "mozilla/Attributes.h" -#include "mozilla/glue/Debug.h" #include "mozilla/Range.h" #include @@ -340,22 +339,7 @@ class JS_PUBLIC_API Fprinter final : public GenericPrinter { // Puts |len| characters from |s| at the current position and // return true on success, false on failure. - bool put(const char* s, size_t len) override; - using GenericPrinter::put; // pick up |inline bool put(const char* s);| -}; - -// SEprinter, print using printf_stderr (goes to Android log, Windows debug, -// else just stderr). -class SEprinter final : public GenericPrinter { - public: - constexpr SEprinter() {} - - // Puts |len| characters from |s| at the current position and - // return true on success, false on failure. - virtual bool put(const char* s, size_t len) override { - printf_stderr("%.*s", int(len), s); - return true; - } + virtual void put(const char* s, size_t len) override; using GenericPrinter::put; // pick up |inline bool put(const char* s);| }; diff --git a/mozglue/misc/Debug.cpp b/mozglue/misc/Debug.cpp deleted file mode 100644 index c3a2ca89e079b..0000000000000 --- a/mozglue/misc/Debug.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/glue/Debug.h" -#include "mozilla/Fuzzing.h" -#include "mozilla/Sprintf.h" - -#include -#include - -#ifdef XP_WIN -# include -# include -#endif - -#ifdef ANDROID -# include -#endif - -#ifndef ANDROID -static void vprintf_stderr_buffered(const char* aFmt, va_list aArgs) { - // Avoid interleaving by writing to an on-stack buffer and then writing in one - // go with fputs, as long as the output fits into the buffer. - char buffer[1024]; - va_list argsCpy; - va_copy(argsCpy, aArgs); - int n = VsprintfLiteral(buffer, aFmt, aArgs); - if (n < int(sizeof(buffer))) { - fputs(buffer, stderr); - } else { - // Message too long for buffer. Just print it, not worrying about - // interleaving. (We could malloc, but the underlying write() syscall could - // get interleaved if the output is too big anyway.) - vfprintf(stderr, aFmt, argsCpy); - } - va_end(argsCpy); - fflush(stderr); -} -#endif - -#if defined(XP_WIN) -MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) { - if (IsDebuggerPresent()) { - int lengthNeeded = _vscprintf(aFmt, aArgs); - if (lengthNeeded) { - lengthNeeded++; - auto buf = mozilla::MakeUnique(lengthNeeded); - if (buf) { - va_list argsCpy; - va_copy(argsCpy, aArgs); - vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy); - buf[lengthNeeded - 1] = '\0'; - va_end(argsCpy); - OutputDebugStringA(buf.get()); - } - } - } - - vprintf_stderr_buffered(aFmt, aArgs); -} - -#elif defined(ANDROID) -MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) { - __android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs); -} -#elif defined(FUZZING_SNAPSHOT) -MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) { - if (nyx_puts) { - auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs); - nyx_puts(msgbuf.get()); - } else { - vprintf_stderr_buffered(aFmt, aArgs); - } -} -#else -MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) { - vprintf_stderr_buffered(aFmt, aArgs); -} -#endif - -MFBT_API void printf_stderr(const char* aFmt, ...) { - va_list args; - va_start(args, aFmt); - vprintf_stderr(aFmt, args); - va_end(args); -} - -MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...) { - va_list args; - va_start(args, aFmt); - if (aFile == stderr) { - vprintf_stderr(aFmt, args); - } else { - vfprintf(aFile, aFmt, args); - } - va_end(args); -} - -MFBT_API void print_stderr(std::stringstream& aStr) { -#if defined(ANDROID) - // On Android logcat output is truncated to 1024 chars per line, and - // we usually use std::stringstream to build up giant multi-line gobs - // of output. So to avoid the truncation we find the newlines and - // print the lines individually. - std::string line; - while (std::getline(aStr, line)) { - printf_stderr("%s\n", line.c_str()); - } -#else - printf_stderr("%s", aStr.str().c_str()); -#endif -} - -MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr) { - if (aFile == stderr) { - print_stderr(aStr); - } else { - fprintf_stderr(aFile, "%s", aStr.str().c_str()); - } -} diff --git a/mozglue/misc/Debug.h b/mozglue/misc/Debug.h index 43380878b9f78..f8f05c6299044 100644 --- a/mozglue/misc/Debug.h +++ b/mozglue/misc/Debug.h @@ -7,12 +7,6 @@ #ifndef mozilla_glue_Debug_h #define mozilla_glue_Debug_h -#include "mozilla/Attributes.h" // For MOZ_FORMAT_PRINTF -#include "mozilla/Types.h" // For MFBT_API - -#include -#include - /* This header file intends to supply debugging utilities for use in code * that cannot use XPCOM debugging facilities like nsDebug.h. * e.g. mozglue, browser/app @@ -21,53 +15,52 @@ * care; avoid including from header files. */ +#include +#if defined(XP_WIN) +# include +#endif // defined(XP_WIN) +#include "mozilla/Attributes.h" +#include "mozilla/Sprintf.h" + +#if defined(MOZILLA_INTERNAL_API) +# error Do not include this file from XUL sources. +#endif + +// Though this is a separate implementation than nsDebug's, we want to make the +// declarations compatible to avoid confusing the linker if both headers are +// included. #ifdef __cplusplus extern "C" { #endif // __cplusplus -/** - * printf_stderr(...) is much like fprintf(stderr, ...), except that: - * - on Android and Firefox OS, *instead* of printing to stderr, it - * prints to logcat. (Newlines in the string lead to multiple lines - * of logcat, but each function call implicitly completes a line even - * if the string does not end with a newline.) - * - on Windows, if a debugger is present, it calls OutputDebugString - * in *addition* to writing to stderr - */ -MFBT_API void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2); +void printf_stderr(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2); +inline void printf_stderr(const char* fmt, ...) { +#if defined(XP_WIN) + if (IsDebuggerPresent()) { + char buf[2048]; + va_list args; + va_start(args, fmt); + VsprintfLiteral(buf, fmt, args); + va_end(args); + OutputDebugStringA(buf); + } +#endif // defined(XP_WIN) -/** - * Same as printf_stderr, but taking va_list instead of varargs - */ -MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) - MOZ_FORMAT_PRINTF(1, 0); + // stderr is unbuffered by default so we open a new FILE (which is buffered) + // so that calls to printf_stderr are not as likely to get mixed together. + int fd = _fileno(stderr); + if (fd == -2) return; -/** - * fprintf_stderr is like fprintf, except that if its file argument - * is stderr, it invokes printf_stderr instead. - * - * This is useful for general debugging code that logs information to a - * file, but that you would like to be useful on Android and Firefox OS. - * If you use fprintf_stderr instead of fprintf in such debugging code, - * then callers can pass stderr to get logging that works on Android and - * Firefox OS (and also the other side-effects of using printf_stderr). - * - * Code that is structured this way needs to be careful not to split a - * line of output across multiple calls to fprintf_stderr, since doing - * so will cause it to appear in multiple lines in logcat output. - * (Producing multiple lines at once is fine.) - */ -MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...) - MOZ_FORMAT_PRINTF(2, 3); + FILE* fp = _fdopen(_dup(fd), "a"); + if (!fp) return; -/* - * print_stderr and fprint_stderr are like printf_stderr and fprintf_stderr, - * except they deal with Android logcat line length limitations. They do this - * by printing individual lines out of the provided stringstream using separate - * calls to logcat. - */ -MFBT_API void print_stderr(std::stringstream& aStr); -MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr); + va_list args; + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + + fclose(fp); +} #ifdef __cplusplus } diff --git a/mozglue/misc/moz.build b/mozglue/misc/moz.build index c0ff86ea0517c..0976d80a6d366 100644 --- a/mozglue/misc/moz.build +++ b/mozglue/misc/moz.build @@ -43,7 +43,6 @@ if CONFIG["OS_ARCH"] == "WINNT": SOURCES += [ "AutoProfilerLabel.cpp", "AwakeTimeStamp.cpp", - "Debug.cpp", "MmapFaultHandler.cpp", "Printf.cpp", "SIMD.cpp", diff --git a/xpcom/base/nsCRTGlue.cpp b/xpcom/base/nsCRTGlue.cpp index 99289daa63163..925379f716ffe 100644 --- a/xpcom/base/nsCRTGlue.cpp +++ b/xpcom/base/nsCRTGlue.cpp @@ -19,6 +19,12 @@ #ifdef XP_WIN # include # include +# include "mozilla/LateWriteChecks.h" +# include "mozilla/UniquePtr.h" +#endif + +#ifdef ANDROID +# include #endif #ifdef FUZZING_SNAPSHOT @@ -224,3 +230,99 @@ void NS_MakeRandomString(char* aBuf, int32_t aBufLen) { } #endif + +#if defined(XP_WIN) +void vprintf_stderr(const char* aFmt, va_list aArgs) { + if (IsDebuggerPresent()) { + int lengthNeeded = _vscprintf(aFmt, aArgs); + if (lengthNeeded) { + lengthNeeded++; + auto buf = MakeUnique(lengthNeeded); + if (buf) { + va_list argsCpy; + va_copy(argsCpy, aArgs); + vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy); + buf[lengthNeeded - 1] = '\0'; + va_end(argsCpy); + OutputDebugStringA(buf.get()); + } + } + } + + // stderr is unbuffered by default so we open a new FILE (which is buffered) + // so that calls to printf_stderr are not as likely to get mixed together. + int fd = _fileno(stderr); + if (fd == -2) { + return; + } + + FILE* fp = _fdopen(_dup(fd), "a"); + if (!fp) { + return; + } + + vfprintf(fp, aFmt, aArgs); + + AutoSuspendLateWriteChecks suspend; + fclose(fp); +} + +#elif defined(ANDROID) +void vprintf_stderr(const char* aFmt, va_list aArgs) { + __android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs); +} +#elif defined(FUZZING_SNAPSHOT) +void vprintf_stderr(const char* aFmt, va_list aArgs) { + if (nyx_puts) { + auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs); + nyx_puts(msgbuf.get()); + } else { + vfprintf(stderr, aFmt, aArgs); + } +} +#else +void vprintf_stderr(const char* aFmt, va_list aArgs) { + vfprintf(stderr, aFmt, aArgs); +} +#endif + +void printf_stderr(const char* aFmt, ...) { + va_list args; + va_start(args, aFmt); + vprintf_stderr(aFmt, args); + va_end(args); +} + +void fprintf_stderr(FILE* aFile, const char* aFmt, ...) { + va_list args; + va_start(args, aFmt); + if (aFile == stderr) { + vprintf_stderr(aFmt, args); + } else { + vfprintf(aFile, aFmt, args); + } + va_end(args); +} + +void print_stderr(std::stringstream& aStr) { +#if defined(ANDROID) + // On Android logcat output is truncated to 1024 chars per line, and + // we usually use std::stringstream to build up giant multi-line gobs + // of output. So to avoid the truncation we find the newlines and + // print the lines individually. + std::string line; + while (std::getline(aStr, line)) { + printf_stderr("%s\n", line.c_str()); + } +#else + printf_stderr("%s", aStr.str().c_str()); +#endif +} + +void fprint_stderr(FILE* aFile, std::stringstream& aStr) { + if (aFile == stderr) { + print_stderr(aStr); + } else { + fprintf_stderr(aFile, "%s", aStr.str().c_str()); + } +} diff --git a/xpcom/base/nsDebug.h b/xpcom/base/nsDebug.h index 3e3fc4d89eef0..349c297ea8bfe 100644 --- a/xpcom/base/nsDebug.h +++ b/xpcom/base/nsDebug.h @@ -12,7 +12,6 @@ #include "nsXPCOM.h" #include "mozilla/Assertions.h" -#include "mozilla/glue/Debug.h" #include "mozilla/DbgMacro.h" #include "mozilla/Likely.h" #include @@ -327,4 +326,59 @@ void NS_ABORT_OOM(size_t aSize); inline void NS_ABORT_OOM(size_t) { MOZ_CRASH(); } #endif +/* When compiling the XPCOM Glue on Windows, we pretend that it's going to + * be linked with a static CRT (-MT) even when it's not. This means that we + * cannot link to data exports from the CRT, only function exports. So, + * instead of referencing "stderr" directly, use fdopen. + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * printf_stderr(...) is much like fprintf(stderr, ...), except that: + * - on Android and Firefox OS, *instead* of printing to stderr, it + * prints to logcat. (Newlines in the string lead to multiple lines + * of logcat, but each function call implicitly completes a line even + * if the string does not end with a newline.) + * - on Windows, if a debugger is present, it calls OutputDebugString + * in *addition* to writing to stderr + */ +void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2); + +/** + * Same as printf_stderr, but taking va_list instead of varargs + */ +void vprintf_stderr(const char* aFmt, va_list aArgs) MOZ_FORMAT_PRINTF(1, 0); + +/** + * fprintf_stderr is like fprintf, except that if its file argument + * is stderr, it invokes printf_stderr instead. + * + * This is useful for general debugging code that logs information to a + * file, but that you would like to be useful on Android and Firefox OS. + * If you use fprintf_stderr instead of fprintf in such debugging code, + * then callers can pass stderr to get logging that works on Android and + * Firefox OS (and also the other side-effects of using printf_stderr). + * + * Code that is structured this way needs to be careful not to split a + * line of output across multiple calls to fprintf_stderr, since doing + * so will cause it to appear in multiple lines in logcat output. + * (Producing multiple lines at once is fine.) + */ +void fprintf_stderr(FILE* aFile, const char* aFmt, ...) MOZ_FORMAT_PRINTF(2, 3); + +/* + * print_stderr and fprint_stderr are like printf_stderr and fprintf_stderr, + * except they deal with Android logcat line length limitations. They do this + * by printing individual lines out of the provided stringstream using separate + * calls to logcat. + */ +void print_stderr(std::stringstream& aStr); +void fprint_stderr(FILE* aFile, std::stringstream& aStr); + +#ifdef __cplusplus +} +#endif + #endif /* nsDebug_h___ */