Skip to content

Commit fab3527

Browse files
committed
Bug 1790873 - Move printf_stderr() to mozglue so it can be used within js/src r=glandium,nika
Differential Revision: https://phabricator.services.mozilla.com/D157354
1 parent 9abb6aa commit fab3527

File tree

7 files changed

+176
-201
lines changed

7 files changed

+176
-201
lines changed

config/check_spidermonkey_style.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"jit/LIROpsGenerated.h", # generated in $OBJDIR
7070
"jit/MIROpsGenerated.h", # generated in $OBJDIR
7171
"js/ProfilingCategoryList.h", # comes from mozglue/baseprofiler
72+
"mozilla/glue/Debug.h", # comes from mozglue/misc, shadowed by <mozilla/Debug.h>
7273
"jscustomallocator.h", # provided by embedders; allowed to be missing
7374
"js-config.h", # generated in $OBJDIR
7475
"fdlibm.h", # fdlibm

config/check_vanilla_allocations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ def main():
147147
"Decimal.o",
148148
# Ignore use of std::string in regexp AST debug output.
149149
"regexp-ast.o",
150+
# mozglue/misc/Debug.cpp contains a call to `printf_stderr("%s", aStr.str().c_str())`
151+
# where `aStr` is a `std::stringstream`. In inlined opt builds, this calls
152+
# `operator new()` and `operator delete` for a temporary.
153+
"Debug.o",
150154
]
151155
all_ignored_files = set((f, 1) for f in ignored_files)
152156

mozglue/misc/Debug.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include "mozilla/glue/Debug.h"
8+
#include "mozilla/Fuzzing.h"
9+
#include "mozilla/Sprintf.h"
10+
11+
#include <stdarg.h>
12+
#include <stdio.h>
13+
14+
#ifdef XP_WIN
15+
# include <io.h>
16+
# include <windows.h>
17+
#endif
18+
19+
#ifdef ANDROID
20+
# include <android/log.h>
21+
#endif
22+
23+
#ifndef ANDROID
24+
static void vprintf_stderr_buffered(const char* aFmt, va_list aArgs) {
25+
// Avoid interleaving by writing to an on-stack buffer and then writing in one
26+
// go with fputs, as long as the output fits into the buffer.
27+
char buffer[1024];
28+
va_list argsCpy;
29+
va_copy(argsCpy, aArgs);
30+
int n = VsprintfLiteral(buffer, aFmt, aArgs);
31+
if (n < int(sizeof(buffer))) {
32+
fputs(buffer, stderr);
33+
} else {
34+
// Message too long for buffer. Just print it, not worrying about
35+
// interleaving. (We could malloc, but the underlying write() syscall could
36+
// get interleaved if the output is too big anyway.)
37+
vfprintf(stderr, aFmt, argsCpy);
38+
}
39+
va_end(argsCpy);
40+
fflush(stderr);
41+
}
42+
#endif
43+
44+
#if defined(XP_WIN)
45+
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
46+
if (IsDebuggerPresent()) {
47+
int lengthNeeded = _vscprintf(aFmt, aArgs);
48+
if (lengthNeeded) {
49+
lengthNeeded++;
50+
auto buf = mozilla::MakeUnique<char[]>(lengthNeeded);
51+
if (buf) {
52+
va_list argsCpy;
53+
va_copy(argsCpy, aArgs);
54+
vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy);
55+
buf[lengthNeeded - 1] = '\0';
56+
va_end(argsCpy);
57+
OutputDebugStringA(buf.get());
58+
}
59+
}
60+
}
61+
62+
vprintf_stderr_buffered(aFmt, aArgs);
63+
}
64+
65+
#elif defined(ANDROID)
66+
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
67+
__android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs);
68+
}
69+
#elif defined(FUZZING_SNAPSHOT)
70+
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
71+
if (nyx_puts) {
72+
auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs);
73+
nyx_puts(msgbuf.get());
74+
} else {
75+
vprintf_stderr_buffered(aFmt, aArgs);
76+
}
77+
}
78+
#else
79+
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs) {
80+
vprintf_stderr_buffered(aFmt, aArgs);
81+
}
82+
#endif
83+
84+
MFBT_API void printf_stderr(const char* aFmt, ...) {
85+
va_list args;
86+
va_start(args, aFmt);
87+
vprintf_stderr(aFmt, args);
88+
va_end(args);
89+
}
90+
91+
MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...) {
92+
va_list args;
93+
va_start(args, aFmt);
94+
if (aFile == stderr) {
95+
vprintf_stderr(aFmt, args);
96+
} else {
97+
vfprintf(aFile, aFmt, args);
98+
}
99+
va_end(args);
100+
}
101+
102+
MFBT_API void print_stderr(std::stringstream& aStr) {
103+
#if defined(ANDROID)
104+
// On Android logcat output is truncated to 1024 chars per line, and
105+
// we usually use std::stringstream to build up giant multi-line gobs
106+
// of output. So to avoid the truncation we find the newlines and
107+
// print the lines individually.
108+
std::string line;
109+
while (std::getline(aStr, line)) {
110+
printf_stderr("%s\n", line.c_str());
111+
}
112+
#else
113+
printf_stderr("%s", aStr.str().c_str());
114+
#endif
115+
}
116+
117+
MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr) {
118+
if (aFile == stderr) {
119+
print_stderr(aStr);
120+
} else {
121+
fprintf_stderr(aFile, "%s", aStr.str().c_str());
122+
}
123+
}

mozglue/misc/Debug.h

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
#ifndef mozilla_glue_Debug_h
88
#define mozilla_glue_Debug_h
99

10+
#include "mozilla/Attributes.h" // For MOZ_FORMAT_PRINTF
11+
#include "mozilla/Types.h" // For MFBT_API
12+
13+
#include <cstdarg>
14+
#include <sstream>
15+
1016
/* This header file intends to supply debugging utilities for use in code
1117
* that cannot use XPCOM debugging facilities like nsDebug.h.
1218
* e.g. mozglue, browser/app
@@ -15,52 +21,53 @@
1521
* care; avoid including from header files.
1622
*/
1723

18-
#include <io.h>
19-
#if defined(XP_WIN)
20-
# include <windows.h>
21-
#endif // defined(XP_WIN)
22-
#include "mozilla/Attributes.h"
23-
#include "mozilla/Sprintf.h"
24-
25-
#if defined(MOZILLA_INTERNAL_API)
26-
# error Do not include this file from XUL sources.
27-
#endif
28-
29-
// Though this is a separate implementation than nsDebug's, we want to make the
30-
// declarations compatible to avoid confusing the linker if both headers are
31-
// included.
3224
#ifdef __cplusplus
3325
extern "C" {
3426
#endif // __cplusplus
3527

36-
void printf_stderr(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2);
37-
inline void printf_stderr(const char* fmt, ...) {
38-
#if defined(XP_WIN)
39-
if (IsDebuggerPresent()) {
40-
char buf[2048];
41-
va_list args;
42-
va_start(args, fmt);
43-
VsprintfLiteral(buf, fmt, args);
44-
va_end(args);
45-
OutputDebugStringA(buf);
46-
}
47-
#endif // defined(XP_WIN)
48-
49-
// stderr is unbuffered by default so we open a new FILE (which is buffered)
50-
// so that calls to printf_stderr are not as likely to get mixed together.
51-
int fd = _fileno(stderr);
52-
if (fd == -2) return;
28+
/**
29+
* printf_stderr(...) is much like fprintf(stderr, ...), except that:
30+
* - on Android and Firefox OS, *instead* of printing to stderr, it
31+
* prints to logcat. (Newlines in the string lead to multiple lines
32+
* of logcat, but each function call implicitly completes a line even
33+
* if the string does not end with a newline.)
34+
* - on Windows, if a debugger is present, it calls OutputDebugString
35+
* in *addition* to writing to stderr
36+
*/
37+
MFBT_API void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2);
5338

54-
FILE* fp = _fdopen(_dup(fd), "a");
55-
if (!fp) return;
39+
/**
40+
* Same as printf_stderr, but taking va_list instead of varargs
41+
*/
42+
MFBT_API void vprintf_stderr(const char* aFmt, va_list aArgs)
43+
MOZ_FORMAT_PRINTF(1, 0);
5644

57-
va_list args;
58-
va_start(args, fmt);
59-
vfprintf(fp, fmt, args);
60-
va_end(args);
45+
/**
46+
* fprintf_stderr is like fprintf, except that if its file argument
47+
* is stderr, it invokes printf_stderr instead.
48+
*
49+
* This is useful for general debugging code that logs information to a
50+
* file, but that you would like to be useful on Android and Firefox OS.
51+
* If you use fprintf_stderr instead of fprintf in such debugging code,
52+
* then callers can pass stderr to get logging that works on Android and
53+
* Firefox OS (and also the other side-effects of using printf_stderr).
54+
*
55+
* Code that is structured this way needs to be careful not to split a
56+
* line of output across multiple calls to fprintf_stderr, since doing
57+
* so will cause it to appear in multiple lines in logcat output.
58+
* (Producing multiple lines at once is fine.)
59+
*/
60+
MFBT_API void fprintf_stderr(FILE* aFile, const char* aFmt, ...)
61+
MOZ_FORMAT_PRINTF(2, 3);
6162

62-
fclose(fp);
63-
}
63+
/*
64+
* print_stderr and fprint_stderr are like printf_stderr and fprintf_stderr,
65+
* except they deal with Android logcat line length limitations. They do this
66+
* by printing individual lines out of the provided stringstream using separate
67+
* calls to logcat.
68+
*/
69+
MFBT_API void print_stderr(std::stringstream& aStr);
70+
MFBT_API void fprint_stderr(FILE* aFile, std::stringstream& aStr);
6471

6572
#ifdef __cplusplus
6673
}

mozglue/misc/moz.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ if CONFIG["OS_ARCH"] == "WINNT":
4343
SOURCES += [
4444
"AutoProfilerLabel.cpp",
4545
"AwakeTimeStamp.cpp",
46+
"Debug.cpp",
4647
"MmapFaultHandler.cpp",
4748
"Printf.cpp",
4849
"SIMD.cpp",

xpcom/base/nsCRTGlue.cpp

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919
#ifdef XP_WIN
2020
# include <io.h>
2121
# include <windows.h>
22-
# include "mozilla/UniquePtr.h"
23-
#endif
24-
25-
#ifdef ANDROID
26-
# include <android/log.h>
2722
#endif
2823

2924
#ifdef FUZZING_SNAPSHOT
@@ -229,105 +224,3 @@ void NS_MakeRandomString(char* aBuf, int32_t aBufLen) {
229224
}
230225

231226
#endif
232-
233-
#ifndef ANDROID
234-
void vprintf_stderr_buffered(const char* aFmt, va_list aArgs) {
235-
// Avoid interleaving by writing to an on-stack buffer and then writing in one
236-
// go with fputs, as long as the output fits into the buffer.
237-
char buffer[1024];
238-
va_list argsCpy;
239-
va_copy(argsCpy, aArgs);
240-
int n = VsprintfLiteral(buffer, aFmt, aArgs);
241-
if (n < sizeof(buffer)) {
242-
fputs(buffer, stderr);
243-
} else {
244-
// Message too long for buffer. Just print it, not worrying about
245-
// interleaving. (We could malloc, but the underlying write() syscall could
246-
// get interleaved if the output is too big anyway.)
247-
vfprintf(stderr, aFmt, argsCpy);
248-
}
249-
va_end(argsCpy);
250-
fflush(stderr);
251-
}
252-
#endif
253-
254-
#if defined(XP_WIN)
255-
void vprintf_stderr(const char* aFmt, va_list aArgs) {
256-
if (IsDebuggerPresent()) {
257-
int lengthNeeded = _vscprintf(aFmt, aArgs);
258-
if (lengthNeeded) {
259-
lengthNeeded++;
260-
auto buf = MakeUnique<char[]>(lengthNeeded);
261-
if (buf) {
262-
va_list argsCpy;
263-
va_copy(argsCpy, aArgs);
264-
vsnprintf(buf.get(), lengthNeeded, aFmt, argsCpy);
265-
buf[lengthNeeded - 1] = '\0';
266-
va_end(argsCpy);
267-
OutputDebugStringA(buf.get());
268-
}
269-
}
270-
}
271-
272-
vprintf_stderr_buffered(aFmt, aArgs);
273-
}
274-
275-
#elif defined(ANDROID)
276-
void vprintf_stderr(const char* aFmt, va_list aArgs) {
277-
__android_log_vprint(ANDROID_LOG_INFO, "Gecko", aFmt, aArgs);
278-
}
279-
#elif defined(FUZZING_SNAPSHOT)
280-
void vprintf_stderr(const char* aFmt, va_list aArgs) {
281-
if (nyx_puts) {
282-
auto msgbuf = mozilla::Vsmprintf(aFmt, aArgs);
283-
nyx_puts(msgbuf.get());
284-
} else {
285-
vprintf_stderr_buffered(aFmt, aArgs);
286-
}
287-
}
288-
#else
289-
void vprintf_stderr(const char* aFmt, va_list aArgs) {
290-
vprintf_stderr_buffered(aFmt, aArgs);
291-
}
292-
#endif
293-
294-
void printf_stderr(const char* aFmt, ...) {
295-
va_list args;
296-
va_start(args, aFmt);
297-
vprintf_stderr(aFmt, args);
298-
va_end(args);
299-
}
300-
301-
void fprintf_stderr(FILE* aFile, const char* aFmt, ...) {
302-
va_list args;
303-
va_start(args, aFmt);
304-
if (aFile == stderr) {
305-
vprintf_stderr(aFmt, args);
306-
} else {
307-
vfprintf(aFile, aFmt, args);
308-
}
309-
va_end(args);
310-
}
311-
312-
void print_stderr(std::stringstream& aStr) {
313-
#if defined(ANDROID)
314-
// On Android logcat output is truncated to 1024 chars per line, and
315-
// we usually use std::stringstream to build up giant multi-line gobs
316-
// of output. So to avoid the truncation we find the newlines and
317-
// print the lines individually.
318-
std::string line;
319-
while (std::getline(aStr, line)) {
320-
printf_stderr("%s\n", line.c_str());
321-
}
322-
#else
323-
printf_stderr("%s", aStr.str().c_str());
324-
#endif
325-
}
326-
327-
void fprint_stderr(FILE* aFile, std::stringstream& aStr) {
328-
if (aFile == stderr) {
329-
print_stderr(aStr);
330-
} else {
331-
fprintf_stderr(aFile, "%s", aStr.str().c_str());
332-
}
333-
}

0 commit comments

Comments
 (0)