changeset 6939:07f026cdf7ac

vcs: catch MemoryErrors when calling Git diff Binary diffs can make the diffs VERY big and cause MemoryError exceptions. Before giving MemoryError, the system might start swapping, any process might fail when allocating memory, random processes might get killed, and our process might fail in other places. The proper fix would be to avoid the problem by not trying to process more data than we can handle - for example by not processing more than a certain amount of Git output. Before, memory errors were shown to the user as a 500 Internal Server Error page. Now, as long as we have no better/safer way get the diff, catch the MemoryError and show the page with a flash error message and no diff. The error handling is placed in the diffs module to avoid leaking flash messages into the vcs lib.
author domruf <dominikruf@gmail.com>
date Thu, 04 May 2017 20:51:26 +0200
parents 6fde53180c50
children 7a31cb862a58
files kallithea/lib/diffs.py
diffstat 1 files changed, 8 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/lib/diffs.py	Sun Oct 22 00:42:12 2017 +0200
+++ b/kallithea/lib/diffs.py	Thu May 04 20:51:26 2017 +0200
@@ -31,10 +31,10 @@
 
 from tg.i18n import ugettext as _
 
+from kallithea.lib import helpers as h
 from kallithea.lib.vcs.exceptions import VCSError
 from kallithea.lib.vcs.nodes import FileNode, SubModuleNode
 from kallithea.lib.vcs.backends.base import EmptyChangeset
-from kallithea.lib.helpers import escape
 from kallithea.lib.utils2 import safe_unicode
 
 log = logging.getLogger(__name__)
@@ -218,7 +218,7 @@
         submodules = filter(lambda o: isinstance(o, SubModuleNode),
                             [filenode_new, filenode_old])
         if submodules:
-            html_diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
+            html_diff = wrap_to_table(h.escape('Submodule %r' % submodules[0]))
         else:
             html_diff = wrap_to_table(_('No changes detected'))
 
@@ -257,8 +257,12 @@
     """
     A thin wrapper around vcs lib get_diff.
     """
-    return scm_instance.get_diff(rev1, rev2, path=path,
-                                 ignore_whitespace=ignore_whitespace, context=context)
+    try:
+        return scm_instance.get_diff(rev1, rev2, path=path,
+                                     ignore_whitespace=ignore_whitespace, context=context)
+    except MemoryError:
+        h.flash('MemoryError: Diff is too big', category='error')
+        return ''
 
 
 NEW_FILENODE = 1