Fixed #31675 -- Added warning to ExceptionReporter when exception chain has a cycle.

This commit is contained in:
Hasan Ramezani 2020-06-09 21:55:49 +02:00 committed by Mariusz Felisiak
parent 69a78a4a63
commit a59de6e89e
2 changed files with 18 additions and 3 deletions

View File

@ -2,6 +2,7 @@ import functools
import re
import sys
import types
import warnings
from pathlib import Path
from django.conf import settings
@ -28,6 +29,10 @@ DEBUG_ENGINE = Engine(
CURRENT_DIR = Path(__file__).parent
class ExceptionCycleWarning(UserWarning):
pass
class CallableSettingWrapper:
"""
Object to wrap callable appearing in settings.
@ -401,6 +406,11 @@ class ExceptionReporter:
exceptions.append(exc_value)
exc_value = explicit_or_implicit_cause(exc_value)
if exc_value in exceptions:
warnings.warn(
"Cycle in the exception chain detected: exception '%s' "
"encountered again." % exc_value,
ExceptionCycleWarning,
)
# Avoid infinite loop if there's a cyclic reference (#29393).
break

View File

@ -23,8 +23,8 @@ from django.utils.functional import SimpleLazyObject
from django.utils.regex_helper import _lazy_re_compile
from django.utils.safestring import mark_safe
from django.views.debug import (
CallableSettingWrapper, ExceptionReporter, Path as DebugPath,
SafeExceptionReporterFilter, default_urlconf,
CallableSettingWrapper, ExceptionCycleWarning, ExceptionReporter,
Path as DebugPath, SafeExceptionReporterFilter, default_urlconf,
get_default_exception_reporter_filter, technical_404_response,
technical_500_response,
)
@ -518,7 +518,12 @@ class ExceptionReporterTests(SimpleTestCase):
tb_frames = None
tb_generator = threading.Thread(target=generate_traceback_frames, daemon=True)
tb_generator.start()
msg = (
"Cycle in the exception chain detected: exception 'inner' "
"encountered again."
)
with self.assertWarnsMessage(ExceptionCycleWarning, msg):
tb_generator.start()
tb_generator.join(timeout=5)
if tb_generator.is_alive():
# tb_generator is a daemon that runs until the main thread/process