Skip to content

Commit 8f19dff

Browse files
authored
Update test_resource.py to 3.14.4 (#7808)
* Update `test_resource.py` to 3.14.4 * Mark failing tests * Skip crashing macos test
1 parent 320355f commit 8f19dff

2 files changed

Lines changed: 171 additions & 89 deletions

File tree

Lib/test/test_resource.py

Lines changed: 146 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -14,91 +14,157 @@ class ResourceTest(unittest.TestCase):
1414

1515
def test_args(self):
1616
self.assertRaises(TypeError, resource.getrlimit)
17-
self.assertRaises(TypeError, resource.getrlimit, 42, 42)
17+
self.assertRaises(TypeError, resource.getrlimit, 0, 42)
18+
self.assertRaises(OverflowError, resource.getrlimit, 2**1000)
19+
self.assertRaises(OverflowError, resource.getrlimit, -2**1000)
20+
self.assertRaises(TypeError, resource.getrlimit, '0')
1821
self.assertRaises(TypeError, resource.setrlimit)
19-
self.assertRaises(TypeError, resource.setrlimit, 42, 42, 42)
22+
self.assertRaises(TypeError, resource.setrlimit, 0)
23+
self.assertRaises(TypeError, resource.setrlimit, 0, 42)
24+
self.assertRaises(TypeError, resource.setrlimit, 0, 42, 42)
25+
self.assertRaises(OverflowError, resource.setrlimit, 2**1000, (42, 42))
26+
self.assertRaises(OverflowError, resource.setrlimit, -2**1000, (42, 42))
27+
self.assertRaises(ValueError, resource.setrlimit, 0, (42,))
28+
self.assertRaises(ValueError, resource.setrlimit, 0, (42, 42, 42))
29+
self.assertRaises(TypeError, resource.setrlimit, '0', (42, 42))
30+
self.assertRaises(TypeError, resource.setrlimit, 0, ('42', 42))
31+
self.assertRaises(TypeError, resource.setrlimit, 0, (42, '42'))
2032

2133
@unittest.skipIf(sys.platform == "vxworks",
2234
"setting RLIMIT_FSIZE is not supported on VxWorks")
35+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
2336
def test_fsize_ismax(self):
24-
try:
25-
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
26-
except AttributeError:
27-
pass
28-
else:
29-
# RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really big
30-
# number on a platform with large file support. On these platforms,
31-
# we need to test that the get/setrlimit functions properly convert
32-
# the number to a C long long and that the conversion doesn't raise
33-
# an error.
34-
self.assertEqual(resource.RLIM_INFINITY, max)
35-
resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
36-
37-
# TODO: RUSTPYTHON
38-
@unittest.skip("file size limit exceeded.")
37+
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
38+
# RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really big
39+
# number on a platform with large file support. On these platforms,
40+
# we need to test that the get/setrlimit functions properly convert
41+
# the number to a C long long and that the conversion doesn't raise
42+
# an error.
43+
self.assertEqual(resource.RLIM_INFINITY, max)
44+
resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
45+
46+
@unittest.skip("TODO: RUSTPYTHON; crash")
47+
@unittest.skipIf(sys.platform == "vxworks",
48+
"setting RLIMIT_FSIZE is not supported on VxWorks")
49+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
3950
def test_fsize_enforced(self):
51+
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
52+
# Check to see what happens when the RLIMIT_FSIZE is small. Some
53+
# versions of Python were terminated by an uncaught SIGXFSZ, but
54+
# pythonrun.c has been fixed to ignore that exception. If so, the
55+
# write() should return EFBIG when the limit is exceeded.
56+
57+
# At least one platform has an unlimited RLIMIT_FSIZE and attempts
58+
# to change it raise ValueError instead.
4059
try:
41-
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
42-
except AttributeError:
43-
pass
44-
else:
45-
# Check to see what happens when the RLIMIT_FSIZE is small. Some
46-
# versions of Python were terminated by an uncaught SIGXFSZ, but
47-
# pythonrun.c has been fixed to ignore that exception. If so, the
48-
# write() should return EFBIG when the limit is exceeded.
49-
50-
# At least one platform has an unlimited RLIMIT_FSIZE and attempts
51-
# to change it raise ValueError instead.
5260
try:
61+
resource.setrlimit(resource.RLIMIT_FSIZE, (1024, max))
62+
limit_set = True
63+
except ValueError:
64+
limit_set = False
65+
f = open(os_helper.TESTFN, "wb")
66+
try:
67+
f.write(b"X" * 1024)
5368
try:
54-
resource.setrlimit(resource.RLIMIT_FSIZE, (1024, max))
55-
limit_set = True
56-
except ValueError:
57-
limit_set = False
58-
f = open(os_helper.TESTFN, "wb")
59-
try:
60-
f.write(b"X" * 1024)
61-
try:
62-
f.write(b"Y")
69+
f.write(b"Y")
70+
f.flush()
71+
# On some systems (e.g., Ubuntu on hppa) the flush()
72+
# doesn't always cause the exception, but the close()
73+
# does eventually. Try flushing several times in
74+
# an attempt to ensure the file is really synced and
75+
# the exception raised.
76+
for i in range(5):
77+
time.sleep(.1)
6378
f.flush()
64-
# On some systems (e.g., Ubuntu on hppa) the flush()
65-
# doesn't always cause the exception, but the close()
66-
# does eventually. Try flushing several times in
67-
# an attempt to ensure the file is really synced and
68-
# the exception raised.
69-
for i in range(5):
70-
time.sleep(.1)
71-
f.flush()
72-
except OSError:
73-
if not limit_set:
74-
raise
75-
if limit_set:
76-
# Close will attempt to flush the byte we wrote
77-
# Restore limit first to avoid getting a spurious error
78-
resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
79-
finally:
80-
f.close()
81-
finally:
79+
except OSError:
80+
if not limit_set:
81+
raise
8282
if limit_set:
83+
# Close will attempt to flush the byte we wrote
84+
# Restore limit first to avoid getting a spurious error
8385
resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
84-
os_helper.unlink(os_helper.TESTFN)
86+
finally:
87+
f.close()
88+
finally:
89+
if limit_set:
90+
resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
91+
os_helper.unlink(os_helper.TESTFN)
8592

86-
def test_fsize_toobig(self):
93+
@unittest.skipIf(sys.platform == "vxworks",
94+
"setting RLIMIT_FSIZE is not supported on VxWorks")
95+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
96+
def test_fsize_too_big(self):
8797
# Be sure that setrlimit is checking for really large values
8898
too_big = 10**50
99+
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
100+
try:
101+
resource.setrlimit(resource.RLIMIT_FSIZE, (too_big, max))
102+
except (OverflowError, ValueError):
103+
pass
89104
try:
90-
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
91-
except AttributeError:
105+
resource.setrlimit(resource.RLIMIT_FSIZE, (max, too_big))
106+
except (OverflowError, ValueError):
92107
pass
108+
109+
@unittest.skipIf(sys.platform == "darwin", "TODO: RUSTPYTHON; crash")
110+
@unittest.skipIf(sys.platform == "vxworks",
111+
"setting RLIMIT_FSIZE is not supported on VxWorks")
112+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
113+
def test_fsize_not_too_big(self):
114+
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
115+
self.addCleanup(resource.setrlimit, resource.RLIMIT_FSIZE, (cur, max))
116+
117+
def expected(cur):
118+
if resource.RLIM_INFINITY < 0:
119+
return [(cur, max), (resource.RLIM_INFINITY, max)]
120+
elif resource.RLIM_INFINITY < cur:
121+
return [(resource.RLIM_INFINITY, max)]
122+
else:
123+
return [(cur, max)]
124+
125+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**31-5, max))
126+
self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**31-5, max))
127+
128+
try:
129+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**32, max))
130+
except OverflowError:
131+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**31, max))
132+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**31))
133+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**32-5, max))
134+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**32-5))
93135
else:
136+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**32))
137+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**31, max))
138+
self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**31, max))
139+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**32-5, max))
140+
self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**32-5, max))
141+
142+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**63-5, max))
143+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**63-5))
94144
try:
95-
resource.setrlimit(resource.RLIMIT_FSIZE, (too_big, max))
96-
except (OverflowError, ValueError):
97-
pass
98-
try:
99-
resource.setrlimit(resource.RLIMIT_FSIZE, (max, too_big))
100-
except (OverflowError, ValueError):
145+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**63, max))
146+
except ValueError:
147+
# There is a hard limit on macOS.
101148
pass
149+
else:
150+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**63))
151+
resource.setrlimit(resource.RLIMIT_FSIZE, (2**64-5, max))
152+
self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**64-5))
153+
154+
@unittest.expectedFailure # TODO: RUSTPYTHON; OverflowError: Python int too large to convert to Rust u64
155+
@unittest.skipIf(sys.platform == "vxworks",
156+
"setting RLIMIT_FSIZE is not supported on VxWorks")
157+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
158+
def test_fsize_negative(self):
159+
(cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
160+
for value in -5, -2**31, -2**32-5, -2**63, -2**64-5, -2**1000:
161+
with self.subTest(value=value):
162+
# This test assumes that the values don't map to RLIM_INFINITY,
163+
# though Posix doesn't guarantee it.
164+
self.assertNotEqual(value, resource.RLIM_INFINITY)
165+
166+
self.assertRaises(ValueError, resource.setrlimit, resource.RLIMIT_FSIZE, (value, max))
167+
self.assertRaises(ValueError, resource.setrlimit, resource.RLIMIT_FSIZE, (cur, value))
102168

103169
@unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage")
104170
def test_getrusage(self):
@@ -119,24 +185,20 @@ def test_getrusage(self):
119185
# Issue 6083: Reference counting bug
120186
@unittest.skipIf(sys.platform == "vxworks",
121187
"setting RLIMIT_CPU is not supported on VxWorks")
188+
@unittest.skipUnless(hasattr(resource, 'RLIMIT_CPU'), 'requires resource.RLIMIT_CPU')
122189
def test_setrusage_refcount(self):
123-
try:
124-
limits = resource.getrlimit(resource.RLIMIT_CPU)
125-
except AttributeError:
126-
pass
127-
else:
128-
class BadSequence:
129-
def __len__(self):
130-
return 2
131-
def __getitem__(self, key):
132-
if key in (0, 1):
133-
return len(tuple(range(1000000)))
134-
raise IndexError
135-
136-
resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
137-
138-
# TODO: RUSTPYTHON: module 'resource' has no attribute 'getpagesize'
139-
@unittest.expectedFailure
190+
limits = resource.getrlimit(resource.RLIMIT_CPU)
191+
class BadSequence:
192+
def __len__(self):
193+
return 2
194+
def __getitem__(self, key):
195+
if key in (0, 1):
196+
return len(tuple(range(1000000)))
197+
raise IndexError
198+
199+
resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
200+
201+
@unittest.expectedFailure # TODO: RUSTPYTHON; module 'resource' has no attribute 'getpagesize'
140202
def test_pagesize(self):
141203
pagesize = resource.getpagesize()
142204
self.assertIsInstance(pagesize, int)
@@ -172,7 +234,8 @@ class BadSeq:
172234
def __len__(self):
173235
return 2
174236
def __getitem__(self, key):
175-
return limits[key] - 1 # new reference
237+
lim = limits[key]
238+
return lim - 1 if lim > 0 else lim + sys.maxsize*2 # new reference
176239

177240
limits = resource.getrlimit(resource.RLIMIT_AS)
178241
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),

crates/stdlib/src/resource.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub(crate) use resource::module_def;
66
mod resource {
77
use crate::vm::{
88
PyObject, PyObjectRef, PyResult, TryFromBorrowedObject, VirtualMachine,
9+
builtins::PyIntRef,
910
convert::{ToPyException, ToPyObject},
1011
types::PyStructSequence,
1112
};
@@ -135,6 +136,7 @@ mod resource {
135136
}
136137

137138
struct Limits(libc::rlimit);
139+
138140
impl<'a> TryFromBorrowedObject<'a> for Limits {
139141
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
140142
let seq: Vec<libc::rlim_t> = obj.try_to_value(vm)?;
@@ -147,18 +149,32 @@ mod resource {
147149
}
148150
}
149151
}
152+
150153
impl ToPyObject for Limits {
151154
fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
152155
(self.0.rlim_cur, self.0.rlim_max).to_pyobject(vm)
153156
}
154157
}
155158

159+
fn py2rlim(obj: PyIntRef, vm: &VirtualMachine) -> PyResult<libc::rlim_t> {
160+
let value = obj.try_to_primitive::<isize>(vm)?;
161+
162+
if value.is_negative() {
163+
return Err(vm.new_value_error("Cannot convert negative int"));
164+
}
165+
166+
libc::rlim_t::try_from(value)
167+
.map_err(|_| vm.new_overflow_error("Python int too large to convert to C rlim_t"))
168+
}
169+
156170
#[pyfunction]
157-
fn getrlimit(resource: i32, vm: &VirtualMachine) -> PyResult<Limits> {
158-
#[allow(clippy::unnecessary_cast)]
159-
if resource < 0 || resource >= RLIM_NLIMITS as i32 {
171+
fn getrlimit(resource: PyIntRef, vm: &VirtualMachine) -> PyResult<Limits> {
172+
let resource = py2rlim(resource, vm)?;
173+
174+
if resource >= RLIM_NLIMITS as libc::rlim_t {
160175
return Err(vm.new_value_error("invalid resource specified"));
161176
}
177+
162178
let rlimit = unsafe {
163179
let mut rlimit = mem::MaybeUninit::<libc::rlimit>::uninit();
164180
if libc::getrlimit(resource as _, rlimit.as_mut_ptr()) == -1 {
@@ -170,18 +186,21 @@ mod resource {
170186
}
171187

172188
#[pyfunction]
173-
fn setrlimit(resource: i32, limits: Limits, vm: &VirtualMachine) -> PyResult<()> {
174-
#[allow(clippy::unnecessary_cast)]
175-
if resource < 0 || resource >= RLIM_NLIMITS as i32 {
189+
fn setrlimit(resource: PyIntRef, limits: Limits, vm: &VirtualMachine) -> PyResult<()> {
190+
let resource = py2rlim(resource, vm)?;
191+
192+
if resource >= RLIM_NLIMITS as libc::rlim_t {
176193
return Err(vm.new_value_error("invalid resource specified"));
177194
}
195+
178196
let res = unsafe {
179197
if libc::setrlimit(resource as _, &limits.0) == -1 {
180198
Err(io::Error::last_os_error())
181199
} else {
182200
Ok(())
183201
}
184202
};
203+
185204
res.map_err(|e| match e.kind() {
186205
io::ErrorKind::InvalidInput => {
187206
vm.new_value_error("current limit exceeds maximum limit")

0 commit comments

Comments
 (0)