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 infinite recursion with circular refs #1400

Closed
wants to merge 2 commits into from

Conversation

andrewalker
Copy link
Contributor

I hit a particular edge case when working on PearlBee. I added a component which used a circular reference (it used the application config, and then it went to the config itself). While maybe it's not a great idea to use circular references anyway, it made Dancer2 go into infinite recursion whenever an exception happened inside Dancer2.

To trigger the issue, the following has to happen:

  • have a circular reference on the config or session;
  • have show_errors enabled;
  • have an exception somewhere in the stack;

show_errors will make Dancer2::Core::Error dump the stack trace, the settings of the app, the session, and the request environment. And before dumping, it will traverse the data and try to sensor things that look sensitive. When there are circular refs, it will traverse forever.

My fix is to use a $visited hashref in the _censor subroutine, so that it keeps track of the data structures it visited.

I hit a particular edge case when working on PearlBee (a Dancer2 blog
engine). I added a component which used a circular reference (it used
the application config, and then it went to the config itself). While
maybe it's not a great idea to use circular references anyway, it made
Dancer2 go into infinite recursion whenever an exception happened inside
Dancer2.

To trigger the issue, the following has to happen:

- have a circular reference on the config or session;
- have show_errors enabled;
- have an exception somewhere in the stack;

The last item is a bit weird, because a simple `die` or throwing
Dancer2::Core::Error don't cause it. But, for example, if the template
engine dies, or if DBIx::Class dies, then the problem appears. It might
be related to the exception being blessed? I tried to find out why, but
was unable to.

So in my test, I just used a template not found.

Show_errors will make Dancer2::Core::Error dump the stack trace, the
settings of the app, the session, and the request environment. And
before dumping, it will traverse the data and try to sensor things that
look sensitive. When there are circular refs, it will traverse forever.
The previous commit added a test case for this issue. This commit uses a
`$visited` hashref to the _censor subroutine, so that it keeps track of
the data structures it visited.

Whenever _censor would recurse, it used to copy the data structure like
this:

    $hash->{$key} = { %{ $hash->{$key} } };

That would change the address of the data, and make it harder for us to
keep track of visited structures. So instead, I used Clone to make a
deep copy of the entire structure on one go, and then I'm free to remove
the sensitive data as I please, with no fear of interfering with the
original.
Copy link
Member

@xsawyerx xsawyerx left a comment

Choose a reason for hiding this comment

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

Nice catch!

Copy link
Member

@SysPete SysPete left a comment

Choose a reason for hiding this comment

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

👍 A nice fix and great set of tests. Thanks @andrewalker!

@xsawyerx
Copy link
Member

Merged in 262ffa7.

@xsawyerx xsawyerx closed this Nov 21, 2017
cromedome added a commit that referenced this pull request Apr 10, 2018
    [ BUG FIXES ]
    * GH #1304: Fix the order by which config files are loaded, independently
      of their filename extension (Alberto Simões, Russell @veryrusty Jenkins)
    * GH #1400: Fix infinite recursion with exceptions that use circular
      references. (Andre Walker)
    * GH #1430: Fix `dancer2 gen` from source directory when Dancer2 not
      installed. (Tina @perlpunk Müller - Tina)
    * GH #1434: Add `validate_id` method to verify a session id before
      requesting the session engine fetch it from its data store.
      (Russell @veryrusty Jenkins)
    * GH #1435, #1438: Allow XS crush_cookie methods to return an arrayref
      of values. (Russell @veryrusty Jenkins)
    * GH #1090, #1406: Replace HTTP::Body with HTTP::Entity::Parser in
      Dancer2::Core::Request. (Russell @veryrusty Jenkins)
    * GH #1443: Update copyright year (Joseph Frazer)
    * GH #1445: Use latest HTTP::Headers::Fast (Russell @veryrusty Jenkins)

    [ ENHANCEMENTS ]
    * GH #1432: Support Content-Disposition of inline in
      send_file() (Dave Webb)
    * PR #1433: Verbose testing in AppVeyor (Graham Knop)
    * PR #1354: TemplateToolkit template engine will log (at debug level)
      if a template is not found. (Kiel R Stirling, Russell @veryrusty Jenkins)

    [ DOCUMENTATION ]
    * GH #1317: Document serializer configuration (sdeseille)
    * PR #1426: Move performance improvement information from Migration guide
      to Deployment (Pedro Melo)
cromedome added a commit that referenced this pull request Apr 20, 2018
    [ BUG FIXES ]
    * GH #1090, #1406: Replace HTTP::Body with HTTP::Entity::Parser in
      Dancer2::Core::Request. (Russell @veryrusty Jenkins)
    * GH #1292: Fix multiple attribute definitions within Plugins
      (Nigel Gregoire)
    * GH #1304: Fix the order by which config files are loaded, independently
      of their filename extension (Alberto Simões, Russell @veryrusty Jenkins)
    * GH #1400: Fix infinite recursion with exceptions that use circular
      references. (Andre Walker)
    * GH #1430: Fix `dancer2 gen` from source directory when Dancer2 not
      installed. (Tina @perlpunk Müller - Tina)
    * GH #1434: Add `validate_id` method to verify a session id before
      requesting the session engine fetch it from its data store.
      (Russell @veryrusty Jenkins)
    * GH #1435, #1438: Allow XS crush_cookie methods to return an arrayref
      of values. (Russell @veryrusty Jenkins)
    * GH #1443: Update copyright year (Joseph Frazer)
    * GH #1445: Use latest HTTP::Headers::Fast (Russell @veryrusty Jenkins)
    * PR #1447: Fix missing build requires (Mohammad S Anwar)

    [ ENHANCEMENTS ]
    * PR #1354: TemplateToolkit template engine will log (at debug level)
      if a template is not found. (Kiel R Stirling, Russell @veryrusty Jenkins)
    * GH #1432: Support Content-Disposition of inline in
      send_file() (Dave Webb)
    * PR #1433: Verbose testing in AppVeyor (Graham Knop)

    [ DOCUMENTATION ]
    * GH #1314: Documentation tweaks (David Precious)
    * GH #1317: Document serializer configuration (sdeseille)
    * GH #1386: Add Hello World example (Gabor Szabo)
    * PR #1408: List project development resources (Steve Dondley)
    * PR #1426: Move performance improvement information from Migration guide
      to Deployment (Pedro Melo)
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.

None yet

3 participants