detect cpl-protocol-violations early
authorChristophe Rhodes <csr21@cantab.net>
Tue, 10 Sep 2013 22:24:46 +0000 (23:24 +0100)
committerChristophe Rhodes <csr21@cantab.net>
Tue, 10 Sep 2013 22:25:59 +0000 (23:25 +0100)
Don't try to eagerly finalize classes which will cause
cpl-protocol-violations to be signalled.  (lp#309076)

NEWS
src/pcl/dfun.lisp
src/pcl/std-class.lisp
tests/clos.impure.lisp

diff --git a/NEWS b/NEWS
index fa9a742..c099edc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,8 @@ changes relative to sbcl-1.1.11:
     constructors handles non-KEYWORD initialization arguments more correctly.
   * bug fix: loading the SB-SIMPLE-STREAMS contributed module no longer
     clobbers FILE-NAMESTRING.  (thanks to Anton Kovalenko, lp#884603)
+  * bug fix: class definitions with CPLs inconsistent with their metaclasses
+    are less likely to destroy the object system's integrity.  (lp#309076)
   
 changes in sbcl-1.1.11 relative to sbcl-1.1.10:
   * enhancement: support building the manual under texinfo version 5.
index 35e9fba..05aace9 100644 (file)
@@ -1441,7 +1441,8 @@ Except see also BREAK-VICIOUS-METACIRCLE.  -- CSR, 2003-05-28
 
         ;; if we can finalize an unfinalized class, then do so
         (when (and (not (class-finalized-p class))
-                   (not (class-has-a-forward-referenced-superclass-p class)))
+                   (not (class-has-a-forward-referenced-superclass-p class))
+                   (not (class-has-a-cpl-protocol-violation-p class)))
           (finalize-inheritance class)
           (class-precedence-list class)))
 
index 1ac4eb4..975acc4 100644 (file)
              (find-class 'function)
              (cpl-protocol-violation-cpl c)))))
 
+(defun class-has-a-cpl-protocol-violation-p (class)
+  (labels ((find-in-superclasses (class classes)
+             (cond
+               ((null classes) nil)
+               ((eql class (car classes)) t)
+               (t (find-in-superclasses class (append (class-direct-superclasses (car classes)) (cdr classes)))))))
+    (let ((metaclass (class-of class)))
+      (cond
+        ((eql metaclass *the-class-standard-class*)
+         (find-in-superclasses (find-class 'function) (list class)))
+        ((eql metaclass *the-class-funcallable-standard-class*)
+         (not (find-in-superclasses (find-class 'function) (list class))))))))
+
 (defun %update-cpl (class cpl)
   (when (eq (class-of class) *the-class-standard-class*)
     (when (find (find-class 'function) cpl)
index 0838bd6..4484eb7 100644 (file)
     (assert
      (foo= 15 (funcall (compile nil '(lambda () (make-instance 'bug-1179858b 'foo 15))))))))
 
+(with-test (:name (cpl-violation-setup :bug-309076))
+  (assert (raises-error?
+           (progn
+             (defclass bug-309076-broken-class (standard-class) ()
+               (:metaclass sb-mop:funcallable-standard-class))
+             (sb-mop:finalize-inheritance (find-class 'bug-309076-broken-class))))))
+
+(with-test (:name (cpl-violation-irrelevant-class :bug-309076))
+  (defclass bug-309076-class (standard-class) ())
+  (defmethod sb-mop:validate-superclass ((x bug-309076-class) (y standard-class)) t)
+  (assert (typep (make-instance 'bug-309076-class) 'bug-309076-class)))
+
 ;;;; success