Skip to content
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
91 changes: 4 additions & 87 deletions Include/internal/pycore_bytesobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,93 +60,7 @@ PyAPI_FUNC(void)
_PyBytes_Repeat(char* dest, Py_ssize_t len_dest,
const char* src, Py_ssize_t len_src);

/* --- _PyBytesWriter ----------------------------------------------------- */

/* The _PyBytesWriter structure is big: it contains an embedded "stack buffer".
A _PyBytesWriter variable must be declared at the end of variables in a
function to optimize the memory allocation on the stack. */
typedef struct {
/* bytes, bytearray or NULL (when the small buffer is used) */
PyObject *buffer;

/* Number of allocated size. */
Py_ssize_t allocated;

/* Minimum number of allocated bytes,
incremented by _PyBytesWriter_Prepare() */
Py_ssize_t min_size;

/* If non-zero, use a bytearray instead of a bytes object for buffer. */
int use_bytearray;

/* If non-zero, overallocate the buffer (default: 0).
This flag must be zero if use_bytearray is non-zero. */
int overallocate;

/* Stack buffer */
int use_small_buffer;
char small_buffer[512];
} _PyBytesWriter;

/* Initialize a bytes writer

By default, the overallocation is disabled. Set the overallocate attribute
to control the allocation of the buffer.

Export _PyBytesWriter API for '_pickle' shared extension. */
PyAPI_FUNC(void) _PyBytesWriter_Init(_PyBytesWriter *writer);

/* Get the buffer content and reset the writer.
Return a bytes object, or a bytearray object if use_bytearray is non-zero.
Raise an exception and return NULL on error. */
PyAPI_FUNC(PyObject *) _PyBytesWriter_Finish(_PyBytesWriter *writer,
void *str);

/* Deallocate memory of a writer (clear its internal buffer). */
PyAPI_FUNC(void) _PyBytesWriter_Dealloc(_PyBytesWriter *writer);

/* Allocate the buffer to write size bytes.
Return the pointer to the beginning of buffer data.
Raise an exception and return NULL on error. */
PyAPI_FUNC(void*) _PyBytesWriter_Alloc(_PyBytesWriter *writer,
Py_ssize_t size);

/* Ensure that the buffer is large enough to write *size* bytes.
Add size to the writer minimum size (min_size attribute).

str is the current pointer inside the buffer.
Return the updated current pointer inside the buffer.
Raise an exception and return NULL on error. */
PyAPI_FUNC(void*) _PyBytesWriter_Prepare(_PyBytesWriter *writer,
void *str,
Py_ssize_t size);

/* Resize the buffer to make it larger.
The new buffer may be larger than size bytes because of overallocation.
Return the updated current pointer inside the buffer.
Raise an exception and return NULL on error.

Note: size must be greater than the number of allocated bytes in the writer.

This function doesn't use the writer minimum size (min_size attribute).

See also _PyBytesWriter_Prepare().
*/
PyAPI_FUNC(void*) _PyBytesWriter_Resize(_PyBytesWriter *writer,
void *str,
Py_ssize_t size);

/* Write bytes.
Raise an exception and return NULL on error. */
PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer,
void *str,
const void *bytes,
Py_ssize_t size);

// Export for '_testcapi' shared extension.
PyAPI_FUNC(PyBytesWriter*) _PyBytesWriter_CreateByteArray(
Py_ssize_t size);

/* --- PyBytesWriter ------------------------------------------------------ */

struct PyBytesWriter {
char small_buffer[256];
Expand All @@ -156,6 +70,9 @@ struct PyBytesWriter {
int overallocate;
};

// Export for '_testcapi' shared extension
PyAPI_FUNC(PyBytesWriter*) _PyBytesWriter_CreateByteArray(Py_ssize_t size);

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 5 additions & 1 deletion Lib/test/libregrtest/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,11 @@ def _parse_args(args, **kwargs):
if ns.python is None:
ns.rerun = True
ns.print_slow = True
ns.verbose3 = True
if not ns.verbose:
ns.verbose3 = True
else:
# --verbose has the priority over --verbose3
pass
else:
ns._add_python_opts = False

Expand Down
12 changes: 4 additions & 8 deletions Lib/test/test_c_locale_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Set the list of ways we expect to be able to ask for the "C" locale.
# 'invalid.ascii' is an invalid LOCALE name and so should get turned in to the
# default locale, which is traditionally C.
EXPECTED_C_LOCALE_EQUIVALENTS = ["C", "invalid.ascii"]
EXPECTED_C_LOCALE_EQUIVALENTS = ["C", "POSIX", "invalid.ascii"]

# Set our expectation for the default encoding used in the C locale
# for the filesystem encoding and the standard streams
Expand Down Expand Up @@ -55,11 +55,6 @@
# VxWorks defaults to using UTF-8 for all system interfaces
EXPECTED_C_LOCALE_STREAM_ENCODING = "utf-8"
EXPECTED_C_LOCALE_FS_ENCODING = "utf-8"
if sys.platform.startswith("linux"):
# Linux recognizes POSIX as a synonym for C. Python will always coerce
# if the locale is set to POSIX, but not all platforms will use the
# C locale encodings if POSIX is set, so we'll only test it on linux.
EXPECTED_C_LOCALE_EQUIVALENTS.append("POSIX")

# Note that the above expectations are still wrong in some cases, such as:
# * Windows when PYTHONLEGACYWINDOWSFSENCODING is set
Expand Down Expand Up @@ -467,8 +462,9 @@ def test_PYTHONCOERCECLOCALE_set_to_one(self):
loc = locale.setlocale(locale.LC_CTYPE, "")
except locale.Error as e:
self.skipTest(str(e))
if loc == "C":
self.skipTest("test requires LC_CTYPE locale different than C")
if loc in ("C", "POSIX"):
self.skipTest("test requires LC_CTYPE locale different "
"than C and POSIX")
if loc in TARGET_LOCALES :
self.skipTest("coerced LC_CTYPE locale: %s" % loc)

Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import _testlimitedcapi
except ImportError:
_testlimitedcapi = None
try:
import _testinternalcapi
except ImportError:
_testinternalcapi = None
import struct
import collections
import itertools
Expand Down Expand Up @@ -1037,6 +1041,18 @@ def test_unexpected_keyword_suggestion_via_getargs(self):
@cpython_only
class TestRecursion(unittest.TestCase):

def test_margin_is_sufficient(self):

def get_sp():
return _testinternalcapi.get_stack_pointer()

this_sp = _testinternalcapi.get_stack_pointer()
lower_sp = _testcapi.pyobject_vectorcall(get_sp, (), ())
self.assertLess(lower_sp, this_sp)
# Add an (arbitrary) extra 25% for safety
safe_margin = (this_sp - lower_sp) * 5 / 4
self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())

@skip_on_s390x
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
@skip_if_sanitizer("requires deep stack", thread=True)
Expand Down
7 changes: 6 additions & 1 deletion Lib/test/test_interpreters/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,12 @@ def test():
error = proc.stderr.read()
self.assertIn(b"KeyboardInterrupt", error)
retcode = proc.wait()
self.assertEqual(retcode, 0)
# Sometimes we send the SIGINT after the subthread yields the GIL to
# the main thread, which results in the main thread getting the
# KeyboardInterrupt before finalization is reached. There's not
# any great way to protect against that, so we just allow a -2
# return code as well.
self.assertIn(retcode, (0, -signal.SIGINT))


class TestInterpreterIsRunning(TestBase):
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test_pydoc/test_pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,6 @@ def test_apropos_with_unreadable_dir(self):
self.assertEqual(out.getvalue(), '')
self.assertEqual(err.getvalue(), '')

@os_helper.skip_unless_working_chmod
def test_apropos_empty_doc(self):
pkgdir = os.path.join(TESTFN, 'walkpkg')
os.mkdir(pkgdir)
Expand Down
13 changes: 11 additions & 2 deletions Lib/test/test_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,8 @@ def create_regrtest(self, args):

return regrtest

def check_ci_mode(self, args, use_resources, *, rerun=True, randomize=True):
def check_ci_mode(self, args, use_resources,
*, rerun=True, randomize=True, output_on_failure=True):
regrtest = self.create_regrtest(args)
self.assertEqual(regrtest.num_workers, -1)
self.assertEqual(regrtest.want_rerun, rerun)
Expand All @@ -457,7 +458,7 @@ def check_ci_mode(self, args, use_resources, *, rerun=True, randomize=True):
self.assertIsInstance(regrtest.random_seed, int)
self.assertTrue(regrtest.fail_env_changed)
self.assertTrue(regrtest.print_slowest)
self.assertTrue(regrtest.output_on_failure)
self.assertEqual(regrtest.output_on_failure, output_on_failure)
self.assertEqual(sorted(regrtest.use_resources), sorted(use_resources))
return regrtest

Expand All @@ -484,6 +485,14 @@ def test_fast_ci_resource(self):
use_resources.remove('network')
self.check_ci_mode(args, use_resources)

def test_fast_ci_verbose(self):
args = ['--fast-ci', '--verbose']
use_resources = sorted(cmdline.ALL_RESOURCES)
use_resources.remove('cpu')
regrtest = self.check_ci_mode(args, use_resources,
output_on_failure=False)
self.assertEqual(regrtest.verbose, True)

def test_slow_ci(self):
args = ['--slow-ci']
use_resources = sorted(cmdline.ALL_RESOURCES)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:pep:`538`: Coerce the POSIX locale to a UTF-8 based locale. Patch by Victor
Stinner.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix possible crash in :func:`locale.strxfrm` due to a platform bug on
macOS.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix regrtest ``--fast-ci --verbose``: don't ignore the ``--verbose`` option
anymore. Patch by Victor Stinner.
4 changes: 3 additions & 1 deletion Modules/_localemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,9 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str)

/* assume no change in size, first */
n1 = n1 + 1;
buf = PyMem_New(wchar_t, n1);
/* Yet another +1 is needed to work around a platform bug in wcsxfrm()
* on macOS. See gh-130567. */
buf = PyMem_New(wchar_t, n1+1);
if (!buf) {
PyErr_NoMemory();
goto exit;
Expand Down
14 changes: 14 additions & 0 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ get_c_recursion_remaining(PyObject *self, PyObject *Py_UNUSED(args))
return PyLong_FromLong(remaining);
}

static PyObject*
get_stack_pointer(PyObject *self, PyObject *Py_UNUSED(args))
{
uintptr_t here_addr = _Py_get_machine_stack_pointer();
return PyLong_FromSize_t(here_addr);
}

static PyObject*
get_stack_margin(PyObject *self, PyObject *Py_UNUSED(args))
{
return PyLong_FromSize_t(_PyOS_STACK_MARGIN_BYTES);
}

static PyObject*
test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
Expand Down Expand Up @@ -2390,6 +2402,8 @@ static PyMethodDef module_functions[] = {
{"get_configs", get_configs, METH_NOARGS},
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
{"get_c_recursion_remaining", get_c_recursion_remaining, METH_NOARGS},
{"get_stack_pointer", get_stack_pointer, METH_NOARGS},
{"get_stack_margin", get_stack_margin, METH_NOARGS},
{"test_bswap", test_bswap, METH_NOARGS},
{"test_popcount", test_popcount, METH_NOARGS},
{"test_bit_length", test_bit_length, METH_NOARGS},
Expand Down
Loading
Loading