Skip to content

Commit 7505f2b

Browse files
authored
Merge branch 'main' into multi_inputs
2 parents 4ffd20a + 830f04b commit 7505f2b

File tree

16 files changed

+192
-48
lines changed

16 files changed

+192
-48
lines changed

Lib/gzip.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55

66
# based on Andrew Kuchling's minigzip.py distributed with the zlib module
77

8-
import struct, sys, time, os
9-
import zlib
8+
import _compression
109
import builtins
1110
import io
12-
import _compression
11+
import os
12+
import struct
13+
import sys
14+
import time
15+
import weakref
16+
import zlib
1317

1418
__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
1519

@@ -125,10 +129,13 @@ class BadGzipFile(OSError):
125129
class _WriteBufferStream(io.RawIOBase):
126130
"""Minimal object to pass WriteBuffer flushes into GzipFile"""
127131
def __init__(self, gzip_file):
128-
self.gzip_file = gzip_file
132+
self.gzip_file = weakref.ref(gzip_file)
129133

130134
def write(self, data):
131-
return self.gzip_file._write_raw(data)
135+
gzip_file = self.gzip_file()
136+
if gzip_file is None:
137+
raise RuntimeError("lost gzip_file")
138+
return gzip_file._write_raw(data)
132139

133140
def seekable(self):
134141
return False

Lib/test/test_gettext.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import base64
33
import gettext
44
import unittest
5+
import unittest.mock
56
from functools import partial
67

78
from test import support
@@ -691,6 +692,32 @@ def test_cache(self):
691692
self.assertEqual(t.__class__, DummyGNUTranslations)
692693

693694

695+
class ExpandLangTestCase(unittest.TestCase):
696+
def test_expand_lang(self):
697+
# Test all combinations of territory, charset and
698+
# modifier (locale extension)
699+
locales = {
700+
'cs': ['cs'],
701+
'cs_CZ': ['cs_CZ', 'cs'],
702+
'cs.ISO8859-2': ['cs.ISO8859-2', 'cs'],
703+
'cs@euro': ['cs@euro', 'cs'],
704+
'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'cs_CZ', 'cs.ISO8859-2',
705+
'cs'],
706+
'cs_CZ@euro': ['cs_CZ@euro', 'cs@euro', 'cs_CZ', 'cs'],
707+
'cs.ISO8859-2@euro': ['cs.ISO8859-2@euro', 'cs@euro',
708+
'cs.ISO8859-2', 'cs'],
709+
'cs_CZ.ISO8859-2@euro': ['cs_CZ.ISO8859-2@euro', 'cs_CZ@euro',
710+
'cs.ISO8859-2@euro', 'cs@euro',
711+
'cs_CZ.ISO8859-2', 'cs_CZ',
712+
'cs.ISO8859-2', 'cs'],
713+
}
714+
for locale, expanded in locales.items():
715+
with self.subTest(locale=locale):
716+
with unittest.mock.patch("locale.normalize",
717+
return_value=locale):
718+
self.assertEqual(gettext._expand_lang(locale), expanded)
719+
720+
694721
class MiscTestCase(unittest.TestCase):
695722
def test__all__(self):
696723
support.check__all__(self, gettext,

Lib/test/test_gzip.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
import array
55
import functools
6+
import gc
67
import io
78
import os
89
import struct
910
import sys
1011
import unittest
1112
from subprocess import PIPE, Popen
13+
from test.support import catch_unraisable_exception
1214
from test.support import import_helper
1315
from test.support import os_helper
1416
from test.support import _4G, bigmemtest, requires_subprocess
@@ -859,6 +861,17 @@ def test_write_seek_write(self):
859861
self.assertEqual(gzip.decompress(data), message * 2)
860862

861863

864+
def test_refloop_unraisable(self):
865+
# Ensure a GzipFile referring to a temporary fileobj deletes cleanly.
866+
# Previously an unraisable exception would occur on close because the
867+
# fileobj would be closed before the GzipFile as the result of a
868+
# reference loop. See issue gh-129726
869+
with catch_unraisable_exception() as cm:
870+
gzip.GzipFile(fileobj=io.BytesIO(), mode="w")
871+
gc.collect()
872+
self.assertIsNone(cm.unraisable)
873+
874+
862875
class TestOpen(BaseTest):
863876
def test_binary_modes(self):
864877
uncompressed = data1 * 50

Makefile.pre.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2149,7 +2149,7 @@ testuniversal: all
21492149
# a full Xcode install that has an iPhone SE (3rd edition) simulator available.
21502150
# This must be run *after* a `make install` has completed the build. The
21512151
# `--with-framework-name` argument *cannot* be used when configuring the build.
2152-
XCFOLDER:=iOSTestbed.$(MULTIARCH).$(shell date +%s)
2152+
XCFOLDER:=iOSTestbed.$(MULTIARCH).$(shell date +%s).$$PPID
21532153
.PHONY: testios
21542154
testios:
21552155
@if test "$(MACHDEP)" != "ios"; then \
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :class:`gzip.GzipFile` raising an unraisable exception during garbage
2+
collection when referring to a temporary object by breaking the reference
3+
loop with :mod:`weakref`.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Multiple iOS testbed runners can now be started at the same time without
2+
introducing an ambiguity over simulator ownership.

Modules/timemodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ time_clockid_converter(PyObject *obj, clockid_t *p)
187187
{
188188
#ifdef _AIX
189189
long long clk_id = PyLong_AsLongLong(obj);
190+
#elif defined(__DragonFly__)
191+
long clk_id = PyLong_AsLong(obj);
190192
#else
191193
int clk_id = PyLong_AsInt(obj);
192194
#endif

Objects/codeobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <stdbool.h>
2-
31
#include "Python.h"
42
#include "opcode.h"
53

@@ -20,6 +18,8 @@
2018
#include "pycore_uniqueid.h" // _PyObject_AssignUniqueId()
2119
#include "clinic/codeobject.c.h"
2220

21+
#include <stdbool.h>
22+
2323
#define INITIAL_SPECIALIZED_CODE_SIZE 16
2424

2525
static const char *

Objects/frameobject.c

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define OFF(x) offsetof(PyFrameObject, x)
2929

3030

31-
// Returns borrowed reference or NULL
31+
// Returns new reference or NULL
3232
static PyObject *
3333
framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
3434
{
@@ -57,7 +57,10 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
5757
}
5858

5959
if (cell != NULL) {
60-
value = PyCell_GET(cell);
60+
value = PyCell_GetRef((PyCellObject *)cell);
61+
}
62+
else {
63+
Py_XINCREF(value);
6164
}
6265

6366
if (value == NULL) {
@@ -67,24 +70,42 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
6770
return value;
6871
}
6972

73+
static bool
74+
framelocalsproxy_hasval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
75+
{
76+
PyObject *value = framelocalsproxy_getval(frame, co, i);
77+
if (value == NULL) {
78+
return false;
79+
}
80+
Py_DECREF(value);
81+
return true;
82+
}
83+
7084
static int
71-
framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
85+
framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyObject **value_ptr)
7286
{
7387
/*
7488
* Returns -2 (!) if an error occurred; exception will be set.
7589
* Returns the fast locals index of the key on success:
7690
* - if read == true, returns the index if the value is not NULL
7791
* - if read == false, returns the index if the value is not hidden
7892
* Otherwise returns -1.
93+
*
94+
* If read == true and value_ptr is not NULL, *value_ptr is set to
95+
* the value of the key if it is found (with a new reference).
7996
*/
8097

98+
// value_ptr should only be given if we are reading the value
99+
assert(read || value_ptr == NULL);
100+
81101
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
82102

83103
// Ensure that the key is hashable.
84104
Py_hash_t key_hash = PyObject_Hash(key);
85105
if (key_hash == -1) {
86106
return -2;
87107
}
108+
88109
bool found = false;
89110

90111
// We do 2 loops here because it's highly possible the key is interned
@@ -93,7 +114,14 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
93114
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
94115
if (name == key) {
95116
if (read) {
96-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
117+
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
118+
if (value != NULL) {
119+
if (value_ptr != NULL) {
120+
*value_ptr = value;
121+
}
122+
else {
123+
Py_DECREF(value);
124+
}
97125
return i;
98126
}
99127
} else {
@@ -124,7 +152,14 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
124152
}
125153
if (same) {
126154
if (read) {
127-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
155+
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
156+
if (value != NULL) {
157+
if (value_ptr != NULL) {
158+
*value_ptr = value;
159+
}
160+
else {
161+
Py_DECREF(value);
162+
}
128163
return i;
129164
}
130165
} else {
@@ -142,25 +177,27 @@ static PyObject *
142177
framelocalsproxy_getitem(PyObject *self, PyObject *key)
143178
{
144179
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
145-
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
180+
PyObject *value = NULL;
146181

147-
int i = framelocalsproxy_getkeyindex(frame, key, true);
182+
int i = framelocalsproxy_getkeyindex(frame, key, true, &value);
148183
if (i == -2) {
149184
return NULL;
150185
}
151186
if (i >= 0) {
152-
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
153187
assert(value != NULL);
154-
return Py_NewRef(value);
188+
return value;
155189
}
190+
assert(value == NULL);
156191

157192
// Okay not in the fast locals, try extra locals
158193

159194
PyObject *extra = frame->f_extra_locals;
160195
if (extra != NULL) {
161-
PyObject *value = PyDict_GetItem(extra, key);
196+
if (PyDict_GetItemRef(extra, key, &value) < 0) {
197+
return NULL;
198+
}
162199
if (value != NULL) {
163-
return Py_NewRef(value);
200+
return value;
164201
}
165202
}
166203

@@ -176,7 +213,7 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
176213
_PyStackRef *fast = _PyFrame_GetLocalsArray(frame->f_frame);
177214
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
178215

179-
int i = framelocalsproxy_getkeyindex(frame, key, false);
216+
int i = framelocalsproxy_getkeyindex(frame, key, false, NULL);
180217
if (i == -2) {
181218
return -1;
182219
}
@@ -297,8 +334,7 @@ framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored))
297334
}
298335

299336
for (int i = 0; i < co->co_nlocalsplus; i++) {
300-
PyObject *val = framelocalsproxy_getval(frame->f_frame, co, i);
301-
if (val) {
337+
if (framelocalsproxy_hasval(frame->f_frame, co, i)) {
302338
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
303339
if (PyList_Append(names, name) < 0) {
304340
Py_DECREF(names);
@@ -511,8 +547,10 @@ framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored))
511547
if (value) {
512548
if (PyList_Append(values, value) < 0) {
513549
Py_DECREF(values);
550+
Py_DECREF(value);
514551
return NULL;
515552
}
553+
Py_DECREF(value);
516554
}
517555
}
518556

@@ -550,16 +588,19 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored))
550588
PyObject *pair = PyTuple_Pack(2, name, value);
551589
if (pair == NULL) {
552590
Py_DECREF(items);
591+
Py_DECREF(value);
553592
return NULL;
554593
}
555594

556595
if (PyList_Append(items, pair) < 0) {
557596
Py_DECREF(items);
558597
Py_DECREF(pair);
598+
Py_DECREF(value);
559599
return NULL;
560600
}
561601

562602
Py_DECREF(pair);
603+
Py_DECREF(value);
563604
}
564605
}
565606

@@ -601,7 +642,7 @@ framelocalsproxy_length(PyObject *self)
601642
}
602643

603644
for (int i = 0; i < co->co_nlocalsplus; i++) {
604-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
645+
if (framelocalsproxy_hasval(frame->f_frame, co, i)) {
605646
size++;
606647
}
607648
}
@@ -613,7 +654,7 @@ framelocalsproxy_contains(PyObject *self, PyObject *key)
613654
{
614655
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
615656

616-
int i = framelocalsproxy_getkeyindex(frame, key, true);
657+
int i = framelocalsproxy_getkeyindex(frame, key, true, NULL);
617658
if (i == -2) {
618659
return -1;
619660
}
@@ -724,7 +765,7 @@ framelocalsproxy_pop(PyObject* self, PyObject *const *args, Py_ssize_t nargs)
724765

725766
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
726767

727-
int i = framelocalsproxy_getkeyindex(frame, key, false);
768+
int i = framelocalsproxy_getkeyindex(frame, key, false, NULL);
728769
if (i == -2) {
729770
return NULL;
730771
}
@@ -2066,9 +2107,7 @@ _PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame)
20662107
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
20672108

20682109
if (kind & CO_FAST_HIDDEN) {
2069-
PyObject* value = framelocalsproxy_getval(frame, co, i);
2070-
2071-
if (value != NULL) {
2110+
if (framelocalsproxy_hasval(frame, co, i)) {
20722111
return true;
20732112
}
20742113
}

Python/assemble.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <stdbool.h>
2-
31
#include "Python.h"
42
#include "pycore_code.h" // write_location_entry_start()
53
#include "pycore_compile.h"
@@ -8,6 +6,7 @@
86
#include "pycore_opcode_metadata.h" // is_pseudo_target, _PyOpcode_Caches
97
#include "pycore_symtable.h" // _Py_SourceLocation
108

9+
#include <stdbool.h>
1110

1211
#define DEFAULT_CODE_SIZE 128
1312
#define DEFAULT_LNOTAB_SIZE 16

0 commit comments

Comments
 (0)