mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	[3.14] gh-137044: Support large limit values in getrlimit() and setrlimit() (GH-137338) (#137506)
gh-137044: Support large limit values in getrlimit() and setrlimit() (GH-137338)
* Return large limit values as positive integers instead of negative integers
  in resource.getrlimit().
* Accept large values and reject negative values (except RLIM_INFINITY)
  for limits in resource.setrlimit().
(cherry picked from commit baefaa6cba)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									b414ad1043
								
							
						
					
					
						commit
						c4be405fe9
					
				
					 4 changed files with 200 additions and 121 deletions
				
			
		| 
						 | 
					@ -14,89 +14,154 @@ class ResourceTest(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_args(self):
 | 
					    def test_args(self):
 | 
				
			||||||
        self.assertRaises(TypeError, resource.getrlimit)
 | 
					        self.assertRaises(TypeError, resource.getrlimit)
 | 
				
			||||||
        self.assertRaises(TypeError, resource.getrlimit, 42, 42)
 | 
					        self.assertRaises(TypeError, resource.getrlimit, 0, 42)
 | 
				
			||||||
 | 
					        self.assertRaises(OverflowError, resource.getrlimit, 2**1000)
 | 
				
			||||||
 | 
					        self.assertRaises(OverflowError, resource.getrlimit, -2**1000)
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.getrlimit, '0')
 | 
				
			||||||
        self.assertRaises(TypeError, resource.setrlimit)
 | 
					        self.assertRaises(TypeError, resource.setrlimit)
 | 
				
			||||||
        self.assertRaises(TypeError, resource.setrlimit, 42, 42, 42)
 | 
					        self.assertRaises(TypeError, resource.setrlimit, 0)
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.setrlimit, 0, 42)
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.setrlimit, 0, 42, 42)
 | 
				
			||||||
 | 
					        self.assertRaises(OverflowError, resource.setrlimit, 2**1000, (42, 42))
 | 
				
			||||||
 | 
					        self.assertRaises(OverflowError, resource.setrlimit, -2**1000, (42, 42))
 | 
				
			||||||
 | 
					        self.assertRaises(ValueError, resource.setrlimit, 0, (42,))
 | 
				
			||||||
 | 
					        self.assertRaises(ValueError, resource.setrlimit, 0, (42, 42, 42))
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.setrlimit, '0', (42, 42))
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.setrlimit, 0, ('42', 42))
 | 
				
			||||||
 | 
					        self.assertRaises(TypeError, resource.setrlimit, 0, (42, '42'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(sys.platform == "vxworks",
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
					                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
 | 
				
			||||||
    def test_fsize_ismax(self):
 | 
					    def test_fsize_ismax(self):
 | 
				
			||||||
        try:
 | 
					        (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
				
			||||||
            (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
					        # RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really big
 | 
				
			||||||
        except AttributeError:
 | 
					        # number on a platform with large file support.  On these platforms,
 | 
				
			||||||
            pass
 | 
					        # we need to test that the get/setrlimit functions properly convert
 | 
				
			||||||
        else:
 | 
					        # the number to a C long long and that the conversion doesn't raise
 | 
				
			||||||
            # RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really big
 | 
					        # an error.
 | 
				
			||||||
            # number on a platform with large file support.  On these platforms,
 | 
					        self.assertEqual(resource.RLIM_INFINITY, max)
 | 
				
			||||||
            # we need to test that the get/setrlimit functions properly convert
 | 
					        resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
				
			||||||
            # the number to a C long long and that the conversion doesn't raise
 | 
					 | 
				
			||||||
            # an error.
 | 
					 | 
				
			||||||
            self.assertEqual(resource.RLIM_INFINITY, max)
 | 
					 | 
				
			||||||
            resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
 | 
					                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
 | 
				
			||||||
    def test_fsize_enforced(self):
 | 
					    def test_fsize_enforced(self):
 | 
				
			||||||
 | 
					        (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
				
			||||||
 | 
					        # Check to see what happens when the RLIMIT_FSIZE is small.  Some
 | 
				
			||||||
 | 
					        # versions of Python were terminated by an uncaught SIGXFSZ, but
 | 
				
			||||||
 | 
					        # pythonrun.c has been fixed to ignore that exception.  If so, the
 | 
				
			||||||
 | 
					        # write() should return EFBIG when the limit is exceeded.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # At least one platform has an unlimited RLIMIT_FSIZE and attempts
 | 
				
			||||||
 | 
					        # to change it raise ValueError instead.
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
					 | 
				
			||||||
        except AttributeError:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            # Check to see what happens when the RLIMIT_FSIZE is small.  Some
 | 
					 | 
				
			||||||
            # versions of Python were terminated by an uncaught SIGXFSZ, but
 | 
					 | 
				
			||||||
            # pythonrun.c has been fixed to ignore that exception.  If so, the
 | 
					 | 
				
			||||||
            # write() should return EFBIG when the limit is exceeded.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # At least one platform has an unlimited RLIMIT_FSIZE and attempts
 | 
					 | 
				
			||||||
            # to change it raise ValueError instead.
 | 
					 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
 | 
					                resource.setrlimit(resource.RLIMIT_FSIZE, (1024, max))
 | 
				
			||||||
 | 
					                limit_set = True
 | 
				
			||||||
 | 
					            except ValueError:
 | 
				
			||||||
 | 
					                limit_set = False
 | 
				
			||||||
 | 
					            f = open(os_helper.TESTFN, "wb")
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                f.write(b"X" * 1024)
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    resource.setrlimit(resource.RLIMIT_FSIZE, (1024, max))
 | 
					                    f.write(b"Y")
 | 
				
			||||||
                    limit_set = True
 | 
					                    f.flush()
 | 
				
			||||||
                except ValueError:
 | 
					                    # On some systems (e.g., Ubuntu on hppa) the flush()
 | 
				
			||||||
                    limit_set = False
 | 
					                    # doesn't always cause the exception, but the close()
 | 
				
			||||||
                f = open(os_helper.TESTFN, "wb")
 | 
					                    # does eventually.  Try flushing several times in
 | 
				
			||||||
                try:
 | 
					                    # an attempt to ensure the file is really synced and
 | 
				
			||||||
                    f.write(b"X" * 1024)
 | 
					                    # the exception raised.
 | 
				
			||||||
                    try:
 | 
					                    for i in range(5):
 | 
				
			||||||
                        f.write(b"Y")
 | 
					                        time.sleep(.1)
 | 
				
			||||||
                        f.flush()
 | 
					                        f.flush()
 | 
				
			||||||
                        # On some systems (e.g., Ubuntu on hppa) the flush()
 | 
					                except OSError:
 | 
				
			||||||
                        # doesn't always cause the exception, but the close()
 | 
					                    if not limit_set:
 | 
				
			||||||
                        # does eventually.  Try flushing several times in
 | 
					                        raise
 | 
				
			||||||
                        # an attempt to ensure the file is really synced and
 | 
					 | 
				
			||||||
                        # the exception raised.
 | 
					 | 
				
			||||||
                        for i in range(5):
 | 
					 | 
				
			||||||
                            time.sleep(.1)
 | 
					 | 
				
			||||||
                            f.flush()
 | 
					 | 
				
			||||||
                    except OSError:
 | 
					 | 
				
			||||||
                        if not limit_set:
 | 
					 | 
				
			||||||
                            raise
 | 
					 | 
				
			||||||
                    if limit_set:
 | 
					 | 
				
			||||||
                        # Close will attempt to flush the byte we wrote
 | 
					 | 
				
			||||||
                        # Restore limit first to avoid getting a spurious error
 | 
					 | 
				
			||||||
                        resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
					 | 
				
			||||||
                finally:
 | 
					 | 
				
			||||||
                    f.close()
 | 
					 | 
				
			||||||
            finally:
 | 
					 | 
				
			||||||
                if limit_set:
 | 
					                if limit_set:
 | 
				
			||||||
 | 
					                    # Close will attempt to flush the byte we wrote
 | 
				
			||||||
 | 
					                    # Restore limit first to avoid getting a spurious error
 | 
				
			||||||
                    resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
					                    resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
				
			||||||
                os_helper.unlink(os_helper.TESTFN)
 | 
					            finally:
 | 
				
			||||||
 | 
					                f.close()
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            if limit_set:
 | 
				
			||||||
 | 
					                resource.setrlimit(resource.RLIMIT_FSIZE, (cur, max))
 | 
				
			||||||
 | 
					            os_helper.unlink(os_helper.TESTFN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_fsize_toobig(self):
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
 | 
					                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
 | 
				
			||||||
 | 
					    def test_fsize_too_big(self):
 | 
				
			||||||
        # Be sure that setrlimit is checking for really large values
 | 
					        # Be sure that setrlimit is checking for really large values
 | 
				
			||||||
        too_big = 10**50
 | 
					        too_big = 10**50
 | 
				
			||||||
 | 
					        (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (too_big, max))
 | 
				
			||||||
        except AttributeError:
 | 
					        except (OverflowError, ValueError):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (max, too_big))
 | 
				
			||||||
 | 
					        except (OverflowError, ValueError):
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
 | 
					                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
 | 
				
			||||||
 | 
					    def test_fsize_not_too_big(self):
 | 
				
			||||||
 | 
					        (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
				
			||||||
 | 
					        self.addCleanup(resource.setrlimit, resource.RLIMIT_FSIZE, (cur, max))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def expected(cur):
 | 
				
			||||||
 | 
					            if resource.RLIM_INFINITY < 0:
 | 
				
			||||||
 | 
					                return [(cur, max), (resource.RLIM_INFINITY, max)]
 | 
				
			||||||
 | 
					            elif resource.RLIM_INFINITY < cur:
 | 
				
			||||||
 | 
					                return [(resource.RLIM_INFINITY, max)]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return [(cur, max)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resource.setrlimit(resource.RLIMIT_FSIZE, (2**31-5, max))
 | 
				
			||||||
 | 
					        self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**31-5, max))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**32, max))
 | 
				
			||||||
 | 
					        except OverflowError:
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**31, max))
 | 
				
			||||||
 | 
					            self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**31))
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**32-5, max))
 | 
				
			||||||
 | 
					            self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**32-5))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
 | 
					            self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**32))
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**31, max))
 | 
				
			||||||
 | 
					            self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**31, max))
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**32-5, max))
 | 
				
			||||||
 | 
					            self.assertEqual(resource.getrlimit(resource.RLIMIT_FSIZE), (2**32-5, max))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            resource.setrlimit(resource.RLIMIT_FSIZE, (2**63-5, max))
 | 
				
			||||||
 | 
					            self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**63-5))
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                resource.setrlimit(resource.RLIMIT_FSIZE, (too_big, max))
 | 
					                resource.setrlimit(resource.RLIMIT_FSIZE, (2**63, max))
 | 
				
			||||||
            except (OverflowError, ValueError):
 | 
					            except ValueError:
 | 
				
			||||||
                pass
 | 
					                # There is a hard limit on macOS.
 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                resource.setrlimit(resource.RLIMIT_FSIZE, (max, too_big))
 | 
					 | 
				
			||||||
            except (OverflowError, ValueError):
 | 
					 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**63))
 | 
				
			||||||
 | 
					                resource.setrlimit(resource.RLIMIT_FSIZE, (2**64-5, max))
 | 
				
			||||||
 | 
					                self.assertIn(resource.getrlimit(resource.RLIMIT_FSIZE), expected(2**64-5))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
 | 
					                     "setting RLIMIT_FSIZE is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_FSIZE'), 'requires resource.RLIMIT_FSIZE')
 | 
				
			||||||
 | 
					    def test_fsize_negative(self):
 | 
				
			||||||
 | 
					        (cur, max) = resource.getrlimit(resource.RLIMIT_FSIZE)
 | 
				
			||||||
 | 
					        for value in -5, -2**31, -2**32-5, -2**63, -2**64-5, -2**1000:
 | 
				
			||||||
 | 
					            with self.subTest(value=value):
 | 
				
			||||||
 | 
					                # This test assumes that the values don't map to RLIM_INFINITY,
 | 
				
			||||||
 | 
					                # though Posix doesn't guarantee it.
 | 
				
			||||||
 | 
					                self.assertNotEqual(value, resource.RLIM_INFINITY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertRaises(ValueError, resource.setrlimit, resource.RLIMIT_FSIZE, (value, max))
 | 
				
			||||||
 | 
					                self.assertRaises(ValueError, resource.setrlimit, resource.RLIMIT_FSIZE, (cur, value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage")
 | 
					    @unittest.skipUnless(hasattr(resource, "getrusage"), "needs getrusage")
 | 
				
			||||||
    def test_getrusage(self):
 | 
					    def test_getrusage(self):
 | 
				
			||||||
| 
						 | 
					@ -117,21 +182,18 @@ def test_getrusage(self):
 | 
				
			||||||
    # Issue 6083: Reference counting bug
 | 
					    # Issue 6083: Reference counting bug
 | 
				
			||||||
    @unittest.skipIf(sys.platform == "vxworks",
 | 
					    @unittest.skipIf(sys.platform == "vxworks",
 | 
				
			||||||
                     "setting RLIMIT_CPU is not supported on VxWorks")
 | 
					                     "setting RLIMIT_CPU is not supported on VxWorks")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(hasattr(resource, 'RLIMIT_CPU'), 'requires resource.RLIMIT_CPU')
 | 
				
			||||||
    def test_setrusage_refcount(self):
 | 
					    def test_setrusage_refcount(self):
 | 
				
			||||||
        try:
 | 
					        limits = resource.getrlimit(resource.RLIMIT_CPU)
 | 
				
			||||||
            limits = resource.getrlimit(resource.RLIMIT_CPU)
 | 
					        class BadSequence:
 | 
				
			||||||
        except AttributeError:
 | 
					            def __len__(self):
 | 
				
			||||||
            pass
 | 
					                return 2
 | 
				
			||||||
        else:
 | 
					            def __getitem__(self, key):
 | 
				
			||||||
            class BadSequence:
 | 
					                if key in (0, 1):
 | 
				
			||||||
                def __len__(self):
 | 
					                    return len(tuple(range(1000000)))
 | 
				
			||||||
                    return 2
 | 
					                raise IndexError
 | 
				
			||||||
                def __getitem__(self, key):
 | 
					 | 
				
			||||||
                    if key in (0, 1):
 | 
					 | 
				
			||||||
                        return len(tuple(range(1000000)))
 | 
					 | 
				
			||||||
                    raise IndexError
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
 | 
					        resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pagesize(self):
 | 
					    def test_pagesize(self):
 | 
				
			||||||
        pagesize = resource.getpagesize()
 | 
					        pagesize = resource.getpagesize()
 | 
				
			||||||
| 
						 | 
					@ -168,7 +230,8 @@ class BadSeq:
 | 
				
			||||||
            def __len__(self):
 | 
					            def __len__(self):
 | 
				
			||||||
                return 2
 | 
					                return 2
 | 
				
			||||||
            def __getitem__(self, key):
 | 
					            def __getitem__(self, key):
 | 
				
			||||||
                return limits[key] - 1  # new reference
 | 
					                lim = limits[key]
 | 
				
			||||||
 | 
					                return lim - 1 if lim > 0 else lim + sys.maxsize*2  # new reference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        limits = resource.getrlimit(resource.RLIMIT_AS)
 | 
					        limits = resource.getrlimit(resource.RLIMIT_AS)
 | 
				
			||||||
        self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),
 | 
					        self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					Return large limit values as positive integers instead of negative integers
 | 
				
			||||||
 | 
					in :func:`resource.getrlimit`. Accept large values and reject negative
 | 
				
			||||||
 | 
					values (except :data:`~resource.RLIM_INFINITY`) for limits in
 | 
				
			||||||
 | 
					:func:`resource.setrlimit`.
 | 
				
			||||||
							
								
								
									
										18
									
								
								Modules/clinic/resource.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								Modules/clinic/resource.c.h
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -2,6 +2,8 @@
 | 
				
			||||||
preserve
 | 
					preserve
 | 
				
			||||||
[clinic start generated code]*/
 | 
					[clinic start generated code]*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pycore_modsupport.h"    // _PyArg_CheckPositional()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(HAVE_GETRUSAGE)
 | 
					#if defined(HAVE_GETRUSAGE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyDoc_STRVAR(resource_getrusage__doc__,
 | 
					PyDoc_STRVAR(resource_getrusage__doc__,
 | 
				
			||||||
| 
						 | 
					@ -66,7 +68,7 @@ PyDoc_STRVAR(resource_setrlimit__doc__,
 | 
				
			||||||
"\n");
 | 
					"\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RESOURCE_SETRLIMIT_METHODDEF    \
 | 
					#define RESOURCE_SETRLIMIT_METHODDEF    \
 | 
				
			||||||
    {"setrlimit", (PyCFunction)(void(*)(void))resource_setrlimit, METH_FASTCALL, resource_setrlimit__doc__},
 | 
					    {"setrlimit", _PyCFunction_CAST(resource_setrlimit), METH_FASTCALL, resource_setrlimit__doc__},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
resource_setrlimit_impl(PyObject *module, int resource, PyObject *limits);
 | 
					resource_setrlimit_impl(PyObject *module, int resource, PyObject *limits);
 | 
				
			||||||
| 
						 | 
					@ -78,8 +80,7 @@ resource_setrlimit(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
 | 
				
			||||||
    int resource;
 | 
					    int resource;
 | 
				
			||||||
    PyObject *limits;
 | 
					    PyObject *limits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nargs != 2) {
 | 
					    if (!_PyArg_CheckPositional("setrlimit", nargs, 2, 2)) {
 | 
				
			||||||
        PyErr_Format(PyExc_TypeError, "setrlimit expected 2 arguments, got %zd", nargs);
 | 
					 | 
				
			||||||
        goto exit;
 | 
					        goto exit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    resource = PyLong_AsInt(args[0]);
 | 
					    resource = PyLong_AsInt(args[0]);
 | 
				
			||||||
| 
						 | 
					@ -101,7 +102,7 @@ PyDoc_STRVAR(resource_prlimit__doc__,
 | 
				
			||||||
"\n");
 | 
					"\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RESOURCE_PRLIMIT_METHODDEF    \
 | 
					#define RESOURCE_PRLIMIT_METHODDEF    \
 | 
				
			||||||
    {"prlimit", (PyCFunction)(void(*)(void))resource_prlimit, METH_FASTCALL, resource_prlimit__doc__},
 | 
					    {"prlimit", _PyCFunction_CAST(resource_prlimit), METH_FASTCALL, resource_prlimit__doc__},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
resource_prlimit_impl(PyObject *module, pid_t pid, int resource,
 | 
					resource_prlimit_impl(PyObject *module, pid_t pid, int resource,
 | 
				
			||||||
| 
						 | 
					@ -115,12 +116,7 @@ resource_prlimit(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
 | 
				
			||||||
    int resource;
 | 
					    int resource;
 | 
				
			||||||
    PyObject *limits = Py_None;
 | 
					    PyObject *limits = Py_None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (nargs < 2) {
 | 
					    if (!_PyArg_CheckPositional("prlimit", nargs, 2, 3)) {
 | 
				
			||||||
        PyErr_Format(PyExc_TypeError, "prlimit expected at least 2 arguments, got %zd", nargs);
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (nargs > 3) {
 | 
					 | 
				
			||||||
        PyErr_Format(PyExc_TypeError, "prlimit expected at most 3 arguments, got %zd", nargs);
 | 
					 | 
				
			||||||
        goto exit;
 | 
					        goto exit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pid = PyLong_AsPid(args[0]);
 | 
					    pid = PyLong_AsPid(args[0]);
 | 
				
			||||||
| 
						 | 
					@ -178,4 +174,4 @@ exit:
 | 
				
			||||||
#ifndef RESOURCE_PRLIMIT_METHODDEF
 | 
					#ifndef RESOURCE_PRLIMIT_METHODDEF
 | 
				
			||||||
    #define RESOURCE_PRLIMIT_METHODDEF
 | 
					    #define RESOURCE_PRLIMIT_METHODDEF
 | 
				
			||||||
#endif /* !defined(RESOURCE_PRLIMIT_METHODDEF) */
 | 
					#endif /* !defined(RESOURCE_PRLIMIT_METHODDEF) */
 | 
				
			||||||
/*[clinic end generated code: output=e45883ace510414a input=a9049054013a1b77]*/
 | 
					/*[clinic end generated code: output=8e905b2f5c35170e input=a9049054013a1b77]*/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,5 @@
 | 
				
			||||||
// Need limited C API version 3.13 for PySys_Audit()
 | 
					#ifndef Py_BUILD_CORE_BUILTIN
 | 
				
			||||||
#include "pyconfig.h"   // Py_GIL_DISABLED
 | 
					#  define Py_BUILD_CORE_MODULE 1
 | 
				
			||||||
#ifndef Py_GIL_DISABLED
 | 
					 | 
				
			||||||
#  define Py_LIMITED_API 0x030d0000
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Python.h"
 | 
					#include "Python.h"
 | 
				
			||||||
| 
						 | 
					@ -150,6 +148,35 @@ resource_getrusage_impl(PyObject *module, int who)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					py2rlim(PyObject *obj, rlim_t *out)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    obj = PyNumber_Index(obj);
 | 
				
			||||||
 | 
					    if (obj == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int neg = PyLong_IsNegative(obj);
 | 
				
			||||||
 | 
					    assert(neg >= 0);
 | 
				
			||||||
 | 
					    Py_ssize_t bytes = PyLong_AsNativeBytes(obj, out, sizeof(*out),
 | 
				
			||||||
 | 
					                                            Py_ASNATIVEBYTES_NATIVE_ENDIAN |
 | 
				
			||||||
 | 
					                                            Py_ASNATIVEBYTES_UNSIGNED_BUFFER);
 | 
				
			||||||
 | 
					    Py_DECREF(obj);
 | 
				
			||||||
 | 
					    if (bytes < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (neg && (*out != RLIM_INFINITY || bytes > (Py_ssize_t)sizeof(*out))) {
 | 
				
			||||||
 | 
					        PyErr_SetString(PyExc_ValueError,
 | 
				
			||||||
 | 
					            "Cannot convert negative int");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (bytes > (Py_ssize_t)sizeof(*out)) {
 | 
				
			||||||
 | 
					        PyErr_SetString(PyExc_OverflowError,
 | 
				
			||||||
 | 
					            "Python int too large to convert to C rlim_t");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
py2rlimit(PyObject *limits, struct rlimit *rl_out)
 | 
					py2rlimit(PyObject *limits, struct rlimit *rl_out)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -166,26 +193,13 @@ py2rlimit(PyObject *limits, struct rlimit *rl_out)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    curobj = PyTuple_GetItem(limits, 0);  // borrowed
 | 
					    curobj = PyTuple_GetItem(limits, 0);  // borrowed
 | 
				
			||||||
    maxobj = PyTuple_GetItem(limits, 1);  // borrowed
 | 
					    maxobj = PyTuple_GetItem(limits, 1);  // borrowed
 | 
				
			||||||
#if !defined(HAVE_LARGEFILE_SUPPORT)
 | 
					    if (py2rlim(curobj, &rl_out->rlim_cur) < 0 ||
 | 
				
			||||||
    rl_out->rlim_cur = PyLong_AsLong(curobj);
 | 
					        py2rlim(maxobj, &rl_out->rlim_max) < 0)
 | 
				
			||||||
    if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
 | 
					    {
 | 
				
			||||||
        goto error;
 | 
					        goto error;
 | 
				
			||||||
    rl_out->rlim_max = PyLong_AsLong(maxobj);
 | 
					    }
 | 
				
			||||||
    if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    /* The limits are probably bigger than a long */
 | 
					 | 
				
			||||||
    rl_out->rlim_cur = PyLong_AsLongLong(curobj);
 | 
					 | 
				
			||||||
    if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    rl_out->rlim_max = PyLong_AsLongLong(maxobj);
 | 
					 | 
				
			||||||
    if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Py_DECREF(limits);
 | 
					    Py_DECREF(limits);
 | 
				
			||||||
    rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
 | 
					 | 
				
			||||||
    rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
| 
						 | 
					@ -193,15 +207,24 @@ py2rlimit(PyObject *limits, struct rlimit *rl_out)
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject*
 | 
				
			||||||
 | 
					rlim2py(rlim_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (value == RLIM_INFINITY) {
 | 
				
			||||||
 | 
					        return PyLong_FromNativeBytes(&value, sizeof(value), -1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return PyLong_FromUnsignedNativeBytes(&value, sizeof(value), -1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject*
 | 
					static PyObject*
 | 
				
			||||||
rlimit2py(struct rlimit rl)
 | 
					rlimit2py(struct rlimit rl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (sizeof(rl.rlim_cur) > sizeof(long)) {
 | 
					    PyObject *cur = rlim2py(rl.rlim_cur);
 | 
				
			||||||
        return Py_BuildValue("LL",
 | 
					    if (cur == NULL) {
 | 
				
			||||||
                             (long long) rl.rlim_cur,
 | 
					        return NULL;
 | 
				
			||||||
                             (long long) rl.rlim_max);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
 | 
					    PyObject *max = rlim2py(rl.rlim_max);
 | 
				
			||||||
 | 
					    return Py_BuildValue("NN", cur, max);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*[clinic input]
 | 
					/*[clinic input]
 | 
				
			||||||
| 
						 | 
					@ -495,14 +518,7 @@ resource_exec(PyObject *module)
 | 
				
			||||||
    ADD_INT(module, RLIMIT_KQUEUES);
 | 
					    ADD_INT(module, RLIMIT_KQUEUES);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PyObject *v;
 | 
					    if (PyModule_Add(module, "RLIM_INFINITY", rlim2py(RLIM_INFINITY)) < 0) {
 | 
				
			||||||
    if (sizeof(RLIM_INFINITY) > sizeof(long)) {
 | 
					 | 
				
			||||||
        v = PyLong_FromLongLong((long long) RLIM_INFINITY);
 | 
					 | 
				
			||||||
    } else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        v = PyLong_FromLong((long) RLIM_INFINITY);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (PyModule_Add(module, "RLIM_INFINITY", v) < 0) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue