# Buggy code
def sign_message(self, sequence, message, password):
    # Sign a message on device. Since we have big screen, of course we
    # have to show the message unabiguously there first!
    try:
        msg = message.encode("ascii", errors="strict")
        assert 1 <= len(msg) <= MSG_SIGNING_MAX_LENGTH
    except (UnicodeError, AssertionError):
        # there are other restrictions on message content,
        # but let the device enforce and report those
        self.handler.show_error(
            "Only short (%d max) ASCII messages can be signed." % MSG_SIGNING_MAX_LENGTH
        )
        return b""

    client = self.get_client()
    path = self.get_derivation_prefix() + ("/%d/%d" % sequence)
    try:
        cl = self.get_client()
        try:
            self.handler.show_message("Signing message (using %s)..." % path)

            cl.sign_message_start(path, msg)

            while 1:
                # How to kill some time, without locking UI?
                time.sleep(0.250)

                resp = cl.sign_message_poll()
                if resp is not None:
                    break

        finally:
            self.handler.finished()

        assert len(resp) == 2
        addr, raw_sig = resp

        # already encoded in Bitcoin fashion, binary.
        assert 40 < len(raw_sig) <= 65

        return raw_sig

    except (CCUserRefused, CCBusyError) as exc:
        self.handler.show_error(str(exc))
    except CCProtoError as exc:
        self.logger.exception("Error showing address")
        self.handler.show_error(
            "{}\n\n{}".format(_("Error showing address") + ":", str(exc))
        )
    except Exception as e:
        self.give_error(e, True)

    # give empty bytes for error cases; it seems to clear the old signature box
    return b""


# Traceback (OSError)
$ ~/Downloads/apps/electrum-4.0.2-x86_64.AppImage --testnet
Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
E | plugin.DeviceMgr | failed to create client for bitbox02 at b'0001:0009:01': Exception('No BitBox02 detected')
E | plugins.coldcard.coldcard.Coldcard_KeyStore |
Traceback (most recent call last):
File "/tmp/.mount_electrcFBIsQ/usr/lib/python3.7/site-packages/electrum/plugins/coldcard/coldcard.py", line 383, in sign_transaction
resp = client.sign_transaction_poll()
File "/tmp/.mount_electrcFBIsQ/usr/lib/python3.7/site-packages/electrum/plugins/coldcard/coldcard.py", line 233, in sign_transaction_poll
return self.dev.send_recv(CCProtocolPacker.get_signed_txn(), timeout=None)
File "/tmp/.mount_electrcFBIsQ/usr/lib/python3.7/site-packages/ckcc/client.py", line 139, in send_recv
buf = self.dev.read(64, timeout_ms=(timeout or 0))
File "hid.pyx", line 123, in hid.device.read
OSError: read error
double free or corruption (fasttop)
Aborted

# Fixed code
def sign_message(self, sequence, message, password):
    # Sign a message on device. Since we have big screen, of course we
    # have to show the message unabiguously there first!
    try:
        msg = message.encode("ascii", errors="strict")
        assert 1 <= len(msg) <= MSG_SIGNING_MAX_LENGTH
    except (UnicodeError, AssertionError):
        # there are other restrictions on message content,
        # but let the device enforce and report those
        self.handler.show_error(
            "Only short (%d max) ASCII messages can be signed." % MSG_SIGNING_MAX_LENGTH
        )
        return b""

    path = self.get_derivation_prefix() + ("/%d/%d" % sequence)
    try:
        cl = self.get_client()
        try:
            self.handler.show_message("Signing message (using %s)..." % path)

            cl.sign_message_start(path, msg)

            while 1:
                # How to kill some time, without locking UI?
                time.sleep(0.250)

                resp = cl.sign_message_poll()
                if resp is not None:
                    break

        finally:
            self.handler.finished()

        assert len(resp) == 2
        addr, raw_sig = resp

        # already encoded in Bitcoin fashion, binary.
        assert 40 < len(raw_sig) <= 65

        return raw_sig

    except (CCUserRefused, CCBusyError) as exc:
        self.handler.show_error(str(exc))
    except CCProtoError as exc:
        self.logger.exception("Error showing address")
        self.handler.show_error(
            "{}\n\n{}".format(_("Error showing address") + ":", str(exc))
        )
    except Exception as e:
        self.give_error(e, True)

    # give empty bytes for error cases; it seems to clear the old signature box
    return b""