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

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

Closed
timvandam opened this issue Sep 12, 2023 · 5 comments
Closed

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

timvandam opened this issue Sep 12, 2023 · 5 comments

Comments

@timvandam
Copy link
Contributor

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
Copy link
Member

marcj commented Jan 22, 2024

That's fixed

@marcj marcj closed this as completed Jan 22, 2024
@alpharder
Copy link
Contributor

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 added a commit that referenced this issue Feb 4, 2024
Previously each serializer template was required to handle circular structures when needed. Now, the serializer framework itself handles it.

Also, BSON property name writer refactored so that auto-handling of circular references works correctly.

For JIT code generation env DEBUG=deepkit now pretty formats it for easier debugging.

ref #477
@marcj
Copy link
Member

marcj commented Feb 4, 2024

@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 5f6bd12

@alpharder
Copy link
Contributor

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

@marcj
Copy link
Member

marcj commented Feb 4, 2024

@alpharder released in 1.0.1-alpha.124

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants