Skip to content

Commit d07f6b5

Browse files
authored
Handle unprintable objects better in print() (#834)
Before this commit, such objects were printed as `<exception>` because print() and console.log() had no good way to turn them into strings. Instead perform the C equivalent of Object.prototype.toString.call(o) and print the result (which can still error but at least we tried.) Fixes: #832
1 parent c5a47b4 commit d07f6b5

File tree

7 files changed

+35
-9
lines changed

7 files changed

+35
-9
lines changed

quickjs-libc.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3984,12 +3984,20 @@ static JSValue js_print(JSContext *ctx, JSValue this_val,
39843984
DWORD mode;
39853985
#endif
39863986
const char *s;
3987+
JSValue v;
39873988
DynBuf b;
39883989
int i;
39893990

39903991
dbuf_init(&b);
39913992
for(i = 0; i < argc; i++) {
3992-
s = JS_ToCString(ctx, argv[i]);
3993+
v = argv[i];
3994+
s = JS_ToCString(ctx, v);
3995+
if (!s && JS_IsObject(v)) {
3996+
JS_FreeValue(ctx, JS_GetException(ctx));
3997+
v = JS_ToObjectString(ctx, v);
3998+
s = JS_ToCString(ctx, v);
3999+
JS_FreeValue(ctx, v);
4000+
}
39934001
if (s) {
39944002
dbuf_printf(&b, "%s%s", &" "[!i], s);
39954003
JS_FreeCString(ctx, s);

quickjs.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37079,6 +37079,11 @@ static JSValue js_object_toString(JSContext *ctx, JSValue this_val,
3707937079
return JS_ConcatString3(ctx, "[object ", tag, "]");
3708037080
}
3708137081

37082+
JSValue JS_ToObjectString(JSContext *ctx, JSValue val)
37083+
{
37084+
return js_object_toString(ctx, val, 0, NULL);
37085+
}
37086+
3708237087
static JSValue js_object_toLocaleString(JSContext *ctx, JSValue this_val,
3708337088
int argc, JSValue *argv)
3708437089
{

quickjs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, int class_id);
694694
JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValue proto);
695695
JS_EXTERN JSValue JS_NewObject(JSContext *ctx);
696696
JS_EXTERN JSValue JS_ToObject(JSContext *ctx, JSValue val);
697+
JS_EXTERN JSValue JS_ToObjectString(JSContext *ctx, JSValue val);
697698

698699
JS_EXTERN bool JS_IsFunction(JSContext* ctx, JSValue val);
699700
JS_EXTERN bool JS_IsConstructor(JSContext* ctx, JSValue val);

run-test262.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -463,26 +463,35 @@ static JSValue js_print_262(JSContext *ctx, JSValue this_val,
463463
int argc, JSValue *argv)
464464
{
465465
ThreadLocalStorage *tls = JS_GetRuntimeOpaque(JS_GetRuntime(ctx));
466+
const char *s;
467+
JSValue v;
466468
int i;
467-
const char *str;
468469

469470
for (i = 0; i < argc; i++) {
470-
str = JS_ToCString(ctx, argv[i]);
471-
if (!str)
471+
v = argv[i];
472+
s = JS_ToCString(ctx, v);
473+
// same logic as js_print in quickjs-libc.c
474+
if (local && !s && JS_IsObject(v)) {
475+
JS_FreeValue(ctx, JS_GetException(ctx));
476+
v = JS_ToObjectString(ctx, v);
477+
s = JS_ToCString(ctx, v);
478+
JS_FreeValue(ctx, v);
479+
}
480+
if (!s)
472481
return JS_EXCEPTION;
473-
if (!strcmp(str, "Test262:AsyncTestComplete")) {
482+
if (!strcmp(s, "Test262:AsyncTestComplete")) {
474483
tls->async_done++;
475-
} else if (js__strstart(str, "Test262:AsyncTestFailure", NULL)) {
484+
} else if (js__strstart(s, "Test262:AsyncTestFailure", NULL)) {
476485
tls->async_done = 2; /* force an error */
477486
}
478487
if (outfile) {
479488
if (i != 0)
480489
fputc(' ', outfile);
481-
fputs(str, outfile);
490+
fputs(s, outfile);
482491
}
483492
if (verbose > 1)
484-
printf("%s%s", &" "[i < 1], str);
485-
JS_FreeCString(ctx, str);
493+
printf("%s%s", &" "[i < 1], s);
494+
JS_FreeCString(ctx, s);
486495
}
487496
if (outfile)
488497
fputc('\n', outfile);

tests.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ verbose=yes
44
testdir=tests
55

66
[exclude]
7+
tests/empty.js
78
tests/fixture_cyclic_import.js
89
tests/microbench.js
910
tests/test_worker_module.js

tests/bug832.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const m = await import("./empty.js")
2+
print(m) // should not throw

tests/empty.js

Whitespace-only changes.

0 commit comments

Comments
 (0)