Skip to content

[3.10] bpo-46913: Fix test_ctypes, test_hashlib, test_faulthandler on UBSan #31675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Lib/ctypes/test/test_bitfields.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ctypes import *
from ctypes.test import need_symbol
from test import support
import unittest
import os

Expand Down Expand Up @@ -39,6 +40,8 @@ def test_ints(self):
setattr(b, name, i)
self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii')))

# bpo-46913: _ctypes/cfield.c h_get() has an undefined behavior
@support.skip_if_sanitizer(ub=True)
def test_shorts(self):
b = BITS()
name = "M"
Expand Down
34 changes: 26 additions & 8 deletions Lib/test/test_hashlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def get_fips_mode():

requires_blake2 = unittest.skipUnless(_blake2, 'requires _blake2')

# bpo-46913: Don't test the _sha3 extension on a Python UBSAN build
SKIP_SHA3 = support.check_sanitizer(ub=True)
requires_sha3 = unittest.skipUnless(not SKIP_SHA3, 'requires _sha3')


def hexstr(s):
assert isinstance(s, bytes), repr(s)
Expand Down Expand Up @@ -125,6 +129,8 @@ def __init__(self, *args, **kwargs):

self.constructors_to_test = {}
for algorithm in algorithms:
if SKIP_SHA3 and algorithm.startswith('sha3_'):
continue
self.constructors_to_test[algorithm] = set()

# For each algorithm, test the direct constructor and the use
Expand Down Expand Up @@ -177,14 +183,15 @@ def add_builtin_constructor(name):
add_builtin_constructor('blake2s')
add_builtin_constructor('blake2b')

_sha3 = self._conditional_import_module('_sha3')
if _sha3:
add_builtin_constructor('sha3_224')
add_builtin_constructor('sha3_256')
add_builtin_constructor('sha3_384')
add_builtin_constructor('sha3_512')
add_builtin_constructor('shake_128')
add_builtin_constructor('shake_256')
if not SKIP_SHA3:
_sha3 = self._conditional_import_module('_sha3')
if _sha3:
add_builtin_constructor('sha3_224')
add_builtin_constructor('sha3_256')
add_builtin_constructor('sha3_384')
add_builtin_constructor('sha3_512')
add_builtin_constructor('shake_128')
add_builtin_constructor('shake_256')

super(HashLibTestCase, self).__init__(*args, **kwargs)

Expand Down Expand Up @@ -383,6 +390,7 @@ def test_no_unicode_blake2(self):
self.check_no_unicode('blake2b')
self.check_no_unicode('blake2s')

@requires_sha3
def test_no_unicode_sha3(self):
self.check_no_unicode('sha3_224')
self.check_no_unicode('sha3_256')
Expand Down Expand Up @@ -418,6 +426,7 @@ def test_blocksize_name(self):
self.check_blocksize_name('sha384', 128, 48)
self.check_blocksize_name('sha512', 128, 64)

@requires_sha3
def test_blocksize_name_sha3(self):
self.check_blocksize_name('sha3_224', 144, 28)
self.check_blocksize_name('sha3_256', 136, 32)
Expand All @@ -438,6 +447,7 @@ def check_sha3(self, name, capacity, rate, suffix):
self.assertEqual(m._rate_bits, rate)
self.assertEqual(m._suffix, suffix)

@requires_sha3
def test_extra_sha3(self):
self.check_sha3('sha3_224', 448, 1152, b'\x06')
self.check_sha3('sha3_256', 512, 1088, b'\x06')
Expand Down Expand Up @@ -777,36 +787,44 @@ def test_blake2s_vectors(self):
key = bytes.fromhex(key)
self.check('blake2s', msg, md, key=key)

@requires_sha3
def test_case_sha3_224_0(self):
self.check('sha3_224', b"",
"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7")

@requires_sha3
def test_case_sha3_224_vector(self):
for msg, md in read_vectors('sha3_224'):
self.check('sha3_224', msg, md)

@requires_sha3
def test_case_sha3_256_0(self):
self.check('sha3_256', b"",
"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a")

@requires_sha3
def test_case_sha3_256_vector(self):
for msg, md in read_vectors('sha3_256'):
self.check('sha3_256', msg, md)

@requires_sha3
def test_case_sha3_384_0(self):
self.check('sha3_384', b"",
"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"+
"c3713831264adb47fb6bd1e058d5f004")

@requires_sha3
def test_case_sha3_384_vector(self):
for msg, md in read_vectors('sha3_384'):
self.check('sha3_384', msg, md)

@requires_sha3
def test_case_sha3_512_0(self):
self.check('sha3_512', b"",
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"+
"15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26")

@requires_sha3
def test_case_sha3_512_vector(self):
for msg, md in read_vectors('sha3_512'):
self.check('sha3_512', msg, md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix test_faulthandler.test_sigfpe() if Python is built with undefined
behavior sanitizer (UBSAN): disable UBSAN on the faulthandler_sigfpe()
function. Patch by Victor Stinner.
26 changes: 23 additions & 3 deletions Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@

#define PUTS(fd, str) _Py_write_noraise(fd, str, strlen(str))


// clang uses __attribute__((no_sanitize("undefined")))
// GCC 4.9+ uses __attribute__((no_sanitize_undefined))
#if defined(__has_feature) // Clang
# if __has_feature(undefined_behavior_sanitizer)
# define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
# endif
#endif
#if defined(__GNUC__) \
&& ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))
# define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
#endif
#ifndef _Py_NO_SANITIZE_UNDEFINED
# define _Py_NO_SANITIZE_UNDEFINED
#endif


_Py_IDENTIFIER(enable);
_Py_IDENTIFIER(fileno);
_Py_IDENTIFIER(flush);
Expand Down Expand Up @@ -1014,7 +1031,7 @@ faulthandler_suppress_crash_report(void)
#endif
}

static PyObject *
static PyObject* _Py_NO_SANITIZE_UNDEFINED
faulthandler_read_null(PyObject *self, PyObject *args)
{
volatile int *x;
Expand Down Expand Up @@ -1103,17 +1120,20 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}

static PyObject *
static PyObject* _Py_NO_SANITIZE_UNDEFINED
faulthandler_sigfpe(PyObject *self, PyObject *args)
{
faulthandler_suppress_crash_report();

/* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
PowerPC. Use volatile to disable compile-time optimizations. */
volatile int x = 1, y = 0, z;
faulthandler_suppress_crash_report();
z = x / y;

/* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
raise it manually. */
raise(SIGFPE);

/* This line is never reached, but we pretend to make something with z
to silence a compiler warning. */
return PyLong_FromLong(z);
Expand Down