The value NIL is not of type FUNCTION inside SB-PCL::INVOKE-EMF

Bug #1909659 reported by Michał "phoe" Herda on 2020-12-30
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
High
Christophe Rhodes

Bug Description

A TYPE-ERROR is sometimes signaled instead of a PROGRAM-ERROR.

This behavior is intermittent and disappears if I call (test) the second time.

----------------------------------------------------

;;;; /tmp/foo.lisp

(defun report-my-unbound-variable (condition stream)
  (format stream "The variable ~S is unbound."
          (my-cell-error-name condition)))

(defclass my-unbound-variable ()
  ((name :reader my-cell-error-name :initarg :name)))

(defmethod print-object ((condition my-unbound-variable) stream)
  (funcall #'report-my-unbound-variable condition stream))

(defun test ()
  (funcall (lambda () (my-cell-error-name
                       (make-instance 'my-unbound-variable :name 'foo)
                       nil))))

----------------------------------------------------

CL-USER> (lisp-implementation-version)
"2.1.0"

CL-USER> (sb-ext:describe-compiler-policy)
  Basic qualities:
COMPILATION-SPEED = 1
DEBUG = 1
SAFETY = 1
SPACE = 1
SPEED = 1
INHIBIT-WARNINGS = 1
  Dependent qualities:
SB-C::CHECK-CONSTANT-MODIFICATION = 1 -> 1 (maybe)
SB-C::TYPE-CHECK = 1 -> 3 (full)
SB-C::CHECK-TAG-EXISTENCE = 1 -> 3 (yes)
SB-C::LET-CONVERSION = 1 -> 3 (on)
SB-C:ALIEN-FUNCALL-SAVES-FP-AND-PC = 1 -> 3 (yes)
SB-C:VERIFY-ARG-COUNT = 1 -> 3 (yes)
SB-C::INSERT-DEBUG-CATCH = 1 -> 1 (maybe)
SB-C::RECOGNIZE-SELF-CALLS = 1 -> 0 (no)
SB-C::FLOAT-ACCURACY = 1 -> 3 (full)
SB-C:INSERT-STEP-CONDITIONS = 1 -> 0 (no)
SB-C::COMPUTE-DEBUG-FUN = 1 -> 1 (yes)
SB-C:STORE-SOURCE-FORM = 1 -> 1 (maybe)
SB-C::PRESERVE-SINGLE-USE-DEBUG-VARIABLES = 1 -> 0 (no)
SB-C::INSERT-ARRAY-BOUNDS-CHECKS = 1 -> 3 (yes)
SB-C::STORE-XREF-DATA = 1 -> 3 (yes)
SB-C:STORE-COVERAGE-DATA = 1 -> 0 (no)
SB-C::INSTRUMENT-CONSING = 1 -> 1 (no)
SB-C::STORE-CLOSURE-DEBUG-POINTER = 1 -> 0 (no)
SB-KERNEL:ALLOW-NON-RETURNING-TAIL-CALL = 1 -> 0 (no)
; No value

----------------------------------------------------

; compiling file "/tmp/foo.lisp" (written 30 DEC 2020 11:57:41 AM):

; file: /tmp/foo.lisp
; in: DEFUN TEST
; (MY-CELL-ERROR-NAME (MAKE-INSTANCE 'MY-UNBOUND-VARIABLE :NAME 'FOO) NIL)
;
; caught STYLE-WARNING:
; The function MY-CELL-ERROR-NAME is called with two arguments, but wants exactly one.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition

; wrote /tmp/foo.fasl
; compilation finished in 0:00:00.012

CL-USER> (test)

The value
  NIL
is not of type
  FUNCTION
   [Condition of type TYPE-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {100FF91EC3}>)

Backtrace:
  0: (SB-PCL::INVOKE-EMF 0 (The variable FOO is unbound. NIL))
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (TEST) #<NULL-LEXENV>)
  2: (EVAL (TEST))

Michał "phoe" Herda (phoe-krk) wrote :

Oops - this is not a regression, this is an old bug! (Thanks, Krystof.) Reproduced on SBCL 1.4.16 and 2.0.11.

I only did not notice it because I always run SBCL with (OPTIMIZE SAFETY DEBUG), and it took another person who ran the test suite on default settings to notice this failure.

Michał "phoe" Herda (phoe-krk) wrote :

Further reduced test case:

(defclass foo ()
  ((name :reader foo-name)))

(defun test ()
  (funcall (lambda () (foo-name (make-instance 'foo) nil))))

Michał "phoe" Herda (phoe-krk) wrote :

(defun oops (&rest args) (break "Broken: ~S" args))

(defclass foo () ((name :reader foo-name)))

(defun test ()
  (funcall (lambda () (foo-name (make-instance 'foo) #'oops))))

---------------------------------------------

CL-USER> (test)

Unhandled memory fault at #x0.
   [Condition of type SB-SYS:MEMORY-FAULT-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {100FF91EC3}>)

Backtrace:
  0: (SB-PCL::INVOKE-EMF 0 (#<FOO {1011BD20D3}> #<FUNCTION OOPS>))
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (TEST) #<NULL-LEXENV>)
  2: (EVAL (TEST))

The confusion in INVOKE-EMF causes a two-arg call to a reader function to attempt to write the first argument at a slot offset of the second. This is... not ideal.

(defun report-my-unbound-variable (condition stream)
  (format stream "The variable ~S is unbound."
          (my-cell-error-name condition)))

(defclass my-unbound-variable ()
  ((name :reader my-cell-error-name :initarg :name)))

(defmethod print-object ((condition my-unbound-variable) stream)
  (funcall #'report-my-unbound-variable condition stream))

(defclass zzz ()
  ((x :initform 1))
  (:metaclass sb-mop:funcallable-standard-class))

(defun test ()
  (let ((zzz (make-instance 'zzz)))
    (assert (typep (slot-value zzz 'x) '(integer 1)))
    (funcall (lambda () (my-cell-error-name
                         (make-instance 'my-unbound-variable :name 'foo)
                         zzz)))
    (assert (typep (slot-value zzz 'x) '(integer 1)))))

Changed in sbcl:
importance: Undecided → High
status: New → Confirmed
status: Confirmed → Triaged
assignee: nobody → Christophe Rhodes (csr21-cantab)

fixed in 1543714587bfb536f6e8fb5256f355f3d76bbbbb

Changed in sbcl:
status: Triaged → Fix Committed
Changed in sbcl:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers