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

fix: #186 avoid infinite recursion in filter method #187

Merged
merged 7 commits into from
May 6, 2024

Conversation

miquelbeltran
Copy link
Contributor

@miquelbeltran miquelbeltran commented May 3, 2024

fix: #186 avoid infinite recursion in filter method

Description 📝

  • Purpose: filterKeys method uses recursion to explore the provided object, this can potentially cause infinite recursion and eventually throw the "Maximum call stack size exceeded" error.
  • Approach: Adds an explored parameter to the recursive filterKeys method, to check if the incoming object has already been explored or not.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Updates

  • TDD approach: Created a test that can reproduce the issue, using a cyclic object, and causes a "Maximum call stack size exceeded" error, then implemented the solution to fix it.
  • Implementation:
    • Added explored: Set<object> as parameter (it is null by default).
    • When iterating over the object children, if the child is in the explored Set, remove from parent. Same as when applying filters.
    • When calling to filterKeys recursively, include the explored object in the Set.
  • After performing the changes, the test passes.
  • Also added a test assert to ensure that the original object is not modified.

One decision I had to make, is if the self-referenced object should be included in the output or not.

My decision to remove it from the output, is that we cannot apply filtering to the properties of the self-referenced object. Remember that we are doing a copy because we don't want to modify the original.

example of input from the test:

{
  myself: *self reference*,
  key: "value",
  filtered: true,
  other: {
    body: *self reference*,
    filtered: true,
  }
}

output would be:

{
  key: "value",
  other: { }
}

After removing all filtered properties and self-referenced objects.

Test plan 🧪

  • Method is unit tested with a new test, also existing tests pass.

Author to check 👓

  • Project and all contained modules builds successfully
  • Self-/dev-tested
  • Unit/UI/Automation/Integration tests provided where applicable
  • Code is written to standards
  • Appropriate documentation written (code comments, internal docs)

Reviewer to check ✔️

  • Project and all contained modules builds successfully
  • Change has been dev-/reviewer-tested, where possible
  • Unit/UI/Automation/Integration tests provided where applicable
  • Code is written to standards
  • Appropriate documentation written (code comments, internal docs)

function filterKeys(
obj: object,
filters: string[],
explored: Set<object> | null = null,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explored is set to null by default, so it is not a mandatory parameter

Comment on lines +380 to +383
// Original object should not be modified
t.equal(body.username, "[email protected]");
t.equal(body.password, "nice try");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to ensure that we do the copy in the filterKeys method, i.e. const _obj = { ...obj } as Record<string, object>;

@miquelbeltran miquelbeltran requested review from a team, TheRealAgentK, PanosNB and sumitramanga and removed request for a team May 3, 2024 07:06
Copy link
Contributor

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

* @param filters list of keys to filter
* @param explored Set that contains already explored nodes, used internally
*/
function filterKeys(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's been checked but it may be useful to check around the repo to see if we've done infinite recursion in the past and fix that up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't see any other instances in this repo. Do you mean in all the codebases from Raygun?

Copy link
Collaborator

@sumitramanga sumitramanga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Just one comment to address this issue as a whole in the repo if that hasn't been done yet :)

@miquelbeltran miquelbeltran merged commit 8103e92 into develop May 6, 2024
6 checks passed
@miquelbeltran miquelbeltran deleted the recursive-filter branch May 6, 2024 06:26
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

Successfully merging this pull request may close these issues.

Look into potential cyclic objects
3 participants