Re: [Python-Dev] [Python-checkins] r83763 - in python/branches/py3k: Doc/library/signal.rst Lib/test/test_signal.py Misc/NEWS Modules/signalmodule.c
Hi, On 06/08/2010 22.27, brian.curtin wrote:
Author: brian.curtin Date: Fri Aug 6 21:27:32 2010 New Revision: 83763
Log: Fix #9324: Add parameter validation to signal.signal on Windows in order to prevent crashes.
Modified: python/branches/py3k/Doc/library/signal.rst python/branches/py3k/Lib/test/test_signal.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/signalmodule.c
Modified: python/branches/py3k/Doc/library/signal.rst ============================================================================== --- python/branches/py3k/Doc/library/signal.rst (original) +++ python/branches/py3k/Doc/library/signal.rst Fri Aug 6 21:27:32 2010 @@ -230,6 +230,10 @@ see the :ref:`description in the type hierarchy<frame-objects>` or see the attribute descriptions in the :mod:`inspect` module).
+ On Windows, :func:`signal` can only be called with :const:`SIGABRT`, + :const:`SIGFPE`, :const:`SIGILL`, :const:`SIGINT`, :const:`SIGSEGV`, or + :const:`SIGTERM`. A :exc:`ValueError` will be raised in any other case. +
.. _signal-example:
Modified: python/branches/py3k/Lib/test/test_signal.py ============================================================================== --- python/branches/py3k/Lib/test/test_signal.py (original) +++ python/branches/py3k/Lib/test/test_signal.py Fri Aug 6 21:27:32 2010 @@ -9,7 +9,7 @@ import traceback import sys, os, time, errno
-if sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos': +if sys.platform == 'os2' or sys.platform == 'riscos': raise unittest.SkipTest("Can't test signal on %s" % \ sys.platform)
@@ -37,6 +37,7 @@ return None
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
In the previous chunk sys.platform[:3] was used instead of just sys.platform. Are there some other "winXX" platform that should be skipped too?
class InterProcessSignalTests(unittest.TestCase): MAX_DURATION = 20 # Entire test should last at most 20 sec.
@@ -186,6 +187,7 @@ self.MAX_DURATION)
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class BasicSignalTests(unittest.TestCase): def trivial_signal_handler(self, *args): pass @@ -208,6 +210,23 @@ self.assertEquals(signal.getsignal(signal.SIGHUP), hup)
+@unittest.skipUnless(sys.platform == "win32", "Windows specific") +class WindowsSignalTests(unittest.TestCase): + def test_issue9324(self): + handler = lambda x, y: None + signal.signal(signal.SIGABRT, handler) + signal.signal(signal.SIGFPE, handler) + signal.signal(signal.SIGILL, handler) + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGSEGV, handler) + signal.signal(signal.SIGTERM, handler) + + with self.assertRaises(ValueError): + signal.signal(-1, handler) + sinal.signal(7, handler)
You should use two separate assertRaises here, otherwise the second line is not executed if the first one raises an error (and if the first doesn't raise an error but the second does the test will pass even if it shouldn't). This also masks the typo in the second line.
+ + +@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class WakeupSignalTests(unittest.TestCase): TIMEOUT_FULL = 10 TIMEOUT_HALF = 5 @@ -253,14 +272,15 @@ os.close(self.write) signal.signal(signal.SIGALRM, self.alrm)
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): - signum = signal.SIGUSR1
def setUp(self): """Install a no-op signal handler that can be set to allow interrupts or not, and arrange for the original signal handler to be re-installed when the test is finished. """ + self.signum = signal.SIGUSR1 oldhandler = signal.signal(self.signum, lambda x,y: None) self.addCleanup(signal.signal, self.signum, oldhandler)
@@ -354,7 +374,7 @@ self.assertFalse(i)
- +@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class ItimerTest(unittest.TestCase): def setUp(self): self.hndl_called = False @@ -463,8 +483,11 @@ self.assertEqual(self.hndl_called, True)
def test_main(): - support.run_unittest(BasicSignalTests, InterProcessSignalTests, - WakeupSignalTests, SiginterruptTest, ItimerTest) + if sys.platform == "win32": + support.run_unittest(WindowsSignalTests) + else: + support.run_unittest(BasicSignalTests, InterProcessSignalTests, + WakeupSignalTests, SiginterruptTest, ItimerTest)
Is this necessary? If the tests are marked with a skip decorator they will be skipped anyway (and also marked as skipped in the output).
if __name__ == "__main__":
Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Aug 6 21:27:32 2010 @@ -24,6 +24,9 @@ Extensions ----------
+- Issue #9324: Add parameter validation to signal.signal on Windows in order + to prevent crashes. + - Issue #9526: Remove some outdated (int) casts that were preventing the array module from working correctly with arrays of more than 2**31 elements.
Modified: python/branches/py3k/Modules/signalmodule.c ============================================================================== --- python/branches/py3k/Modules/signalmodule.c (original) +++ python/branches/py3k/Modules/signalmodule.c Fri Aug 6 21:27:32 2010 @@ -255,8 +255,23 @@ int sig_num; PyObject *old_handler; void (*func)(int); +#ifdef MS_WINDOWS + int cur_sig, num_valid_sigs = 6; + static int valid_sigs[] = {SIGABRT, SIGFPE, SIGILL, SIGINT, + SIGSEGV, SIGTERM}; + BOOL valid_sig = FALSE; +#endif if (!PyArg_ParseTuple(args, "iO:signal",&sig_num,&obj)) return NULL; +#ifdef MS_WINDOWS + /* Validate that sig_num is one of the allowable signals */ + for (cur_sig = 0; cur_sig< num_valid_sigs; cur_sig++) + valid_sig |= (sig_num == valid_sigs[cur_sig]); + if (!valid_sig) { + PyErr_SetString(PyExc_ValueError, "signal number out of range"); + return NULL; + } +#endif #ifdef WITH_THREAD if (PyThread_get_thread_ident() != main_thread) { PyErr_SetString(PyExc_ValueError, _______________________________________________ Python-checkins mailing list Python-checkins@python.org http://mail.python.org/mailman/listinfo/python-checkins
Best Regards, Ezio Melotti
On Fri, Aug 6, 2010 at 21:59, Ezio Melotti <ezio.melotti@gmail.com> wrote:
Hi,
On 06/08/2010 22.27, brian.curtin wrote:
Author: brian.curtin Date: Fri Aug 6 21:27:32 2010 New Revision: 83763
Log: Fix #9324: Add parameter validation to signal.signal on Windows in order to prevent crashes.
Modified: python/branches/py3k/Doc/library/signal.rst python/branches/py3k/Lib/test/test_signal.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/signalmodule.c
Modified: python/branches/py3k/Doc/library/signal.rst
============================================================================== --- python/branches/py3k/Doc/library/signal.rst (original) +++ python/branches/py3k/Doc/library/signal.rst Fri Aug 6 21:27:32 2010 @@ -230,6 +230,10 @@ see the :ref:`description in the type hierarchy<frame-objects>` or see the attribute descriptions in the :mod:`inspect` module).
+ On Windows, :func:`signal` can only be called with :const:`SIGABRT`, + :const:`SIGFPE`, :const:`SIGILL`, :const:`SIGINT`, :const:`SIGSEGV`, or + :const:`SIGTERM`. A :exc:`ValueError` will be raised in any other case. +
.. _signal-example:
Modified: python/branches/py3k/Lib/test/test_signal.py
============================================================================== --- python/branches/py3k/Lib/test/test_signal.py (original) +++ python/branches/py3k/Lib/test/test_signal.py Fri Aug 6 21:27:32 2010 @@ -9,7 +9,7 @@ import traceback import sys, os, time, errno
-if sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos': +if sys.platform == 'os2' or sys.platform == 'riscos': raise unittest.SkipTest("Can't test signal on %s" % \ sys.platform)
@@ -37,6 +37,7 @@ return None
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
In the previous chunk sys.platform[:3] was used instead of just sys.platform. Are there some other "winXX" platform that should be skipped too?
The sliced check was to make it more convenient to also check "os2" at the same time in the first hunk of the change. Windows is "win32" regardless of 32 or 64-bit so that check works. class InterProcessSignalTests(unittest.TestCase):
MAX_DURATION = 20 # Entire test should last at most 20 sec.
@@ -186,6 +187,7 @@ self.MAX_DURATION)
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class BasicSignalTests(unittest.TestCase): def trivial_signal_handler(self, *args): pass @@ -208,6 +210,23 @@ self.assertEquals(signal.getsignal(signal.SIGHUP), hup)
+@unittest.skipUnless(sys.platform == "win32", "Windows specific") +class WindowsSignalTests(unittest.TestCase): + def test_issue9324(self): + handler = lambda x, y: None + signal.signal(signal.SIGABRT, handler) + signal.signal(signal.SIGFPE, handler) + signal.signal(signal.SIGILL, handler) + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGSEGV, handler) + signal.signal(signal.SIGTERM, handler) + + with self.assertRaises(ValueError): + signal.signal(-1, handler) + sinal.signal(7, handler)
You should use two separate assertRaises here, otherwise the second line is not executed if the first one raises an error (and if the first doesn't raise an error but the second does the test will pass even if it shouldn't). This also masks the typo in the second line.
Thanks for noticing this. Corrected in r83771 (py3k), r83772 (release31-maint), and r83773 (release27-maint). +
+ +@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class WakeupSignalTests(unittest.TestCase): TIMEOUT_FULL = 10 TIMEOUT_HALF = 5 @@ -253,14 +272,15 @@ os.close(self.write) signal.signal(signal.SIGALRM, self.alrm)
+@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class SiginterruptTest(unittest.TestCase): - signum = signal.SIGUSR1
def setUp(self): """Install a no-op signal handler that can be set to allow interrupts or not, and arrange for the original signal handler to be re-installed when the test is finished. """ + self.signum = signal.SIGUSR1 oldhandler = signal.signal(self.signum, lambda x,y: None) self.addCleanup(signal.signal, self.signum, oldhandler)
@@ -354,7 +374,7 @@ self.assertFalse(i)
- +@unittest.skipIf(sys.platform == "win32", "Not valid on Windows") class ItimerTest(unittest.TestCase): def setUp(self): self.hndl_called = False @@ -463,8 +483,11 @@ self.assertEqual(self.hndl_called, True)
def test_main(): - support.run_unittest(BasicSignalTests, InterProcessSignalTests, - WakeupSignalTests, SiginterruptTest, ItimerTest) + if sys.platform == "win32": + support.run_unittest(WindowsSignalTests) + else: + support.run_unittest(BasicSignalTests, InterProcessSignalTests, + WakeupSignalTests, SiginterruptTest, ItimerTest)
Is this necessary? If the tests are marked with a skip decorator they will be skipped anyway (and also marked as skipped in the output).
Good point. Fixed in the above revisions. if __name__ == "__main__":
Modified: python/branches/py3k/Misc/NEWS
============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Aug 6 21:27:32 2010 @@ -24,6 +24,9 @@ Extensions ----------
+- Issue #9324: Add parameter validation to signal.signal on Windows in order + to prevent crashes. + - Issue #9526: Remove some outdated (int) casts that were preventing the array module from working correctly with arrays of more than 2**31 elements.
Modified: python/branches/py3k/Modules/signalmodule.c
============================================================================== --- python/branches/py3k/Modules/signalmodule.c (original) +++ python/branches/py3k/Modules/signalmodule.c Fri Aug 6 21:27:32 2010 @@ -255,8 +255,23 @@ int sig_num; PyObject *old_handler; void (*func)(int); +#ifdef MS_WINDOWS + int cur_sig, num_valid_sigs = 6; + static int valid_sigs[] = {SIGABRT, SIGFPE, SIGILL, SIGINT, + SIGSEGV, SIGTERM}; + BOOL valid_sig = FALSE; +#endif if (!PyArg_ParseTuple(args, "iO:signal",&sig_num,&obj)) return NULL; +#ifdef MS_WINDOWS + /* Validate that sig_num is one of the allowable signals */ + for (cur_sig = 0; cur_sig< num_valid_sigs; cur_sig++) + valid_sig |= (sig_num == valid_sigs[cur_sig]); + if (!valid_sig) { + PyErr_SetString(PyExc_ValueError, "signal number out of range"); + return NULL; + } +#endif #ifdef WITH_THREAD if (PyThread_get_thread_ident() != main_thread) { PyErr_SetString(PyExc_ValueError,
Best Regards, Ezio Melotti
On 7 August 2010 04:57, Brian Curtin <brian.curtin@gmail.com> wrote:
-if sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos':
The sliced check was to make it more convenient to also check "os2" at the same time in the first hunk of the change. Windows is "win32" regardless of 32 or 64-bit so that check works.
Wouldn't if sys.platform in ('win32', 'os2', 'riscos'): work just as well? Paul
participants (3)
-
Brian Curtin -
Ezio Melotti -
Paul Moore