mirror of https://github.com/python/cpython
gh-89928: Fix integer conversion of device numbers (GH-31794)
Fix os.major(), os.minor() and os.makedev(). Support device numbers larger than 2**63-1. Support non-existent device number (NODEV).
This commit is contained in:
parent
5f03f09134
commit
7111d9605f
|
@ -704,7 +704,8 @@ class PosixTester(unittest.TestCase):
|
|||
self.assertEqual(posix.major(dev), major)
|
||||
self.assertRaises(TypeError, posix.major, float(dev))
|
||||
self.assertRaises(TypeError, posix.major)
|
||||
self.assertRaises((ValueError, OverflowError), posix.major, -1)
|
||||
for x in -2, 2**64, -2**63-1:
|
||||
self.assertRaises((ValueError, OverflowError), posix.major, x)
|
||||
|
||||
minor = posix.minor(dev)
|
||||
self.assertIsInstance(minor, int)
|
||||
|
@ -712,13 +713,23 @@ class PosixTester(unittest.TestCase):
|
|||
self.assertEqual(posix.minor(dev), minor)
|
||||
self.assertRaises(TypeError, posix.minor, float(dev))
|
||||
self.assertRaises(TypeError, posix.minor)
|
||||
self.assertRaises((ValueError, OverflowError), posix.minor, -1)
|
||||
for x in -2, 2**64, -2**63-1:
|
||||
self.assertRaises((ValueError, OverflowError), posix.minor, x)
|
||||
|
||||
self.assertEqual(posix.makedev(major, minor), dev)
|
||||
self.assertRaises(TypeError, posix.makedev, float(major), minor)
|
||||
self.assertRaises(TypeError, posix.makedev, major, float(minor))
|
||||
self.assertRaises(TypeError, posix.makedev, major)
|
||||
self.assertRaises(TypeError, posix.makedev)
|
||||
for x in -2, 2**32, 2**64, -2**63-1:
|
||||
self.assertRaises((ValueError, OverflowError), posix.makedev, x, minor)
|
||||
self.assertRaises((ValueError, OverflowError), posix.makedev, major, x)
|
||||
|
||||
if sys.platform == 'linux':
|
||||
NODEV = -1
|
||||
self.assertEqual(posix.major(NODEV), NODEV)
|
||||
self.assertEqual(posix.minor(NODEV), NODEV)
|
||||
self.assertEqual(posix.makedev(NODEV, NODEV), NODEV)
|
||||
|
||||
def _test_all_chown_common(self, chown_func, first_param, stat_func):
|
||||
"""Common code for chown, fchown and lchown tests."""
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix integer conversion in :func:`os.major`, :func:`os.minor`, and
|
||||
:func:`os.makedev`. Support device numbers larger than ``2**63-1``. Support
|
||||
non-existent device number (``NODEV``).
|
|
@ -8685,7 +8685,7 @@ PyDoc_STRVAR(os_major__doc__,
|
|||
#define OS_MAJOR_METHODDEF \
|
||||
{"major", (PyCFunction)os_major, METH_O, os_major__doc__},
|
||||
|
||||
static unsigned int
|
||||
static PyObject *
|
||||
os_major_impl(PyObject *module, dev_t device);
|
||||
|
||||
static PyObject *
|
||||
|
@ -8693,16 +8693,11 @@ os_major(PyObject *module, PyObject *arg)
|
|||
{
|
||||
PyObject *return_value = NULL;
|
||||
dev_t device;
|
||||
unsigned int _return_value;
|
||||
|
||||
if (!_Py_Dev_Converter(arg, &device)) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_major_impl(module, device);
|
||||
if ((_return_value == (unsigned int)-1) && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = PyLong_FromUnsignedLong((unsigned long)_return_value);
|
||||
return_value = os_major_impl(module, device);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
@ -8721,7 +8716,7 @@ PyDoc_STRVAR(os_minor__doc__,
|
|||
#define OS_MINOR_METHODDEF \
|
||||
{"minor", (PyCFunction)os_minor, METH_O, os_minor__doc__},
|
||||
|
||||
static unsigned int
|
||||
static PyObject *
|
||||
os_minor_impl(PyObject *module, dev_t device);
|
||||
|
||||
static PyObject *
|
||||
|
@ -8729,16 +8724,11 @@ os_minor(PyObject *module, PyObject *arg)
|
|||
{
|
||||
PyObject *return_value = NULL;
|
||||
dev_t device;
|
||||
unsigned int _return_value;
|
||||
|
||||
if (!_Py_Dev_Converter(arg, &device)) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_minor_impl(module, device);
|
||||
if ((_return_value == (unsigned int)-1) && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = PyLong_FromUnsignedLong((unsigned long)_return_value);
|
||||
return_value = os_minor_impl(module, device);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
@ -8758,25 +8748,23 @@ PyDoc_STRVAR(os_makedev__doc__,
|
|||
{"makedev", _PyCFunction_CAST(os_makedev), METH_FASTCALL, os_makedev__doc__},
|
||||
|
||||
static dev_t
|
||||
os_makedev_impl(PyObject *module, int major, int minor);
|
||||
os_makedev_impl(PyObject *module, dev_t major, dev_t minor);
|
||||
|
||||
static PyObject *
|
||||
os_makedev(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int major;
|
||||
int minor;
|
||||
dev_t major;
|
||||
dev_t minor;
|
||||
dev_t _return_value;
|
||||
|
||||
if (!_PyArg_CheckPositional("makedev", nargs, 2, 2)) {
|
||||
goto exit;
|
||||
}
|
||||
major = PyLong_AsInt(args[0]);
|
||||
if (major == -1 && PyErr_Occurred()) {
|
||||
if (!_Py_Dev_Converter(args[0], &major)) {
|
||||
goto exit;
|
||||
}
|
||||
minor = PyLong_AsInt(args[1]);
|
||||
if (minor == -1 && PyErr_Occurred()) {
|
||||
if (!_Py_Dev_Converter(args[1], &minor)) {
|
||||
goto exit;
|
||||
}
|
||||
_return_value = os_makedev_impl(module, major, minor);
|
||||
|
@ -12795,4 +12783,4 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored))
|
|||
#ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
#define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
#endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */
|
||||
/*[clinic end generated code: output=300bd1c54dc43765 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=49c2d7a65f7a9f3b input=a9049054013a1b77]*/
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "pycore_fileutils.h" // _Py_closerange()
|
||||
#include "pycore_import.h" // _PyImport_ReInitLock()
|
||||
#include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
|
||||
#include "pycore_long.h" // _PyLong_IsNegative()
|
||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
#include "pycore_object.h" // _PyObject_LookupSpecial()
|
||||
#include "pycore_pylifecycle.h" // _PyOS_URandom()
|
||||
|
@ -967,16 +968,46 @@ fail:
|
|||
#endif /* MS_WINDOWS */
|
||||
|
||||
|
||||
#define _PyLong_FromDev PyLong_FromLongLong
|
||||
static PyObject *
|
||||
_PyLong_FromDev(dev_t dev)
|
||||
{
|
||||
#ifdef NODEV
|
||||
if (dev == NODEV) {
|
||||
return PyLong_FromLongLong((long long)dev);
|
||||
}
|
||||
#endif
|
||||
return PyLong_FromUnsignedLongLong((unsigned long long)dev);
|
||||
}
|
||||
|
||||
|
||||
#if (defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)) || defined(HAVE_DEVICE_MACROS)
|
||||
static int
|
||||
_Py_Dev_Converter(PyObject *obj, void *p)
|
||||
{
|
||||
*((dev_t *)p) = PyLong_AsUnsignedLongLong(obj);
|
||||
if (PyErr_Occurred())
|
||||
#ifdef NODEV
|
||||
if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) {
|
||||
int overflow;
|
||||
long long result = PyLong_AsLongLongAndOverflow(obj, &overflow);
|
||||
if (result == -1 && PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
if (!overflow && result == (long long)NODEV) {
|
||||
*((dev_t *)p) = NODEV;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long long result = PyLong_AsUnsignedLongLong(obj);
|
||||
if (result == (unsigned long long)-1 && PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
if ((unsigned long long)(dev_t)result != result) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large to convert to C dev_t");
|
||||
return 0;
|
||||
}
|
||||
*((dev_t *)p) = (dev_t)result;
|
||||
return 1;
|
||||
}
|
||||
#endif /* (HAVE_MKNOD && HAVE_MAKEDEV) || HAVE_DEVICE_MACROS */
|
||||
|
@ -12517,9 +12548,31 @@ os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device,
|
|||
#endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */
|
||||
|
||||
|
||||
static PyObject *
|
||||
major_minor_conv(unsigned int value)
|
||||
{
|
||||
#ifdef NODEV
|
||||
if (value == (unsigned int)NODEV) {
|
||||
return PyLong_FromLong((int)NODEV);
|
||||
}
|
||||
#endif
|
||||
return PyLong_FromUnsignedLong(value);
|
||||
}
|
||||
|
||||
static int
|
||||
major_minor_check(dev_t value)
|
||||
{
|
||||
#ifdef NODEV
|
||||
if (value == NODEV) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return (dev_t)(unsigned int)value == value;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MACROS
|
||||
/*[clinic input]
|
||||
os.major -> unsigned_int
|
||||
os.major
|
||||
|
||||
device: dev_t
|
||||
/
|
||||
|
@ -12527,16 +12580,16 @@ os.major -> unsigned_int
|
|||
Extracts a device major number from a raw device number.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static unsigned int
|
||||
static PyObject *
|
||||
os_major_impl(PyObject *module, dev_t device)
|
||||
/*[clinic end generated code: output=5b3b2589bafb498e input=1e16a4d30c4d4462]*/
|
||||
/*[clinic end generated code: output=4071ffee17647891 input=b1a0a14ec9448229]*/
|
||||
{
|
||||
return major(device);
|
||||
return major_minor_conv(major(device));
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os.minor -> unsigned_int
|
||||
os.minor
|
||||
|
||||
device: dev_t
|
||||
/
|
||||
|
@ -12544,28 +12597,33 @@ os.minor -> unsigned_int
|
|||
Extracts a device minor number from a raw device number.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static unsigned int
|
||||
static PyObject *
|
||||
os_minor_impl(PyObject *module, dev_t device)
|
||||
/*[clinic end generated code: output=5e1a25e630b0157d input=0842c6d23f24c65e]*/
|
||||
/*[clinic end generated code: output=306cb78e3bc5004f input=2f686e463682a9da]*/
|
||||
{
|
||||
return minor(device);
|
||||
return major_minor_conv(minor(device));
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os.makedev -> dev_t
|
||||
|
||||
major: int
|
||||
minor: int
|
||||
major: dev_t
|
||||
minor: dev_t
|
||||
/
|
||||
|
||||
Composes a raw device number from the major and minor device numbers.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static dev_t
|
||||
os_makedev_impl(PyObject *module, int major, int minor)
|
||||
/*[clinic end generated code: output=881aaa4aba6f6a52 input=4b9fd8fc73cbe48f]*/
|
||||
os_makedev_impl(PyObject *module, dev_t major, dev_t minor)
|
||||
/*[clinic end generated code: output=cad6125c51f5af80 input=2146126ec02e55c1]*/
|
||||
{
|
||||
if (!major_minor_check(major) || !major_minor_check(minor)) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large to convert to C unsigned int");
|
||||
return (dev_t)-1;
|
||||
}
|
||||
return makedev(major, minor);
|
||||
}
|
||||
#endif /* HAVE_DEVICE_MACROS */
|
||||
|
|
Loading…
Reference in New Issue