Patchwork D3445: dispatch: validate return type from dispatch() return value

login
register
mail settings
Submitter phabricator
Date May 12, 2018, 4:48 a.m.
Message ID <89db72b521d454ee8551068c6d2ef982@localhost.localdomain>
Download mbox | patch
Permalink /patch/31544/
State Not Applicable
Headers show

Comments

phabricator - May 12, 2018, 4:48 a.m.
indygreg updated this revision to Diff 8654.
indygreg edited the summary of this revision.
indygreg retitled this revision from "dispatch: shore up exit handling" to "dispatch: validate return type from dispatch() return value".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3445?vs=8460&id=8654

REVISION DETAIL
  https://phab.mercurial-scm.org/D3445

AFFECTED FILES
  mercurial/dispatch.py
  tests/test-dispatch.t

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: yuja, mercurial-devel

Patch

diff --git a/tests/test-dispatch.t b/tests/test-dispatch.t
--- a/tests/test-dispatch.t
+++ b/tests/test-dispatch.t
@@ -263,48 +263,28 @@ 
   [42]
 
   $ hg exit returnstring 'some message'
-  Traceback (most recent call last):
-    File "*/hg", line *, in <module> (glob)
-      dispatch.run()
-    File "*/mercurial/dispatch.py", line *, in run (glob)
-      sys.exit(status & 255)
-  TypeError: unsupported operand type(s) for &: 'str' and 'int'
-  [1]
+  error: received non-integer status code: 'some message'
+  [255]
 
   $ hg exit returnnone
 
   $ hg exit returnempty
 
   $ hg exit returndict
-  Traceback (most recent call last):
-    File "*/hg", line *, in <module> (glob)
-      dispatch.run()
-    File "*/mercurial/dispatch.py", line *, in run (glob)
-      sys.exit(status & 255)
-  TypeError: unsupported operand type(s) for &: 'dict' and 'int'
-  [1]
+  error: received non-integer status code: {'key1': 'value1'}
+  [255]
 
   $ hg exit systemexitint 42
   [42]
 
   $ hg exit systemexitstring 'failure message'
-  Traceback (most recent call last):
-    File "*/hg", line *, in <module> (glob)
-      dispatch.run()
-    File "*/mercurial/dispatch.py", line *, in run (glob)
-      sys.exit(status & 255)
-  TypeError: unsupported operand type(s) for &: 'str' and 'int'
-  [1]
+  error: received non-integer status code: 'failure message'
+  [255]
 
   $ hg exit systemexitnoarg
 
   $ hg exit systemexitnone
 
   $ hg exit systemexitdict
-  Traceback (most recent call last):
-    File "*/hg", line *, in <module> (glob)
-      dispatch.run()
-    File "*/mercurial/dispatch.py", line *, in run (glob)
-      sys.exit(status & 255)
-  TypeError: unsupported operand type(s) for &: 'dict' and 'int'
-  [1]
+  error: received non-integer status code: {'key1': 'value1'}
+  [255]
diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -88,6 +88,20 @@ 
     err = None
     try:
         status = dispatch(req) or 0
+
+        # dispatch() should return an int or None. Python allows the
+        # value to sys.exit() to be special. We don't want to fall back to
+        # this handling, so we normalize to an int.
+        if not isinstance(status, int):
+            if util.safehasattr(req.ui, 'ferr'):
+                # If this raises, things are *really* messed up. We're
+                # OK with a possibly uncaught exception in this case
+                # because we're already in an exceptional code path.
+                req.ui.ferr.write('error: received non-integer status '
+                                  'code: %r\n' % status)
+
+            status = -1
+
     except error.StdioError as e:
         err = e
         status = -1