From 86a9a20d91dbbe13a03fe87a7dcf0e39f2e6136e Mon Sep 17 00:00:00 2001 From: Robert Kuska Date: Dec 16 2014 12:41:03 +0000 Subject: Backport patches from other pythons versions --- diff --git a/00170-gc-assertions.patch b/00170-gc-assertions.patch new file mode 100644 index 0000000..1144cc2 --- /dev/null +++ b/00170-gc-assertions.patch @@ -0,0 +1,325 @@ +Index: Include/object.h +=================================================================== +--- Include/object.h (revision 87911) ++++ Include/object.h (working copy) +@@ -914,6 +914,49 @@ + _PyObject_DebugTypeStats(FILE *out); + #endif /* ifndef Py_LIMITED_API */ + ++/* ++ Define a pair of assertion macros. ++ ++ These work like the regular C assert(), in that they will abort the ++ process with a message on stderr if the given condition fails to hold, ++ but compile away to nothing if NDEBUG is defined. ++ ++ However, before aborting, Python will also try to call _PyObject_Dump() on ++ the given object. This may be of use when investigating bugs in which a ++ particular object is corrupt (e.g. buggy a tp_visit method in an extension ++ module breaking the garbage collector), to help locate the broken objects. ++ ++ The WITH_MSG variant allows you to supply an additional message that Python ++ will attempt to print to stderr, after the object dump. ++*/ ++#ifdef NDEBUG ++/* No debugging: compile away the assertions: */ ++#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0) ++#else ++/* With debugging: generate checks: */ ++#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \ ++ ((expr) \ ++ ? (void)(0) \ ++ : _PyObject_AssertFailed((obj), \ ++ (msg), \ ++ (__STRING(expr)), \ ++ (__FILE__), \ ++ (__LINE__), \ ++ (__PRETTY_FUNCTION__))) ++#endif ++ ++#define PyObject_ASSERT(obj, expr) \ ++ PyObject_ASSERT_WITH_MSG(obj, expr, NULL) ++ ++/* ++ Declare and define the entrypoint even when NDEBUG is defined, to avoid ++ causing compiler/linker errors when building extensions without NDEBUG ++ against a Python built with NDEBUG defined ++*/ ++PyAPI_FUNC(void) _PyObject_AssertFailed(PyObject *, const char *, ++ const char *, const char *, int, ++ const char *); ++ + #ifdef __cplusplus + } + #endif +Index: Objects/object.c +=================================================================== +--- Objects/object.c (revision 87911) ++++ Objects/object.c (working copy) +@@ -1899,6 +1899,35 @@ + } + } + ++PyAPI_FUNC(void) ++_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr, ++ const char *file, int line, const char *function) ++{ ++ fprintf(stderr, ++ "%s:%d: %s: Assertion \"%s\" failed.\n", ++ file, line, function, expr); ++ if (msg) { ++ fprintf(stderr, "%s\n", msg); ++ } ++ ++ fflush(stderr); ++ ++ if (obj) { ++ /* This might succeed or fail, but we're about to abort, so at least ++ try to provide any extra info we can: */ ++ _PyObject_Dump(obj); ++ } ++ else { ++ fprintf(stderr, "NULL object\n"); ++ } ++ ++ fflush(stdout); ++ fflush(stderr); ++ ++ /* Terminate the process: */ ++ abort(); ++} ++ + #ifndef Py_TRACE_REFS + /* For Py_LIMITED_API, we need an out-of-line version of _Py_Dealloc. + Define this here, so we can undefine the macro. */ +Index: Lib/test/test_gc.py +=================================================================== +--- Lib/test/test_gc.py (revision 87911) ++++ Lib/test/test_gc.py (working copy) +@@ -1,6 +1,6 @@ + import unittest + from test.support import (verbose, refcount_test, run_unittest, +- strip_python_stderr, cpython_only) ++ strip_python_stderr, cpython_only, import_module) + from test.script_helper import assert_python_ok, make_script, temp_dir + + import sys +@@ -512,6 +512,48 @@ + self.assertEqual(len(gc.garbage), 0) + + ++ def test_refcount_errors(self): ++ self.preclean() ++ # Verify the "handling" of objects with broken refcounts ++ import_module("ctypes") #skip if not supported ++ ++ import subprocess ++ code = '''if 1: ++ a = [] ++ b = [a] ++ ++ # Simulate the refcount of "a" being too low (compared to the ++ # references held on it by live data), but keeping it above zero ++ # (to avoid deallocating it): ++ import ctypes ++ ctypes.pythonapi.Py_DecRef(ctypes.py_object(a)) ++ ++ # The garbage collector should now have a fatal error when it reaches ++ # the broken object: ++ import gc ++ gc.collect() ++ ''' ++ p = subprocess.Popen([sys.executable, "-c", code], ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ stdout, stderr = p.communicate() ++ p.stdout.close() ++ p.stderr.close() ++ # Verify that stderr has a useful error message: ++ self.assertRegex(stderr, ++ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "\(\(gc\)->gc.gc_refs >> \(1\)\) != 0" failed.') ++ self.assertRegex(stderr, ++ b'refcount was too small') ++ self.assertRegex(stderr, ++ b'object : \[\]') ++ self.assertRegex(stderr, ++ b'type : list') ++ self.assertRegex(stderr, ++ b'refcount: 1') ++ self.assertRegex(stderr, ++ b'address : 0x[0-9a-f]+') ++ ++ + class GCTogglingTests(unittest.TestCase): + def setUp(self): + gc.enable() +diff -up Modules/gcmodule.c.orig2 Modules/gcmodule.c +--- Modules/gcmodule.c.orig2 2014-12-08 10:54:14.251742911 +0100 ++++ Modules/gcmodule.c 2014-12-08 10:52:45.674771917 +0100 +@@ -341,7 +341,8 @@ update_refs(PyGC_Head *containers) + { + PyGC_Head *gc = containers->gc.gc_next; + for (; gc != containers; gc = gc->gc.gc_next) { +- assert(_PyGCHead_REFS(gc) == GC_REACHABLE); ++ PyObject_ASSERT(FROM_GC(gc), ++ _PyGCHead_REFS(gc) == GC_REACHABLE); + _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); + /* Python's cyclic gc should never see an incoming refcount + * of 0: if something decref'ed to 0, it should have been +@@ -361,7 +362,8 @@ update_refs(PyGC_Head *containers) + * so serious that maybe this should be a release-build + * check instead of an assert? + */ +- assert(_PyGCHead_REFS(gc) != 0); ++ PyObject_ASSERT(FROM_GC(gc), ++ _PyGCHead_REFS(gc) != 0); + } + } + +@@ -376,7 +378,9 @@ visit_decref(PyObject *op, void *data) + * generation being collected, which can be recognized + * because only they have positive gc_refs. + */ +- assert(_PyGCHead_REFS(gc) != 0); /* else refcount was too small */ ++ PyObject_ASSERT_WITH_MSG(FROM_GC(gc), ++ _PyGCHead_REFS(gc) != 0, ++ "refcount was too small"); /* else refcount was too small */ + if (_PyGCHead_REFS(gc) > 0) + _PyGCHead_DECREF(gc); + } +@@ -436,9 +440,10 @@ visit_reachable(PyObject *op, PyGC_Head + * If gc_refs == GC_UNTRACKED, it must be ignored. + */ + else { +- assert(gc_refs > 0 +- || gc_refs == GC_REACHABLE +- || gc_refs == GC_UNTRACKED); ++ PyObject_ASSERT(FROM_GC(gc), ++ gc_refs > 0 ++ || gc_refs == GC_REACHABLE ++ || gc_refs == GC_UNTRACKED); + } + } + return 0; +@@ -480,7 +485,7 @@ move_unreachable(PyGC_Head *young, PyGC_ + */ + PyObject *op = FROM_GC(gc); + traverseproc traverse = Py_TYPE(op)->tp_traverse; +- assert(_PyGCHead_REFS(gc) > 0); ++ PyObject_ASSERT(op, _PyGCHead_REFS(gc) > 0); + _PyGCHead_SET_REFS(gc, GC_REACHABLE); + (void) traverse(op, + (visitproc)visit_reachable, +@@ -543,7 +548,7 @@ move_legacy_finalizers(PyGC_Head *unreac + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { + PyObject *op = FROM_GC(gc); + +- assert(IS_TENTATIVELY_UNREACHABLE(op)); ++ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (has_legacy_finalizer(op)) { +@@ -619,7 +624,7 @@ handle_weakrefs(PyGC_Head *unreachable, + PyWeakReference **wrlist; + + op = FROM_GC(gc); +- assert(IS_TENTATIVELY_UNREACHABLE(op)); ++ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op))) +@@ -640,9 +645,9 @@ handle_weakrefs(PyGC_Head *unreachable, + * the callback pointer intact. Obscure: it also + * changes *wrlist. + */ +- assert(wr->wr_object == op); ++ PyObject_ASSERT(wr->wr_object, wr->wr_object == op); + _PyWeakref_ClearRef(wr); +- assert(wr->wr_object == Py_None); ++ PyObject_ASSERT(wr->wr_object, wr->wr_object == Py_None); + if (wr->wr_callback == NULL) + continue; /* no callback */ + +@@ -676,7 +681,7 @@ handle_weakrefs(PyGC_Head *unreachable, + */ + if (IS_TENTATIVELY_UNREACHABLE(wr)) + continue; +- assert(IS_REACHABLE(wr)); ++ PyObject_ASSERT(op, IS_REACHABLE(wr)); + + /* Create a new reference so that wr can't go away + * before we can process it again. +@@ -685,7 +690,8 @@ handle_weakrefs(PyGC_Head *unreachable, + + /* Move wr to wrcb_to_call, for the next pass. */ + wrasgc = AS_GC(wr); +- assert(wrasgc != next); /* wrasgc is reachable, but ++ PyObject_ASSERT(op, wrasgc != next); ++ /* wrasgc is reachable, but + next isn't, so they can't + be the same */ + gc_list_move(wrasgc, &wrcb_to_call); +@@ -701,11 +707,11 @@ handle_weakrefs(PyGC_Head *unreachable, + + gc = wrcb_to_call.gc.gc_next; + op = FROM_GC(gc); +- assert(IS_REACHABLE(op)); +- assert(PyWeakref_Check(op)); ++ PyObject_ASSERT(op, IS_REACHABLE(op)); ++ PyObject_ASSERT(op, PyWeakref_Check(op)); + wr = (PyWeakReference *)op; + callback = wr->wr_callback; +- assert(callback != NULL); ++ PyObject_ASSERT(op, callback != NULL); + + /* copy-paste of weakrefobject.c's handle_callback() */ + temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); +@@ -822,12 +828,14 @@ check_garbage(PyGC_Head *collectable) + for (gc = collectable->gc.gc_next; gc != collectable; + gc = gc->gc.gc_next) { + _PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); +- assert(_PyGCHead_REFS(gc) != 0); ++ PyObject_ASSERT(FROM_GC(gc), ++ _PyGCHead_REFS(gc) != 0); + } + subtract_refs(collectable); + for (gc = collectable->gc.gc_next; gc != collectable; + gc = gc->gc.gc_next) { +- assert(_PyGCHead_REFS(gc) >= 0); ++ PyObject_ASSERT(FROM_GC(gc), ++ _PyGCHead_REFS(gc) >= 0); + if (_PyGCHead_REFS(gc) != 0) + return -1; + } +diff -up Lib/test/test_gc.py.old Lib/test/test_gc.py +--- Lib/test/test_gc.py.old 2014-12-10 11:19:33.503982288 +0100 ++++ Lib/test/test_gc.py 2014-12-10 11:21:13.220021364 +0100 +@@ -49,6 +49,8 @@ class GC_Detector(object): + # gc collects it. + self.wr = weakref.ref(C1055820(666), it_happened) + ++BUILD_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS']) ++ + @with_tp_del + class Uncollectable(object): + """Create a reference cycle with multiple __del__ methods. +@@ -854,6 +856,8 @@ class GCCallbackTests(unittest.TestCase) + self.assertEqual(len(gc.garbage), 0) + + ++ @unittest.skipIf(BUILD_WITH_NDEBUG, ++ 'built with -NDEBUG') + def test_refcount_errors(self): + self.preclean() + # Verify the "handling" of objects with broken refcounts +diff -up Lib/test/test_gc.py.old Lib/test/test_gc.py +--- Lib/test/test_gc.py.old 2014-12-10 12:50:58.252121318 +0100 ++++ Lib/test/test_gc.py 2014-12-10 12:51:08.594266653 +0100 +@@ -4,6 +4,7 @@ from test.support import (verbose, refco + from test.script_helper import assert_python_ok, make_script, temp_dir + + import sys ++import sysconfig + import time + import gc + import weakref diff --git a/00200-gettext-plural-fix.patch b/00200-gettext-plural-fix.patch new file mode 100644 index 0000000..93b817b --- /dev/null +++ b/00200-gettext-plural-fix.patch @@ -0,0 +1,12 @@ +diff -up Python-2.5.1/Lib/gettext.py.plural Python-2.5.1/Lib/gettext.py +--- Python-2.5.1/Lib/gettext.py.plural 2007-09-10 11:38:57.000000000 -0400 ++++ Python-2.5.1/Lib/gettext.py 2007-09-10 11:39:00.000000000 -0400 +@@ -299,6 +299,8 @@ class GNUTranslations(NullTranslations): + item = b_item.decode().strip() + if not item: + continue ++ if item.startswith("#"): ++ continue + if ':' in item: + k, v = item.split(':', 1) + k = k.strip().lower() diff --git a/00201-fix-memory-leak-in-gdbm.patch b/00201-fix-memory-leak-in-gdbm.patch new file mode 100644 index 0000000..48839d5 --- /dev/null +++ b/00201-fix-memory-leak-in-gdbm.patch @@ -0,0 +1,10 @@ +--- Modules/_gdbmmodule.c.orig 2013-07-08 14:54:27.803790151 +0200 ++++ Modules/_gdbmmodule.c 2013-07-08 14:55:25.006672443 +0200 +@@ -106,6 +106,7 @@ + if(okey.dsize) free(okey.dptr); + okey=key; + } ++ if(okey.dsize) free(okey.dptr); + dp->di_size = size; + } + return dp->di_size; diff --git a/python3.spec b/python3.spec index 916bc6c..cbe48d0 100644 --- a/python3.spec +++ b/python3.spec @@ -140,7 +140,7 @@ Summary: Version 3 of the Python programming language aka Python 3000 Name: python3 Version: %{pybasever}.2 -Release: 2%{?dist} +Release: 3%{?dist} License: Python Group: Development/Languages @@ -539,10 +539,16 @@ Patch164: 00164-disable-interrupted_write-tests-on-ppc.patch # in python.spec # TODO: python3 status? -# 00170 # -# Patch170: 00170-gc-assertions.patch -# in python.spec -# TODO: python3 status? +# 00170 # +# In debug builds, try to print repr() when a C-level assert fails in the +# garbage collector (typically indicating a reference-counting error +# somewhere else e.g in an extension module) +# Backported to 2.7 from a patch I sent upstream for py3k +# http://bugs.python.org/issue9263 (rhbz#614680) +# hiding the proposed new macros/functions within gcmodule.c to avoid exposing +# them within the extension API. +# (rhbz#850013 +Patch170: 00170-gc-assertions.patch # 00171 # # python.spec had: @@ -704,6 +710,18 @@ Patch196: 00196-test-gdb-match-addr-before-builtin.patch # Issue: http://bugs.python.org/issue22638 Upstream discussion about SSLv3 in Python Patch199: 00199-alter-tests-to-reflect-sslv3-disabled.patch +# 00200 # +# Fix for gettext plural form headers (lines that begin with "#") +# Note: Backported from scl +Patch200: 00200-gettext-plural-fix.patch + +# 00201 # +# Fixes memory leak in gdbm module (rhbz#977308) +# This was upstreamed as a part of bigger patch, but for our purposes +# this is ok: http://bugs.python.org/issue18404 +# Note: Backported from scl +Patch201: 00201-fix-memory-leak-in-gdbm.patch + # (New patches go here ^^^) # @@ -1872,6 +1890,10 @@ rm -fr %{buildroot} # ====================================================== %changelog +* Tue Dec 16 2014 Robert Kuska - 3.4.2-3 +- New patches: 170 (gc asserts), 200 (gettext headers), + 201 (gdbm memory leak) + * Thu Dec 11 2014 Robert Kuska - 3.4.2-2 - OpenSSL disabled SSLv3 in SSLv23 method