Bogdanp / racket-gui-easy

Declarative GUIs in Racket.
https://docs.racket-lang.org/gui-easy/index.html
134 stars 18 forks source link

update-children in container%: hash-ref: no value found for key #18

Closed benknoble closed 2 years ago

benknoble commented 2 years ago

When I run the following program and close the dialog, I consistently get the following output, with an error message:

(object:renderer% ...)
hash-ref: no value found for key
  key: (object:text% ...)
  context...:
   /Users/$USER/Library/Racket/8.5/pkgs/gui-easy-lib/gui/easy/private/view/container.rkt:22:4: update-children method in container%
   /Applications/Racket v8.5/share/pkgs/gui-lib/mred/private/wx/common/queue.rkt:435:6
   /Applications/Racket v8.5/share/pkgs/gui-lib/mred/private/wx/common/queue.rkt:486:32
   /Applications/Racket v8.5/share/pkgs/gui-lib/mred/private/wx/common/queue.rkt:634:3

Program:

#lang racket

(require racket/gui/easy
         racket/gui/easy/operator)

;; calls `proc` when the window closes
(define ((make-on-close-mixin proc) %)
  (class %
    (super-new)
    (define/augment (on-close)
      (proc))))

(define/obs @thing (list 1))
(render
  (dialog
    #:mixin (make-on-close-mixin (thunk (<~ @thing rest)))
    (text (~> @thing (λ (t) (if (empty? t)
                                ""
                                (~a (first t))))))))

Even more bizarrely the indicated line (22 in gui-easy-lib/gui/easy/private/view/container.rkt) is

      (for ([c (in-list (hash-ref deps-to-children what null))])

which has a default value for the hash-ref? So perhaps this is an odd racket bug… unfortunately I cannot come up with a small hash-ref test-case that demonstrates the same bug, and the "context" elision is useless.

Bogdanp commented 2 years ago

Thanks for the report! Fundamentally, this was a data race in the destroy path: updates were correctly being queued up using the eventspace queue, but destroys weren't, so orderings where the container state was inconsistent were possible.

The trace on compiled code was misleading (probably due to inlining) and the error was actually raised in get-child (called on line 23). Typically, to debug these types of errors I end up deleting the compiled folders in the project and then run the code with errortrace (which is extremely slow, but at least provides accurate traces).