Skip to content

Commit

Permalink
[BUGFIX] Prevent possible browser freezes in FormEditor
Browse files Browse the repository at this point in the history
Using timestamps as array keys in form yaml configuration
can result in sparse [1] JavaScript arrays which contain
"empty slots".

Example yaml configuration:

  templateRootPaths:
    1708504268: 'EXT:example/Resources/Private/Emails/Templates'

This value is properly serialized into an object by PHP json_encode
(as it does not contain sequential integer keys starting at 0), but
the FormEditor data model produces arrays from numerical keys during
clone operations of such data sets and basically creates sparse arrays
like:

> const example = []
> example[1708504268] = 'EXT:example/Resources/Private/Emails/Templates'
> console.log(example)
[
  <1708504268 empty items>,
  'EXT:forms_extended/Resources/Private/Emails/Templates'
]

Some array-looping operations like Array.reduce() will loop through all
empty slots [1] and therefore preduce a lot of processing load
(1708504269 loops for the example above) that ultimately cause freezes.

The array to object copy operation is now replaced by a modern spread
operation that is defined to skip empty slots.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays

Releases: main, 12.4, 11.5
Resolves: #103168
Change-Id: I10b586ff5c5b0fb3698bfbbe28b2f93d932b71a2
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83079
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: core-ci <typo3@b13.com>
  • Loading branch information
bnf committed Feb 22, 2024
1 parent 4603748 commit a868e52
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 8 deletions.
8 changes: 1 addition & 7 deletions Build/Sources/TypeScript/form/backend/form-editor/core.ts
Expand Up @@ -803,13 +803,7 @@ export class Model<D extends object, T extends ModelData<D>> {
// in case the previous guess was wrong, the initialized array
// is converted to an object when a non-numeric path segment is found
} else if (false === $.isNumeric(nextPartOfPath) && 'array' === $.type(obj[firstPartOfPath])) {
obj[firstPartOfPath] = (obj[firstPartOfPath] as Array<unknown>).reduce(
(converted: Record<number, unknown>, item: unknown, itemIndex: number): Record<number, unknown> => {
converted[itemIndex] = item;
return converted;
},
{} as Record<number, unknown>
);
obj[firstPartOfPath] = { ...(obj[firstPartOfPath] as Array<unknown>) };
}
obj = obj[firstPartOfPath] as Record<string, unknown>;
}
Expand Down

0 comments on commit a868e52

Please sign in to comment.