From ea3912b0da71e16b8a37e04fcf3969dc85c27fa1 Mon Sep 17 00:00:00 2001
From: Brett Cannon <bcannon@gmail.com>
Date: Tue, 13 Jun 2006 21:46:41 +0000
Subject: If a classic class defined a __coerce__() method that just returned
 its two arguments in reverse, the interpreter would infinitely recourse
 trying to get a coercion that worked.  So put in a recursion check after a
 coercion is made and the next call to attempt to use the coerced values.

Fixes bug #992017 and closes crashers/coerce.py .
---
 Lib/test/crashers/coerce.py | 9 ---------
 Misc/NEWS                   | 3 +++
 Objects/classobject.c       | 3 +++
 3 files changed, 6 insertions(+), 9 deletions(-)
 delete mode 100644 Lib/test/crashers/coerce.py

diff --git a/Lib/test/crashers/coerce.py b/Lib/test/crashers/coerce.py
deleted file mode 100644
index 574956b..0000000
--- a/Lib/test/crashers/coerce.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-# http://python.org/sf/992017
-
-class foo:
-    def __coerce__(self, other):
-        return other, self
-
-if __name__ == '__main__':
-    foo()+1   # segfault: infinite recursion in C
diff --git a/Misc/NEWS b/Misc/NEWS
index 82838f3..d7dfb8f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.5 beta 1?
 Core and builtins
 -----------------
 
+- Bug #992017: A classic class that defined a __coerce__() method that returned
+  its arguments swapped would infinitely recurse and segfault the interpreter.
+
 - Fix the socket tests so they can be run concurrently.
 
 - Removed 5 integers from C frame objects (PyFrameObject).
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 9e57269..c69ba74 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -1368,10 +1368,13 @@ half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc,
 		 * argument */
 		result = generic_binary_op(v1, w, opname);
 	} else {
+		if (Py_EnterRecursiveCall(" after coercion"))
+		    return NULL;
 		if (swapped)
 			result = (thisfunc)(w, v1);
 		else
 			result = (thisfunc)(v1, w);
+		Py_LeaveRecursiveCall();
 	}
 	Py_DECREF(coerced);
 	return result;
-- 
cgit v0.12

