Skip to content

A global initialized from another global reads garbage (heap-typed globals; crash with a class) #446

Closed

Description

@ASDAlexander77

A module-level variable initialized from another module-level variable whose value lives on the heap (an array, a class instance) reads garbage. With a class instance the program dies with a breakpoint trap. This happens under every memory model, with or without the default library. Number globals are not affected.

let a: number[] = [1, 2];
let b = a;

function main() {
    print(a.length, b.length);
}
tslang --emit=jit --no-default-lib -mm=gc globals.ts
2 140711081380496

b.length under the other models: rc 54, none 866. With const instead of let it is the same: print(b2.length) gives 296043999152.

With a class instance it crashes:

class C {
    v = 5;
}

const a = new C();
const b = a;

function main() {
    print(b.v);
}

Under gc, rc and none, JIT fails with Exception Code: 0x80000003, and ahead-of-time compilation (test-runner) fails with exit code -2147483645 (also 0x80000003).

Control case: let a3 = 7; let b3 = a3; prints 7.

Likely cause

Each global gets its own initializer function, and both are listed in llvm.global_ctors with the same priority:

@a = private global { ptr, i64 } undef
@b = private global { ptr, i64 } undef
@llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1000, ptr @a__cctor, ptr null }, { i32, ptr, ptr } { i32 1000, ptr @b__cctor, ptr null }]

b's initializer region is just Load(AddressOf @a). LLVM leaves the order of equal-priority constructors unspecified. If b__cctor runs first, b copies a while a is still undef. A number initializer is folded to a constant, which is why number globals are unaffected.

Possible fixes:

  • give each initializer a priority that follows declaration order;
  • run all of a module's initializers from one function, in declaration order.

Found during -mm=own phase 6 (#445, spec §20.5).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions