Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[SecurityBundle] Fixed a memory leak in SecurityBundle\Security\FirewallMap#22605

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
udavka wants to merge8 commits intosymfony:3.2fromudavka:fix-memory-leak-in-firewallmap
Closed

[SecurityBundle] Fixed a memory leak in SecurityBundle\Security\FirewallMap#22605

udavka wants to merge8 commits intosymfony:3.2fromudavka:fix-memory-leak-in-firewallmap

Conversation

@udavka
Copy link

@udavkaudavka commentedMay 1, 2017
edited
Loading

QA
Branch?3.2
Bug fix?yes
New feature?no
BC breaks?no
Deprecations?no
Tests pass?yes
Fixed tickets-
LicenseMIT
Doc PR-

There is a memory leak in Symfony\Bundle\SecurityBundle\Security\FirewallMap, which leads to not autodestroy Symfony\Component\HttpFoundation\Request object after the request has been proceeded. This object is quite big and uses many internal subobjects, and as a result this leads to an essential memory leak, which can affect long-lived applications like php-pm.
How to reproduce: create a default sample Symfony application, add a destructor for the Request class, add unset($request); at the end of web/app.php and make sure that this destructor is not called after unset().
With this fix the destructor is called immediately after unset(), and that means no memory leak for the Request object.

{
$request =$event->getRequest();

$this->map->detachListeners($event->getRequest());
Copy link
Member

Choose a reason for hiding this comment

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

This may not always work (think of other implementations of theFirewallMapInterface).

Copy link
Author

Choose a reason for hiding this comment

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

Fixed by replacing the implementation.

*
* @param Request $request
*/
publicfunctiondetachListeners(Request$request);
Copy link
Member

Choose a reason for hiding this comment

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

Adding a new method to an interface is a BC break and not allowed by our BC promise.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed by replacing the implementation.

@chalasr
Copy link
Member

But doesn't the issue concern only the SecurityBundle map due to its per-request cache? Wouldn't mapping contexts by Request object hash instead of Request instances be enough, changing the\SplObjectStorage to an array?

@nicolas-grekasnicolas-grekas added this to the3.2 milestoneMay 2, 2017
@udavka
Copy link
Author

@chalasr: The basic problem is the using of FirewallMapInterface to refer to long-lived services. There is no idea of destroying/detaching of FirewallMap from inside Firewall, because both of them are services and live forever.
Initially the FirewallMapInterface is intended only to get information and has nothing to initialize or to finalize itself. Even if we change the implementation of SecurityBundle\Security\FirewallMap to not have a Request reference, there will be a possibility to add a leak in the future.

@ogizanagi
Copy link
Contributor

ogizanagi commentedMay 12, 2017
edited
Loading

@udavka : I don't get how it can improve anything when talking about the SecurityBundleFirewallMap. Unsetting the context for a given request won't free anything, as the services are still referenced by the container, right? The only leaking object is the request, indeed due to the\SplObjectStorage used for cache purpose. Usingspl_object_hash($request) instead is the only thing required for solving the issue to me.

Even if we change the implementation of SecurityBundle\Security\FirewallMap to not have a Request reference, there will be a possibility to add a leak in the future.

Which leak?

Regarding the componentFirewallMap, I don't get why you'd like to remove the listeners once a request is finished. What about subsequent requests? Are you destroying the listeners and recreating and adding them to the map for each request? If so, why? Aren't they stateless?
Also you don't need new interface methods/new interface nor tweaking theFirewall for this I guess: just register theFirewallMap as a listener ofKernelEvents::FINISH_REQUEST in order to calldetachListeners.

chalasr reacted with thumbs up emoji

@udavka
Copy link
Author

udavka commentedMay 12, 2017
edited
Loading

@ogizanagi Symfony is able to process many requests without restarting the whole framework. This idea is used in long-lived applications. Services are not leaks, because they are not recreated on every request. But Request is not a service and must be destroyed after the processing.
As you can see in the code, detaching of listeners is dependent on request, so no subsequent requests can be affected.
Using ofspl_object_hash($request) is not an option, because the resulting hash can be reused later and anyway there will be a small leak in form of an array item [hash => listener].
I seems that the idea aboutKernelEvents::FINISH_REQUEST is the only one possible solution to make this object not leakable without BC breaks, but in this case the whole logic of theFirewallMap object will be inverted - it is initialized by another component, but it wants to clean up itself. This is actually the big hole for future problems.

@ogizanagi
Copy link
Contributor

ogizanagi commentedMay 12, 2017
edited
Loading

Using of spl_object_hash($request) is not an option, because the resulting hash can be reused later.

Indeed, as the previous request is destroyed as this point. Good point.

small leak in form of an array item [hash => listener]

Sure, but not sure how much it can really affect long-living applications, as its one array item (per request though) just holding references.

I seems that the idea about KernelEvents::FINISH_REQUEST is the only one possible solution to make this object not leakable without BC breaks, but in this case the whole logic of the FirewallMap object will be inverted - it is initialized by another component, but it wants to clean up itself. This is actually the big hole for future problems.

Looks acceptable to me, and would allow to be merged as a bugfix in lower branches.
Otherwise, creating a new interface would allow doing it your way without BC break, but only as a new feature, so in 3.4.

privatefunctiondetachListeners(Request$request)
{
unset($this->contexts[$request]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO you should directly unset the request in theonKernelFinishRequest method, that would make one less method call...

Copy link
Author

Choose a reason for hiding this comment

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

fixed

}

/**
* @param FinishRequestEvent $event
Copy link
Contributor

Choose a reason for hiding this comment

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

To remove, as it does not bring anything more than the signature.

Copy link
Author

Choose a reason for hiding this comment

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

fixed

/**
* Get subscribed events.
*
* @return array Subscribed events
Copy link
Contributor

Choose a reason for hiding this comment

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

The whole docblock should be replaced by

/** * {@inheritdoc} */

Copy link
Author

Choose a reason for hiding this comment

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

fixed

@GromNaN
Copy link
Member

GromNaN commentedMay 13, 2017
edited
Loading

Since the matching context relates to the request, this information should have been cached inside the request parameters.

This inside thegetFirewallContext method.

// code in 3.2privatefunctiongetFirewallContext(Request$request)    {if ($this->contexts->contains($request)) {return$this->contexts[$request];        }foreach ($this->mapas$contextId =>$requestMatcher) {if (null ===$requestMatcher ||$requestMatcher->matches($request)) {return$this->contexts[$request] =$this->container->get($contextId);            }        }    }

We can remove the$contexts object map and store information inside the request attributes.

// proposalprivatefunctiongetFirewallContext(Request$request)    {if ($request->attributes->has('_security_firewall_context')) {return$this->container->get($request->attributes->get('_security_firewall_context'));        }foreach ($this->mapas$contextId =>$requestMatcher) {if (null ===$requestMatcher ||$requestMatcher->matches($request)) {$request->attributes->set('_security_firewall_context',$contextId);return$this->container->get($contextId);            }        }    }
Taluu, ogizanagi, chalasr, Koc, and GromNaN reacted with thumbs up emoji

@ogizanagi
Copy link
Contributor

ogizanagi commentedMay 14, 2017
edited
Loading

Indeed,@GromNaN's suggestion looks even better to me :)

@nicolas-grekas
Copy link
Member

Status: needs work

@fabpot
Copy link
Member

Closing in favor of#22943

@fabpotfabpot closed thisJun 9, 2017
fabpot added a commit that referenced this pull requestJun 14, 2017
…he request parameters (GromNaN)This PR was squashed before being merged into the 3.2 branch (closes#22943).Discussion----------[SecurityBundle] Move cache of the firewall context into the request parametersFollowing [this proposal](#22605 (comment)). Since the matching context relates to the request, this information should have been cached inside the request parameters.| Q             | A| ------------- | ---| Branch?       | 3.2| Bug fix?      | yes| New feature?  | no| BC breaks?    | no| Deprecations? | no| Tests pass?   | yes| Fixed tickets |#22605| License       | MIT| Doc PR        | n/a* Avoid memory leak when handling multiple requests* Adding the new request parameter `_firewall_context` might be considered as a breaking change. That adds a new "public" property that could be used by end developers.Commits-------b3203cb [SecurityBundle] Move cache of the firewall context into the request parameters
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@xabbuhxabbuhxabbuh requested changes

+2 more reviewers

@TaluuTaluuTaluu left review comments

@ogizanagiogizanagiogizanagi approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Projects

None yet

Milestone

3.2

Development

Successfully merging this pull request may close these issues.

9 participants

@udavka@chalasr@ogizanagi@GromNaN@nicolas-grekas@fabpot@Taluu@xabbuh@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp