deepkit / deepkit-framework

A new full-featured and high-performance TypeScript framework
https://deepkit.io/
MIT License
3.18k stars 121 forks source link

[type] infinite stack when resolving recursive type parameters #477

Closed timvandam closed 7 months ago

timvandam commented 11 months ago
class Abc<T> {}
export type JsonValue =
  | string
  | number
  | boolean
  | null
  | JsonValue[]
  | { [key: string]: JsonValue };
function repro<T extends JsonValue>(type?: ReceiveType<T>) {
    type = resolveReceiveType(type);
    return function aaa(): Abc<T> {
        return new Abc();
    };
}

const fun = repro<{ type: 'aaa'; ya: 'bbb' }>();

Running resolveReceiveType eventually causes a V8 OOM

marcj commented 7 months ago

That's fixed

alpharder commented 7 months ago

Hello @marcj , it seems that I'm getting a similar issue in the latest master, here's how it can be reproduced at development repo:

packages/type/tests/recursive-union.spec.ts:

import { test } from '@jest/globals';
import {cast} from "../src/serializer-facade";

type JSONValue = null | boolean | number | string | JSONObject | JSONArray;

type JSONArray = JSONValue[];

export type JSONObject = {
    [k: string]: JSONValue;
};

test('complex recursive union type does not cause stack size exceeding', () => {
    const user = cast<JSONObject>({ username: 'Peter' });
});

Then execute npm run test packages/type/tests/recursive-union.spec.ts.

Here's what I get: ``` FAIL packages/type/tests/recursive-union.spec.ts ✕ complex recursive union type does not cause stack size exceeding (53 ms) ● complex recursive union type does not cause stack size exceeding RangeError: Maximum call stack size exceeded 288 | } 289 | > 290 | export function collapsePath(path: (string | RuntimeCode)[], prefix?: string): string { | ^ 291 | return path.filter(v => !!v).map(v => v instanceof RuntimeCode ? v.code : JSON.stringify(v)).join(`+'.'+`) || `''`; 292 | } 293 | at collapsePath (src/serializer.ts:290:29) at handleUnion (src/serializer.ts:1675:120) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) at typeGuardArray (src/serializer.ts:1431:19) at src/serializer.ts:2173:76 at createTypeGuardFunction (src/serializer.ts:256:9) at handleUnion (src/serializer.ts:1688:24) at createTypeGuardFunction (src/serializer.ts:256:9) at executeTemplates (src/serializer.ts:750:24) Test Suites: 1 failed, 1 total ```
marcj commented 7 months ago

@alpharder good catch, thanks. indeed, some circular references weren't detected correctly. I've refactored the code to move the circular reference solver into the typeguard/serializer API itself so the various type templates don't have to take care of that. This should now support much more circular references, if not all. I've added your JSONValue type to our test suite to make sure it keeps working.

fixed in https://github.com/deepkit/deepkit-framework/commit/5f6bd124aaf9c546014b81dbded8110312f4e819

alpharder commented 7 months ago

@marcj wow, that change is massive, thank you for the quick fix! Looking forward for the next release.

marcj commented 7 months ago

@alpharder released in 1.0.1-alpha.124