Skip to content

Commit 05ff8b8

Browse files
authored
fix: runtime segfault when console.log prints null interface or undefined array values (#517)
Co-authored-by: cs01 <cs01@users.noreply.github.com>
1 parent 00ce0a6 commit 05ff8b8

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

src/codegen/expressions/method-calls/console.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ function emitArrayPrint(
6969
arrayPtr: string,
7070
arrayType: "Array" | "StringArray" | "ObjectArray",
7171
): void {
72+
const arrCast = ctx.nextTemp();
73+
ctx.emit(`${arrCast} = ptrtoint %${arrayType}* ${arrayPtr} to i64`);
74+
const arrIsNull = ctx.emitIcmp("eq", "i64", arrCast, "0");
75+
const arrNullLabel = ctx.nextLabel("arr_null");
76+
const arrNonNullLabel = ctx.nextLabel("arr_nonnull");
77+
ctx.emitBrCond(arrIsNull, arrNullLabel, arrNonNullLabel);
78+
ctx.emitLabel(arrNullLabel);
79+
const undefStr = ctx.stringGen.doCreateStringConstant("undefined");
80+
emitPrintStrNoNl(ctx, useStderr, undefStr);
81+
const arrDoneNullLabel = ctx.nextLabel("arr_done_null");
82+
ctx.emitBr(arrDoneNullLabel);
83+
ctx.emitLabel(arrNonNullLabel);
84+
7285
const lenPtr = ctx.nextTemp();
7386
ctx.emit(
7487
`${lenPtr} = getelementptr inbounds %${arrayType}, %${arrayType}* ${arrayPtr}, i32 0, i32 1`,
@@ -164,6 +177,8 @@ function emitArrayPrint(
164177
ctx.emitBr(doneLabel);
165178

166179
ctx.emitLabel(doneLabel);
180+
ctx.emitBr(arrDoneNullLabel);
181+
ctx.emitLabel(arrDoneNullLabel);
167182
}
168183

169184
function emitMapPrint(
@@ -513,13 +528,39 @@ function emitSingleArg(
513528
const ifaceType =
514529
ctx.symbolTable.getInterfaceType(varName) || ctx.symbolTable.getRawInterfaceType(varName);
515530
if (ifaceType) {
531+
const ptrVal = ctx.generateExpression(arg, params);
532+
const isNull = ctx.emitIcmp("eq", "i8*", ptrVal, "null");
533+
const nullLabel = ctx.nextLabel("console_null");
534+
const nonNullLabel = ctx.nextLabel("console_nonnull");
535+
const doneLabel = ctx.nextLabel("console_done");
536+
ctx.emitBrCond(isNull, nullLabel, nonNullLabel);
537+
ctx.emitLabel(nullLabel);
538+
const nullStr = ctx.stringGen.doCreateStringConstant("null");
539+
emitPrintStrNoNl(ctx, useStderr, nullStr);
540+
ctx.emitBr(doneLabel);
541+
ctx.emitLabel(nonNullLabel);
516542
const jsonStr = ctx.jsonGen.generateStringifyExpr(arg, params);
517543
emitPrintStrNoNl(ctx, useStderr, jsonStr);
544+
ctx.emitBr(doneLabel);
545+
ctx.emitLabel(doneLabel);
518546
return;
519547
}
520548
const cn = ctx.symbolTable.getClassName(varName);
521549
if (cn) {
550+
const clsPtr = ctx.generateExpression(arg, params);
551+
const clsIsNull = ctx.emitIcmp("eq", "i8*", clsPtr, "null");
552+
const clsNullLabel = ctx.nextLabel("console_cls_null");
553+
const clsNonNullLabel = ctx.nextLabel("console_cls_nonnull");
554+
const clsDoneLabel = ctx.nextLabel("console_cls_done");
555+
ctx.emitBrCond(clsIsNull, clsNullLabel, clsNonNullLabel);
556+
ctx.emitLabel(clsNullLabel);
557+
const clsNullStr = ctx.stringGen.doCreateStringConstant("null");
558+
emitPrintStrNoNl(ctx, useStderr, clsNullStr);
559+
ctx.emitBr(clsDoneLabel);
560+
ctx.emitLabel(clsNonNullLabel);
522561
emitClassInstancePrint(ctx, useStderr, arg, params, cn);
562+
ctx.emitBr(clsDoneLabel);
563+
ctx.emitLabel(clsDoneLabel);
523564
return;
524565
}
525566
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @test-description: console.log on null interface value prints null instead of segfaulting
2+
interface Item {
3+
name: string;
4+
}
5+
function f(): Item | null {
6+
return null;
7+
}
8+
const y = f();
9+
console.log(y);
10+
console.log("TEST_PASSED");
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @test-description: console.log on Map.get() miss for array value prints undefined instead of segfaulting
2+
const m = new Map<string, number[]>();
3+
const v = m.get("nope");
4+
console.log(v);
5+
console.log("TEST_PASSED");

0 commit comments

Comments
 (0)