Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Out of memory crash with noErrorTruncation #37230

Closed
mprobst opened this issue Mar 5, 2020 · 3 comments
Closed

Out of memory crash with noErrorTruncation #37230

mprobst opened this issue Mar 5, 2020 · 3 comments
Assignees
Labels
Bug A bug in TypeScript Crash For flagging bugs which are compiler or service crashes or unclean exits, rather than bad output

Comments

@mprobst
Copy link
Contributor

mprobst commented Mar 5, 2020

TypeScript Version: Version 3.9.0-dev.20200305

Search Terms:

JavaScript heap out of memory, oom, noErrorTruncation

Code

import 'jasmine';
import 'figma';

declare function exp<T>(actual: ArrayLike<T>): jasmine.ArrayLikeMatchers<T>;
declare function exp<T>(actual: T): jasmine.Matchers<T>;

const selection: SceneNode[] = [];
const frames: FrameNode[] = [];
exp(frames).toEqual(selection);

Install the required types (npm install @types/jasmine @types/figma), then run tsc --noErrorTruncation

Expected behavior:

Report an error due to frames not having the same type as selection.

Actual behavior:

TypeScript crashes with OOM:

    0: ExitFrame [pc: 0x134e879]
Security context: 0x0db089340919 <JSObject>
    1: typeToTypeNodeHelper(aka typeToTypeNodeHelper) [0x30aa8fe76f81] [/usr/local/google/home/martinprobst/.config/yarn/global/node_modules/typescript/lib/tsc.js:~29667] [pc
=0x139e7d8b8e3b](this=0x1b27d36004d1 <undefined>,0x1a24cbd9b629 <Type map = 0x3d5b18402439>,0x299249254b31 <Object map = 0x3d5b1840d1a9>)
    2: typeReferenceToTypeNode(aka typeReferenceToTyp...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x9bcb80 node::Abort() [node]
 2: 0x9bdd16 node::OnFatalError(char const*, char const*) [node]
 3: 0xb1948e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xb19809 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]

I strongly suspect TypeScript runs into an (at least effectively) infinite loop here: this crashes with 2 GB max heap for node, but also with 8 GB.

From a bit of debugging, it seems that TypeScript endlessly recurses through Jasmine's ExpectedRecursive<T> type:

declare namespace jasmine {
    // ...
    type ExpectedRecursive<T> = T | ObjectContaining<T> | AsymmetricMatcher<any> | {
        [K in keyof T]: ExpectedRecursive<T[K]> | Any;
    };
}

As it tries to produce a diagnostic string via typeToTypeNode, it keeps coming through the anonymous inline type here.

Playground Link: n/a (though probably possible to reduce the required type signatures from @types)

Related Issues: n/a

@DanielRosenwasser DanielRosenwasser added the Crash For flagging bugs which are compiler or service crashes or unclean exits, rather than bad output label Mar 5, 2020
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 3.9.0 milestone Mar 5, 2020
@DanielRosenwasser DanielRosenwasser added the Bug A bug in TypeScript label Mar 5, 2020
@alumni
Copy link

alumni commented Mar 18, 2020

I have a similar issue in version 3.8.3:

<--- Last few GCs --->

[13400:000001F0D3429FE0]    54353 ms: Mark-sweep 2041.5 (2050.0) -> 2041.4 (2050.0) MB, 1135.0 / 0.0 ms  (average mu = 0.152, current mu = 0.000) allocation failure GC in old space requested
[13400:000001F0D3429FE0]    55464 ms: Mark-sweep 2041.4 (2050.0) -> 2041.4 (2050.0) MB, 1110.8 / 0.0 ms  (average mu = 0.082, current mu = 0.000) last resort GC in old space requested


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 00007FF7792A528D]
Security context: 0x008826840921 <JSObject>
    1: set [00000088268466E1](this=0x0231bf893529 <Map map = 00000238DBE00F31>,0x00b7c6dd69b1 <String[8]: 68,21171>,1)
    2: recursiveTypeRelatedTo(aka recursiveTypeRelatedTo) [000000B7C6DDDEC9] [XXX\node_modules\typescript\lib\tsc.js:40142] [bytecode=000000BEAA432969 offset=607](this=0x01782bb404b9 <undefined>...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 00007FF77868D98F napi_wrap+111663
 2: 00007FF77862C406 v8::base::CPU::has_sse+57574
 3: 00007FF77862D2A3 v8::base::CPU::has_sse+61315
 4: 00007FF778E5B93E v8::Isolate::ReportExternalAllocationLimitReached+94
 5: 00007FF778E43091 v8::SharedArrayBuffer::Externalize+785
 6: 00007FF778D0A0FC v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1468
 7: 00007FF778D15440 v8::internal::Heap::ProtectUnprotectedMemoryChunks+1312
 8: 00007FF778D11F34 v8::internal::Heap::PageFlagsAreConsistent+3188
 9: 00007FF778D07643 v8::internal::Heap::CollectGarbage+1283
10: 00007FF778D06A14 v8::internal::Heap::CollectAllAvailableGarbage+196
11: 00007FF778D05E54 v8::internal::Heap::AllocateExternalBackingStore+1524
12: 00007FF778D209BD v8::internal::Factory::AllocateRawArray+173
13: 00007FF778D27FD7 v8::internal::Factory::NewFixedArrayWithFiller+87
14: 00007FF778D2020A v8::internal::Factory::InternalizeString<unsigned short>+474
15: 00007FF778B5A57B v8::internal::OrderedHashTable<v8::internal::OrderedHashMap,2>::Allocate+123
16: 00007FF778B5CAFB v8::internal::OrderedHashTable<v8::internal::OrderedHashMap,2>::Rehash+59
17: 00007FF778B5B92A v8::internal::OrderedHashTable<v8::internal::OrderedHashMap,2>::EnsureGrowable+90
18: 00007FF778A9DBF2 v8::internal::interpreter::JumpTableTargetOffsets::iterator::operator=+114706
19: 00007FF7792A528D v8::internal::SetupIsolateDelegate::SetupHeap+517453
20: 00007FF779273026 v8::internal::SetupIsolateDelegate::SetupHeap+312038
21: 00007FF779230BAB v8::internal::SetupIsolateDelegate::SetupHeap+40555
22: 000003665BD54E79

@weswigham
Copy link
Member

@alumni - that dump looks like it occurs in recursiveTypeRelatedTo - it's almost definitely not the same root cause. If you could isolate a small repro and open a new issue, that'd be great, thanks~

@ahejlsberg
Copy link
Member

Verified that this is fixed by #37461.

kyliau pushed a commit to bazelbuild/rules_typescript that referenced this issue Mar 31, 2020
TypeScript runs out of memory trying to produce a human readable
diagnostic in certain situations (infinitely recursing through anonymous
type), see microsoft/TypeScript#37230.

That's a bug, but more generally speaking, the default TypeScript
behaviour is to run with error truncation. That's for a reason: some
errors are much more readable with truncation. TypeScript's core team
made the call that error truncation is generally a good idea, so we
should follow along unless we have strong data indication otherwise
(which we don't).

Beyond that, error truncation being the default means it is the better
tested path, so we'll probably save us some trouble in the future by
keeping it enabled.

PiperOrigin-RevId: 299096788
alexeagle pushed a commit to alexeagle/rules_nodejs that referenced this issue Oct 17, 2020
TypeScript runs out of memory trying to produce a human readable
diagnostic in certain situations (infinitely recursing through anonymous
type), see microsoft/TypeScript#37230.

That's a bug, but more generally speaking, the default TypeScript
behaviour is to run with error truncation. That's for a reason: some
errors are much more readable with truncation. TypeScript's core team
made the call that error truncation is generally a good idea, so we
should follow along unless we have strong data indication otherwise
(which we don't).

Beyond that, error truncation being the default means it is the better
tested path, so we'll probably save us some trouble in the future by
keeping it enabled.

PiperOrigin-RevId: 299096788
alexeagle pushed a commit to alexeagle/rules_nodejs that referenced this issue Oct 18, 2020
TypeScript runs out of memory trying to produce a human readable
diagnostic in certain situations (infinitely recursing through anonymous
type), see microsoft/TypeScript#37230.

That's a bug, but more generally speaking, the default TypeScript
behaviour is to run with error truncation. That's for a reason: some
errors are much more readable with truncation. TypeScript's core team
made the call that error truncation is generally a good idea, so we
should follow along unless we have strong data indication otherwise
(which we don't).

Beyond that, error truncation being the default means it is the better
tested path, so we'll probably save us some trouble in the future by
keeping it enabled.

PiperOrigin-RevId: 299096788
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Crash For flagging bugs which are compiler or service crashes or unclean exits, rather than bad output
Projects
None yet
Development

No branches or pull requests

5 participants