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 cyclic JSON.stringify / primitive conversion stack overflows #777

Merged
merged 13 commits into from Oct 5, 2020

Conversation

vgel
Copy link
Contributor

@vgel vgel commented Oct 3, 2020

This Pull Request fixes/closes #545

It changes the following:

  • Refactor gcobject::RecursionLimiter so it can be used outside of its module for liveness tracking
  • Use that struct in Value::to_json to throw a TypeError, per the spec
  • Also use it in Context::ordinary_to_primitive, where we return a default value
  • Adds tests for above

The biggest change is probably ordinary_to_primitive. Since the spec doesn't mention what to do, I went and looked at what v8 and SpiderMonkey do. They return a default value based on the type hint: either 0. or "". (See example here: https://repl.it/repls/IvoryCircularCertification#index.js) So, I did the same thing. We could alternatively throw a TypeError, but that would both diverge from the spec (which doesn't mention anything) and existing implementations.

These tests currently fail by overflowing the stack.
Value comparisons are drawn from what Chrome
and Firefox do, which doesn't appear to be in the
spec?
This test is likely to be broken by the next change
We can use the existing RecursionLimiter type
used by GcObject's Debug impl for this purpose.
We just need to refactor it to allow both liveness
and visitation tracking, using a HashMap of ptrs
to states instead of a HashSet of ptrs.
Use the newly refactored RecursionLimiter to
check for recursion, and limit it. Throw a TypeError
as mandated by the spec.
Use the new RecursionLimiter type to prevent
overflows from conversions in ordinary_to_primitive.
The spec doesn't say what to do here, so we follow
v8 / SpiderMonkey in returning a default value for
the type hint -- either 0. or "". More details in
the method documentation.
Someone added `as_gc_object` right as I added
`add_gcobject`. What are the chances? Switched
to the new method.
@codecov
Copy link

codecov bot commented Oct 3, 2020

Codecov Report

Merging #777 into master will increase coverage by 0.33%.
The diff coverage is 91.80%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #777      +/-   ##
==========================================
+ Coverage   59.21%   59.54%   +0.33%     
==========================================
  Files         155      155              
  Lines        9908     9943      +35     
==========================================
+ Hits         5867     5921      +54     
+ Misses       4041     4022      -19     
Impacted Files Coverage Δ
boa/src/context.rs 70.67% <ø> (+0.53%) ⬆️
boa/src/object/mod.rs 45.61% <ø> (ø)
boa/src/object/gcobject.rs 78.57% <91.37%> (+5.46%) ⬆️
boa/src/value/mod.rs 71.57% <100.00%> (-0.72%) ⬇️
boa/src/syntax/ast/node/operator/bin_op/mod.rs 70.37% <0.00%> (+0.92%) ⬆️
boa/src/value/operations.rs 46.73% <0.00%> (+2.06%) ⬆️
boa/src/builtins/console/mod.rs 23.03% <0.00%> (+3.93%) ⬆️
boa/src/value/rcstring.rs 64.28% <0.00%> (+7.14%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6bcfc7a...2cc55b9. Read the comment docs.

boa/src/context.rs Outdated Show resolved Hide resolved
@RageKnify
Copy link
Member

One thing I think we could also change is the signature of OrdinaryToPrimitive, it is only called in 2 places on the spec, and in both cases it receives values whose types has been asserted to be Object, so we could for example receive GcObject, but I leave that decision to @HalidOdat who knows more about how we represent Objects.

Copy link
Member

@HalidOdat HalidOdat 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 ready to merge, just some small changes :)

boa/src/context.rs Outdated Show resolved Hide resolved
@HalidOdat
Copy link
Member

HalidOdat commented Oct 3, 2020

One thing I think we could also change is the signature of OrdinaryToPrimitive, it is only called in 2 places on the spec, and in both cases it receives values whose types has been asserted to be Object, so we could for example receive GcObject, but I leave that decision to @HalidOdat who knows more about how we represent Objects.

Yes. I would say its better if we move it to GcObject as pub(crate) and accepting a &self (this will eliminate the debug object check), the Context it is not a good place for it.

@HalidOdat HalidOdat added bug Something isn't working execution Issues or PRs related to code execution builtins PRs and Issues related to builtins/intrinsics labels Oct 3, 2020
@HalidOdat HalidOdat added this to the v0.11.0 milestone Oct 3, 2020
boa/src/value/mod.rs Outdated Show resolved Hide resolved
@RageKnify
Copy link
Member

RageKnify commented Oct 5, 2020

Looks like you accidentaly broke a lot of tests @vgel. Not sure what you did wrong, but you broke a lot of stuf.

@vgel
Copy link
Contributor Author

vgel commented Oct 5, 2020

I'm not sure -- the tests seemed to run fine until I merged master. Will look into it.

Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

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

Looks good to me!

@RageKnify RageKnify merged commit d76e8bf into boa-dev:master Oct 5, 2020
@HalidOdat HalidOdat linked an issue Oct 5, 2020 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working builtins PRs and Issues related to builtins/intrinsics execution Issues or PRs related to code execution
Projects
None yet
3 participants