-
-
Notifications
You must be signed in to change notification settings - Fork 594
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: Fail on infinite recursion in encode.js
#2099
base: alpha
Are you sure you want to change the base?
Conversation
I will reformat the title to use the proper commit message syntax. |
encode.js
encode.js
Thanks for opening this pull request! |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## alpha #2099 +/- ##
==========================================
- Coverage 99.98% 99.96% -0.02%
==========================================
Files 61 61
Lines 6185 6206 +21
Branches 1499 1503 +4
==========================================
+ Hits 6184 6204 +20
- Misses 1 2 +1 ☔ View full report in Codecov by Sentry. |
Also included support for the `traverse` function, which experienced the same issue.
After looking at the |
@mtrezza found a method that seems to be working on my end with complex objects containing cyclical references, I will be able to fully test by installing locally from my branch later tonight. Will update once I have done so. Let me know if there's anything else you want changed and I can take a stab at it. |
/** | ||
* Helper function that turns a string into a unique 53-bit hash. | ||
* @ref https://stackoverflow.com/a/52171480/6456163 | ||
* @param {string} str | ||
* @param {number} seed | ||
* @returns {number} | ||
*/ | ||
export const cyrb53 = (str, seed = 0) => { | ||
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; | ||
for (let i = 0, ch; i < str.length; i++) { | ||
ch = str.charCodeAt(i); | ||
h1 = Math.imul(h1 ^ ch, 2654435761); | ||
h2 = Math.imul(h2 ^ ch, 1597334677); | ||
} | ||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); | ||
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); | ||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); | ||
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); | ||
|
||
return 4294967296 * (2097151 & h2) + (h1 >>> 0); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot accept this algo (or derivations thereof) due to its problematic usage rights situation. The author has claimed to have made this "public domain", but such a claim is invalid in some jurisdictions. I have not found an OS license attributed to this code by the author. If you have found that anywhere, please provide the link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this solution be satisfactory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the effort, but unfortunately the underlying issue is still unaddressed. I appreciate the author's rooting for public domain contributions. However, the issue is a legal one. Unless there's an official OS license attributed to the code, we cannot accept it. We also cannot accept any "self-written", non-official OS license on similar grounds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtrezza is the MIT license addition satisfactory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but SO is not sufficient as source or link to the author. Has this been published anywhere on GitHub, and can this be added as a dependency? Because if we add code like this it won't be maintained by the author and the maintenance is on us. I'm not sure whether we should maintain this piece of code if there are libs for hash functions out there that are regularly maintained.
Why is this hash code even required in this PR? Are there no native Node hash functions we can use instead? This looks odd.
output[k] = encode(value[k], disallowObjects, forcePointers, seen, offline); | ||
try { | ||
// Attempts to get the name of the object's constructor | ||
// Ref: https://stackoverflow.com/a/332429/6456163 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same topic as earlier. If you copy/pasted someone else's code from SO then we cannot accept it.
Edit: Now that I looked at the link, this is a basic JS feature, there is really no need to reference SO here.
However, the above still holds true. I'd ask you to review the whole PR at this point and identify any code that has been copied from somewhere else, so we can investigate whether we can accept it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have more and more doubts that we can accept this PR without a performance comparison. Encode is such a central code that any changes here can have a significant yet subtle impact on Parse Server performance. Perf issues are tough to analyze after the fact, so I'm somewhat hesitant.
A fix might still be worth implementing here, but I don't see myself having the cycles to work on this PR in the near future. HOWEVER, I did figure out a cause of all these errors in the legacy code I inherited, if it helps anyone else. The cloud functions were returning the response of an Axios GET request, and the response object has infinite recursion in its properties with sockets. What I had to do was just parse out the Feel free to close this out if you want, so someone else can come in with a different implementation that you would prefer. |
It would be too bad, since you've already put so much work into it. Thinking about it, adding the recursion limit that you implemented initially may be the least intrusive one and I'd think poses the least risk to performance. It's the simplest fix. But only if we set the limit ridiculously high (10k?), we can treat it as a non-breaking change, if we assume that nested objects with 10k levels deep are rather unlikely. On the other hand the solution you implemented would not require the limit and properly handle recursions, as we already do in other parts of the code. But with hash generation, etc we run into perf issues, so we may need a perf comparison test. In fact we have parse-community/parse-server#7610 for that. |
Picking this up, I think there are 2 ways to move forward:
I would be hesitant to merge (2) without having a perf comparison in our CI, because of #2099 (review). So for now we could go ahead and merge (1), so we at least fix the issue of infinite recursion. |
Issue
Closes: #2098
Approach
Implemented the changes suggested by @mtrezza. Will give some clarity to the issues being encountered, and may illuminate further test cases that cause issues that can be handled in a better way in the future.
Tasks