Skip to content

Commit d1e1744

Browse files
committed
core: implement runtime flag to pring warn on sync
Use the --warn-on-sync flag to print a stack trace whenever a sync method is used. (e.g. fs.readFileSync()) It does not track if the warning has occurred as a specific location in the past and so will print the warning every time the function is used. This does not print the warning for the first synchronous execution of the script. This will allow all the require(), etc. statements to run that are necessary to prepare the environment.
1 parent 4e2f999 commit d1e1744

9 files changed

+67
-1
lines changed

src/env-inl.h

+29
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ inline Environment::Environment(v8::Local<v8::Context> context,
176176
using_abort_on_uncaught_exc_(false),
177177
using_asyncwrap_(false),
178178
printed_error_(false),
179+
warn_on_sync_(false),
179180
debugger_agent_(this),
180181
context_(context->GetIsolate(), context) {
181182
// We'll be creating new objects so make sure we've entered the context.
@@ -325,6 +326,34 @@ inline void Environment::set_printed_error(bool value) {
325326
printed_error_ = value;
326327
}
327328

329+
inline void Environment::print_sync_warn() const {
330+
if (!warn_on_sync_)
331+
return;
332+
333+
v8::HandleScope handle_scope(isolate_);
334+
v8::Local<v8::StackTrace> stack = v8::StackTrace::CurrentStackTrace(
335+
isolate_, 10, v8::StackTrace::kDetailed);
336+
337+
fprintf(stderr, "WARNING: Detected use of sync API\n");
338+
for (int i = 0; i < stack->GetFrameCount() - 1; i++) {
339+
v8::Local<v8::StackFrame> sf = stack->GetFrame(i);
340+
node::Utf8Value fn_s(isolate_, sf->GetFunctionName());
341+
const char* fn;
342+
if (strcmp(*fn_s, "") == 0)
343+
fn = "(anonymous)";
344+
else
345+
fn = *fn_s;
346+
node::Utf8Value m(isolate_, sf->GetScriptName());
347+
int ln = sf->GetLineNumber();
348+
int cl = sf->GetColumn();
349+
fprintf(stderr, " at %s (%s:%i:%i)\n", fn, *m, ln, cl);
350+
}
351+
}
352+
353+
inline void Environment::set_warn_on_sync(bool value) {
354+
warn_on_sync_ = value;
355+
}
356+
328357
inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
329358
return ContainerOf(&Environment::cares_timer_handle_, handle);
330359
}

src/env.h

+4
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,9 @@ class Environment {
420420
inline bool printed_error() const;
421421
inline void set_printed_error(bool value);
422422

423+
inline void print_sync_warn() const;
424+
inline void set_warn_on_sync(bool value);
425+
423426
inline void ThrowError(const char* errmsg);
424427
inline void ThrowTypeError(const char* errmsg);
425428
inline void ThrowRangeError(const char* errmsg);
@@ -506,6 +509,7 @@ class Environment {
506509
bool using_abort_on_uncaught_exc_;
507510
bool using_asyncwrap_;
508511
bool printed_error_;
512+
bool warn_on_sync_;
509513
debugger::Agent debugger_agent_;
510514

511515
HandleWrapQueue handle_wrap_queue_;

src/node.cc

+23
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ using v8::Promise;
102102
using v8::PromiseRejectMessage;
103103
using v8::PropertyCallbackInfo;
104104
using v8::SealHandleScope;
105+
using v8::StackFrame;
106+
using v8::StackTrace;
105107
using v8::String;
106108
using v8::TryCatch;
107109
using v8::Uint32;
@@ -114,6 +116,7 @@ static bool force_repl = false;
114116
static bool trace_deprecation = false;
115117
static bool throw_deprecation = false;
116118
static bool abort_on_uncaught_exception = false;
119+
static bool warn_on_sync = false;
117120
static const char* eval_string = nullptr;
118121
static unsigned int preload_module_count = 0;
119122
static const char** preload_modules = nullptr;
@@ -1019,6 +1022,14 @@ void SetupPromises(const FunctionCallbackInfo<Value>& args) {
10191022
}
10201023

10211024

1025+
void EnableSyncWarn(const FunctionCallbackInfo<Value>& args) {
1026+
Environment* env = Environment::GetCurrent(args);
1027+
env->set_warn_on_sync(true);
1028+
env->process_object()->Delete(
1029+
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_enableSyncWarn"));
1030+
}
1031+
1032+
10221033
Handle<Value> MakeCallback(Environment* env,
10231034
Handle<Value> recv,
10241035
const Handle<Function> callback,
@@ -2834,6 +2845,14 @@ void SetupProcessObject(Environment* env,
28342845
READONLY_PROPERTY(process, "traceDeprecation", True(env->isolate()));
28352846
}
28362847

2848+
// --warn-on-sync
2849+
if (warn_on_sync) {
2850+
READONLY_PROPERTY(process, "warnOnSync", True(env->isolate()));
2851+
// Only add this method if the flag has been enabled.
2852+
env->SetMethod(process, "_enableSyncWarn", EnableSyncWarn);
2853+
// Don't env->set_warn_on_sync(true) because it will be enabled from JS.
2854+
}
2855+
28372856
size_t exec_path_len = 2 * PATH_MAX;
28382857
char* exec_path = new char[exec_path_len];
28392858
Local<String> exec_path_value;
@@ -3061,6 +3080,8 @@ static void PrintHelp() {
30613080
"function is used\n"
30623081
" --trace-deprecation show stack traces on deprecations\n"
30633082
" --v8-options print v8 command line options\n"
3083+
" --warn-on-sync print warning message when sync\n"
3084+
" function is used\n"
30643085
#if defined(NODE_HAVE_I18N_SUPPORT)
30653086
" --icu-data-dir=dir set ICU data load path to dir\n"
30663087
" (overrides NODE_ICU_DATA)\n"
@@ -3180,6 +3201,8 @@ static void ParseArgs(int* argc,
31803201
no_deprecation = true;
31813202
} else if (strcmp(arg, "--trace-deprecation") == 0) {
31823203
trace_deprecation = true;
3204+
} else if (strcmp(arg, "--warn-on-sync") == 0) {
3205+
warn_on_sync = true;
31833206
} else if (strcmp(arg, "--throw-deprecation") == 0) {
31843207
throw_deprecation = true;
31853208
} else if (strcmp(arg, "--abort-on-uncaught-exception") == 0 ||

src/node.h

+1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ NODE_DEPRECATED("Use DecodeWrite(isolate, ...)",
335335
return DecodeWrite(v8::Isolate::GetCurrent(), buf, buflen, val, encoding);
336336
})
337337

338+
338339
#ifdef _WIN32
339340
NODE_EXTERN v8::Local<v8::Value> WinapiErrnoException(
340341
v8::Isolate* isolate,

src/node.js

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545

4646
process.argv[0] = process.execPath;
4747

48+
if (process.warnOnSync)
49+
process.nextTick(process._enableSyncWarn);
50+
4851
// There are various modes that Node can run in. The most common two
4952
// are running from a script and running the REPL - but there are a few
5053
// others like the debugger or running --eval arguments. Here we decide

src/node_crypto.cc

+2
Original file line numberDiff line numberDiff line change
@@ -4630,6 +4630,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
46304630
EIO_PBKDF2,
46314631
EIO_PBKDF2After);
46324632
} else {
4633+
env->print_sync_warn();
46334634
Local<Value> argv[2];
46344635
EIO_PBKDF2(req);
46354636
EIO_PBKDF2After(req, argv);
@@ -4786,6 +4787,7 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
47864787
RandomBytesAfter);
47874788
args.GetReturnValue().Set(obj);
47884789
} else {
4790+
env->print_sync_warn();
47894791
Local<Value> argv[2];
47904792
RandomBytesWork(req->work_req());
47914793
RandomBytesCheck(req, argv);

src/node_file.cc

+1
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ struct fs_req_wrap {
280280

281281
#define SYNC_DEST_CALL(func, path, dest, ...) \
282282
fs_req_wrap req_wrap; \
283+
env->print_sync_warn(); \
283284
int err = uv_fs_ ## func(env->event_loop(), \
284285
&req_wrap.req, \
285286
__VA_ARGS__, \

src/node_zlib.cc

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class ZCtx : public AsyncWrap {
180180
ctx->chunk_size_ = out_len;
181181

182182
if (!async) {
183+
ctx->env()->print_sync_warn();
183184
// sync version
184185
Process(work_req);
185186
if (CheckError(ctx))

src/spawn_sync.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,9 @@ void SyncProcessRunner::Initialize(Handle<Object> target,
349349

350350

351351
void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
352-
SyncProcessRunner p(Environment::GetCurrent(args));
352+
Environment* env = Environment::GetCurrent(args);
353+
env->print_sync_warn();
354+
SyncProcessRunner p(env);
353355
Local<Value> result = p.Run(args[0]);
354356
args.GetReturnValue().Set(result);
355357
}

0 commit comments

Comments
 (0)