##// END OF EJS Templates
protect against bad return type of CustomTB...
MinRK -
Show More
@@ -1485,12 +1485,41 b' class InteractiveShell(SingletonConfigurable, Magic):'
1485 print 'Traceback :',tb
1485 print 'Traceback :',tb
1486 #print 'Source code :','\n'.join(self.buffer)
1486 #print 'Source code :','\n'.join(self.buffer)
1487
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
1510
1488 if handler is None:
1511 if handler is None:
1489 wrapped = dummy_handler
1512 wrapped = dummy_handler
1490 else:
1513 else:
1491 def wrapped(self,etype,value,tb,tb_offset=None):
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 try:
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 except:
1523 except:
1495 # clear custom handler immediately
1524 # clear custom handler immediately
1496 self.set_custom_exc((), None)
1525 self.set_custom_exc((), None)
@@ -1499,7 +1528,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
1499 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1528 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1500 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1529 print >> io.stdout, self.InteractiveTB.stb2text(stb)
1501 print >> io.stdout, "The original exception:"
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 self.CustomTB = types.MethodType(wrapped,self)
1536 self.CustomTB = types.MethodType(wrapped,self)
1505 self.custom_exceptions = exc_tuple
1537 self.custom_exceptions = exc_tuple
@@ -1570,11 +1602,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1570 sys.last_value = value
1602 sys.last_value = value
1571 sys.last_traceback = tb
1603 sys.last_traceback = tb
1572 if etype in self.custom_exceptions:
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 stb = self.CustomTB(etype, value, tb, tb_offset)
1605 stb = self.CustomTB(etype, value, tb, tb_offset)
1576 if isinstance(ctb, basestring):
1577 stb = [stb]
1578 else:
1606 else:
1579 if exception_only:
1607 if exception_only:
1580 stb = ['An exception has occurred, use %tb to see '
1608 stb = ['An exception has occurred, use %tb to see '
@@ -155,7 +155,7 b' class InteractiveShellTestCase(unittest.TestCase):'
155 try:
155 try:
156 # capture stderr
156 # capture stderr
157 io.stderr = StringIO()
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 self.assertEquals(ip.custom_exceptions, (IOError,))
159 self.assertEquals(ip.custom_exceptions, (IOError,))
160 ip.run_cell(u'raise IOError("foo")')
160 ip.run_cell(u'raise IOError("foo")')
161 self.assertEquals(ip.custom_exceptions, ())
161 self.assertEquals(ip.custom_exceptions, ())
@@ -163,4 +163,20 b' class InteractiveShellTestCase(unittest.TestCase):'
163 finally:
163 finally:
164 io.stderr = save_stderr
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