##// END OF EJS Templates
protect against bad return type of CustomTB...
MinRK -
Show More
@@ -1484,13 +1484,42 b' class InteractiveShell(SingletonConfigurable, Magic):'
1484 1484 print 'Exception value:',value
1485 1485 print 'Traceback :',tb
1486 1486 #print 'Source code :','\n'.join(self.buffer)
1487
1488 def validate_stb(stb):
1489 """validate structured traceback return type
1490
1491 return type of CustomTB *should* be a list of strings, but allow
1492 single strings or None, which are harmless.
1493
1494 This function will *always* return a list of strings,
1495 and will raise a TypeError if stb is inappropriate.
1496 """
1497 msg = "CustomTB must return list of strings, not %r" % stb
1498 if stb is None:
1499 return []
1500 elif isinstance(stb, basestring):
1501 return [stb]
1502 elif not isinstance(stb, list):
1503 raise TypeError(msg)
1504 # it's a list
1505 for line in stb:
1506 # check every element
1507 if not isinstance(line, basestring):
1508 raise TypeError(msg)
1509 return stb
1487 1510
1488 1511 if handler is None:
1489 1512 wrapped = dummy_handler
1490 1513 else:
1491 1514 def wrapped(self,etype,value,tb,tb_offset=None):
1515 """wrap CustomTB handler, to protect IPython from user code
1516
1517 This makes it harder (but not impossible) for custom exception
1518 handlers to crash IPython.
1519 """
1492 1520 try:
1493 return handler(self,etype,value,tb,tb_offset=tb_offset)
1521 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1522 return validate_stb(stb)
1494 1523 except:
1495 1524 # clear custom handler immediately
1496 1525 self.set_custom_exc((), None)
@@ -1499,7 +1528,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
1499 1528 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1500 1529 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1501 1530 print >> io.stdout, "The original exception:"
1502 self.showtraceback((etype,value,tb), tb_offset=tb_offset)
1531 stb = self.InteractiveTB.structured_traceback(
1532 (etype,value,tb), tb_offset=tb_offset
1533 )
1534 return stb
1503 1535
1504 1536 self.CustomTB = types.MethodType(wrapped,self)
1505 1537 self.custom_exceptions = exc_tuple
@@ -1570,11 +1602,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1570 1602 sys.last_value = value
1571 1603 sys.last_traceback = tb
1572 1604 if etype in self.custom_exceptions:
1573 # FIXME: Old custom traceback objects may just return a
1574 # string, in that case we just put it into a list
1575 1605 stb = self.CustomTB(etype, value, tb, tb_offset)
1576 if isinstance(ctb, basestring):
1577 stb = [stb]
1578 1606 else:
1579 1607 if exception_only:
1580 1608 stb = ['An exception has occurred, use %tb to see '
@@ -155,7 +155,7 b' class InteractiveShellTestCase(unittest.TestCase):'
155 155 try:
156 156 # capture stderr
157 157 io.stderr = StringIO()
158 ip.set_custom_exc((IOError,),lambda etype,value,tb: None)
158 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
159 159 self.assertEquals(ip.custom_exceptions, (IOError,))
160 160 ip.run_cell(u'raise IOError("foo")')
161 161 self.assertEquals(ip.custom_exceptions, ())
@@ -163,4 +163,20 b' class InteractiveShellTestCase(unittest.TestCase):'
163 163 finally:
164 164 io.stderr = save_stderr
165 165
166 def test_bad_custom_tb_return(self):
167 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
168 ip = get_ipython()
169 from IPython.utils import io
170 save_stderr = io.stderr
171 try:
172 # capture stderr
173 io.stderr = StringIO()
174 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
175 self.assertEquals(ip.custom_exceptions, (NameError,))
176 ip.run_cell(u'a=abracadabra')
177 self.assertEquals(ip.custom_exceptions, ())
178 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
179 finally:
180 io.stderr = save_stderr
181
166 182
General Comments 0
You need to be logged in to leave comments. Login now