core.async

core.async exception rewriting can result in an incorrect return value

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

The following test case passes in core.async 0.2.395, but fails on 0.3.443 due to an incorrect return value from an exception catch. See comments in the test for details.

(ns core-async-exception-test
  (:require [clojure.test :refer :all]
            [clojure.tools.logging :refer [log]]
            [clojure.core.async  :as a]))

(deftest async-error-proof
  (let [resp (a/go
               (try
                 ;; In version 0.2.395 of core.async this test passes
                 ;; (i.e. the behaviour would be as expected). However
                 ;; in 0.3.443 (and other 0.3.x versions) this
                 ;; fails.
                 ;;
                 ;; Note that we wrap the :outer-ok return
                 ;; value. However, with this code-structure in place
                 ;; an *unwrapped* version of the exception is thrown,
                 ;; causing an UnsupportedOperationexception when it
                 ;; attempts to destructure it.
                 ;;
                 ;; Any of the following changes will fix the issue:
                 ;; * Remove the empty finally.
                 ;; * Unwrap the :outer-ok and remove destructuring
                 ;; * Remove the 'value' go/fetch.

                 (let [[r] (try

                             (let [value (a/<!
                                          (a/go :any))]

                               (log :info "Got value, throwing exception")
                               (throw (ex-info "Exception" {:type :inner})))

                             (catch Throwable e
                               (log :info "Caught the exception")

                               [:outer-ok])

                             (finally))] ;; <- Remove this finally to make it work



                   (throw (ex-info "Throwing outer exception" {:type :outer})))

                 (catch clojure.lang.ExceptionInfo ex
                   (assert (= :outer (-> ex ex-data :type)))
                   (log :info "Got Exception Info")
                   :ok)

                 (catch UnsupportedOperationException ex
                   (log :info "Got unsupported exception")
                   :unsupported)))]

    (is (= :ok (a/<!! resp)))))

Activity

Hide
Steve Smith added a comment -

Note, that a bisect on the history shows this behaviour is associated with the changes for ASYNC-169: https://github.com/clojure/core.async/commit/a879b388a47786ef8ee21458eb45403193028f49

Show
Steve Smith added a comment - Note, that a bisect on the history shows this behaviour is associated with the changes for ASYNC-169: https://github.com/clojure/core.async/commit/a879b388a47786ef8ee21458eb45403193028f49

People

Vote (1)
Watch (1)

Dates

  • Created:
    Updated: