Break reference cycle created by default in Flask instances.

Flask instances with static folders were creating a reference cycle
via their "static" view function (which held a strong reference back
to the Flask instance to call its `send_static_file` method). This
prevented CPython from freeing the memory for a Flask instance
when all external references to it were released.

Now use a weakref for the back reference to avoid this.

Co-authored-by: Joshua Bronson <jab@users.noreply.github.com>
This commit is contained in:
Bogdan Opanchuk 2020-10-03 07:05:05 -07:00 committed by GitHub
parent 4e8b020494
commit 8efea0ccbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 1 deletions

View file

@ -1,8 +1,11 @@
import gc
import re
import sys
import time
import uuid
import weakref
from datetime import datetime
from platform import python_implementation
from threading import Thread
import pytest
@ -16,6 +19,11 @@ from werkzeug.routing import BuildError
import flask
require_cpython_gc = pytest.mark.skipif(
python_implementation() != "CPython", reason="Requires CPython GC behavior",
)
def test_options_work(app, client):
@app.route("/", methods=["GET", "POST"])
def index():
@ -1970,3 +1978,19 @@ def test_max_cookie_size(app, client, recwarn):
client.get("/")
assert len(recwarn) == 0
@require_cpython_gc
def test_app_freed_on_zero_refcount():
# A Flask instance should not create a reference cycle that prevents CPython
# from freeing it when all external references to it are released (see #3761).
gc.disable()
try:
app = flask.Flask(__name__)
assert app.view_functions["static"]
weak = weakref.ref(app)
assert weak() is not None
del app
assert weak() is None
finally:
gc.enable()