This was the Android App version of Zoiper. Whatever the latest version was at the time.
I believe I found the reason for this while testing with a different client. I believe that the far-end was returning an incorrect (or missing) "Contact" address in the response to the initial INVITE.
Hence Zoiper did not have a place to which it could send the BYE at call teardown.
So -- no fault in Zoiper I believe. (Other than perhaps it could have shown a warning message?)