diff mbox

[7/9] char: handle qemu_chr_add_handlers() error

Message ID 20161013111449.29387-8-marcandre.lureau@redhat.com
State New
Headers show

Commit Message

Marc-André Lureau Oct. 13, 2016, 11:14 a.m. UTC
Raise or assert on qemu_chr_add_handlers() error.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/rng-egd.c          |  2 +-
 gdbstub.c                   |  4 ++--
 hw/arm/pxa2xx.c             |  3 ++-
 hw/arm/strongarm.c          |  3 ++-
 hw/char/bcm2835_aux.c       |  2 +-
 hw/char/cadence_uart.c      |  2 +-
 hw/char/debugcon.c          |  5 ++++-
 hw/char/digic-uart.c        |  3 ++-
 hw/char/escc.c              |  3 ++-
 hw/char/etraxfs_ser.c       |  4 ++--
 hw/char/exynos4210_uart.c   |  9 +++++++-
 hw/char/grlib_apbuart.c     |  3 ++-
 hw/char/imx_serial.c        |  2 +-
 hw/char/ipoctal232.c        |  5 ++++-
 hw/char/lm32_juart.c        |  3 ++-
 hw/char/lm32_uart.c         |  3 ++-
 hw/char/mcf_uart.c          |  3 ++-
 hw/char/milkymist-uart.c    |  3 ++-
 hw/char/pl011.c             |  2 +-
 hw/char/sclpconsole-lm.c    |  9 ++++++--
 hw/char/sclpconsole.c       |  3 ++-
 hw/char/serial.c            |  6 ++++-
 hw/char/sh_serial.c         |  3 ++-
 hw/char/spapr_vty.c         |  2 +-
 hw/char/stm32f2xx_usart.c   |  2 +-
 hw/char/virtio-console.c    |  7 ++++--
 hw/char/xen_console.c       | 11 +++++++++-
 hw/char/xilinx_uartlite.c   |  3 ++-
 hw/ipmi/ipmi_bmc_extern.c   |  3 ++-
 hw/misc/ivshmem.c           |  5 ++++-
 hw/usb/ccid-card-passthru.c |  9 +++++++-
 hw/usb/dev-serial.c         |  6 ++++-
 hw/usb/redirect.c           |  6 ++++-
 monitor.c                   | 12 +++++++---
 net/colo-compare.c          | 23 ++++++++++++++++----
 net/filter-mirror.c         |  6 ++++-
 net/slirp.c                 |  8 ++++++-
 net/vhost-user.c            | 14 +++++++-----
 qemu-char.c                 | 53 +++++++++++++++++++++++----------------------
 qtest.c                     |  7 ++++--
 stubs/monitor-init.c        |  2 +-
 tests/vhost-user-test.c     |  3 ++-
 vl.c                        |  2 +-
 include/monitor/monitor.h   |  2 +-
 include/sysemu/char.h       | 19 +++++-----------
 45 files changed, 193 insertions(+), 97 deletions(-)
diff mbox

Patch

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 5d8485f..a62eefa 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -111,7 +111,7 @@  static void rng_egd_opened(RngBackend *b, Error **errp)
     if (s->chr_tag == -1) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read,
-                                  rng_egd_chr_read, NULL, s);
+                                  rng_egd_chr_read, NULL, s, NULL, errp);
     }
 }
 
diff --git a/gdbstub.c b/gdbstub.c
index 054a1d3..ee04be3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1754,7 +1754,7 @@  int gdbserver_start(const char *device)
         qemu_chr_fe_claim_no_fail(chr);
         chr_tag =
             qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
-                                  gdb_chr_event, NULL);
+                                  gdb_chr_event, NULL, NULL, &error_abort);
     }
 
     s = gdbserver_state;
@@ -1767,7 +1767,7 @@  int gdbserver_start(const char *device)
         /* Initialize a monitor terminal for gdb */
         mon_chr = qemu_chr_alloc(&common, &error_abort);
         mon_chr->chr_write = gdb_monitor_write;
-        monitor_init(mon_chr, 0);
+        monitor_init(mon_chr, 0, &error_abort);
     } else {
         if (s->chr) {
             qemu_chr_remove_handlers(s->chr, s->chr_tag);
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index e17b904..d70712d 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1978,7 +1978,8 @@  static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
         qemu_chr_fe_claim_no_fail(s->chr);
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
-                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+                                  pxa2xx_fir_rx, pxa2xx_fir_event,
+                                  s, NULL, errp);
     }
 }
 
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 48b4a7c..03150ab 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -39,6 +39,7 @@ 
 #include "hw/ssi/ssi.h"
 #include "qemu/cutils.h"
 #include "qemu/log.h"
+#include "qapi/error.h"
 
 //#define DEBUG
 
@@ -1246,7 +1247,7 @@  static void strongarm_uart_init(Object *obj)
                         strongarm_uart_can_receive,
                         strongarm_uart_receive,
                         strongarm_uart_event,
-                        s);
+                        s, NULL, &error_abort);
     }
 }
 
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 5694c32..7e00c68 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -285,7 +285,7 @@  static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
-                              bcm2835_aux_receive, NULL, s);
+                                  bcm2835_aux_receive, NULL, s, NULL, errp);
     }
 }
 
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 7ca8f0a..3d66e1b 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -477,7 +477,7 @@  static void cadence_uart_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
-                              uart_event, s);
+                                  uart_event, s, NULL, errp);
     }
 }
 
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 45876a7..4f4e4e6 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -98,7 +98,10 @@  static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
     }
 
     /* necessary to start the be */
-    s->chr_tag = qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+    s->chr_tag = qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s, NULL, errp);
+    if (s->chr_tag == -1) {
+        return;
+    }
 
     memory_region_init_io(&s->io, OBJECT(dev), &debugcon_ops, s,
                           TYPE_ISA_DEBUGCON_DEVICE, 1);
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index 83217a4..04013f7 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -149,7 +149,8 @@  static void digic_uart_realize(DeviceState *dev, Error **errp)
 
     if (s->chr) {
         s->chr_tag =
-            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event,
+                                  s, NULL, errp);
     }
 }
 
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 0cbaf27..0e97291 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -1018,7 +1018,8 @@  static void escc_realize(DeviceState *dev, Error **errp)
             s->chn[i].clock = s->frequency / 2;
             s->chn[i].chr_tag =
                 qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
-                                  serial_receive1, serial_event, &s->chn[i]);
+                                      serial_receive1, serial_event, &s->chn[i],
+                                      NULL, errp);
         }
     }
 
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index e606a76..b7cf7b5 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -235,8 +235,8 @@  static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr,
-                              serial_can_receive, serial_receive,
-                              serial_event, s);
+                                  serial_can_receive, serial_receive,
+                                  serial_event, s, NULL, errp);
     }
 }
 
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index ba84a4f..40139ae 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -24,6 +24,7 @@ 
 #include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/char.h"
+#include "qapi/error.h"
 
 #include "hw/arm/exynos4210.h"
 
@@ -633,6 +634,7 @@  DeviceState *exynos4210_uart_create(hwaddr addr,
 static int exynos4210_uart_init(SysBusDevice *dev)
 {
     Exynos4210UartState *s = EXYNOS4210_UART(dev);
+    Error *err = NULL;
 
     /* memory mapping */
     memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s,
@@ -643,7 +645,12 @@  static int exynos4210_uart_init(SysBusDevice *dev)
 
     s->chr_tag =
         qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
-                          exynos4210_uart_receive, exynos4210_uart_event, s);
+                              exynos4210_uart_receive, exynos4210_uart_event,
+                              s, NULL, &err);
+    if (err) {
+        error_report_err(err);
+        return -1;
+    }
 
     return 0;
 }
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 963ca6d..dcacb3a 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -25,6 +25,7 @@ 
 #include "qemu/osdep.h"
 #include "hw/sysbus.h"
 #include "sysemu/char.h"
+#include "qapi/error.h"
 
 #include "trace.h"
 
@@ -248,7 +249,7 @@  static int grlib_apbuart_init(SysBusDevice *dev)
                           grlib_apbuart_can_receive,
                           grlib_apbuart_receive,
                           grlib_apbuart_event,
-                          uart);
+                          uart, NULL, &error_abort);
 
     sysbus_init_irq(dev, &uart->irq);
 
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 5ac3122..ceb9951 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -321,7 +321,7 @@  static void imx_serial_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
-                                  imx_event, s);
+                                  imx_event, s, NULL, errp);
     } else {
         DPRINTF("No char dev for uart\n");
     }
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 4adc500..8175273 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -549,7 +549,10 @@  static void ipoctal_realize(DeviceState *dev, Error **errp)
         /* Redirect IP-Octal channels to host character devices */
         if (ch->dev) {
             ch->chr_tag = qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
-                                  hostdev_receive, hostdev_event, ch);
+                              hostdev_receive, hostdev_event, ch, NULL, errp);
+            if (ch->chr_tag == -1) {
+                return;
+            }
             DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
         } else {
             DPRINTF("Could not redirect channel %u, no chardev set\n", i);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index 065195d..6c2677f 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -123,7 +123,8 @@  static void lm32_juart_realize(DeviceState *dev, Error **errp)
 
     if (s->chr) {
         s->chr_tag = qemu_chr_add_handlers(s->chr, juart_can_rx,
-                                           juart_rx, juart_event, s);
+                                           juart_rx, juart_event,
+                                           s, NULL, errp);
     }
 }
 
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index c94cf19..6c74c55 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -270,7 +270,8 @@  static void lm32_uart_realize(DeviceState *dev, Error **errp)
 
     if (s->chr) {
         s->chr_tag =
-            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event,
+                                  s, NULL, errp);
     }
 }
 
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index 7a677c7..3d9037d 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -10,6 +10,7 @@ 
 #include "hw/m68k/mcf.h"
 #include "sysemu/char.h"
 #include "exec/address-spaces.h"
+#include "qapi/error.h"
 
 typedef struct {
     MemoryRegion iomem;
@@ -287,7 +288,7 @@  void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
         qemu_chr_fe_claim_no_fail(chr);
         s->chr_tag =
             qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
-                              mcf_uart_event, s);
+                                  mcf_uart_event, s, NULL, &error_abort);
     }
     mcf_uart_reset(s);
     return s;
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index 0203512..04fec4c 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -203,7 +203,8 @@  static void milkymist_uart_realize(DeviceState *dev, Error **errp)
 
     if (s->chr) {
         s->chr_tag =
-            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event,
+                                  s, NULL, errp);
     }
 }
 
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 903c044..0827c51 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -306,7 +306,7 @@  static void pl011_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
-                              pl011_event, s);
+                                  pl011_event, s, NULL, errp);
     }
 }
 
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7c76d9e..5677864 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -18,6 +18,7 @@ 
 #include "qemu/thread.h"
 #include "qemu/error-report.h"
 #include "sysemu/char.h"
+#include "qapi/error.h"
 
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/event-facility.h"
@@ -304,8 +305,8 @@  static const VMStateDescription vmstate_sclplmconsole = {
 static int console_init(SCLPEvent *event)
 {
     static bool console_available;
-
     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
+    Error *err = NULL;
 
     if (console_available) {
         error_report("Multiple line-mode operator consoles are not supported");
@@ -316,7 +317,11 @@  static int console_init(SCLPEvent *event)
     if (scon->chr) {
         scon->chr_tag =
             qemu_chr_add_handlers(scon->chr, chr_can_read,
-                                  chr_read, NULL, scon);
+                                  chr_read, NULL, scon, NULL, &err);
+        if (err) {
+            error_report_err(err);
+            return -1;
+        }
     }
 
     return 0;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index cf0b309..d3f87ce 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -20,6 +20,7 @@ 
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/event-facility.h"
 #include "sysemu/char.h"
+#include "qapi/error.h"
 
 typedef struct ASCIIConsoleData {
     EventBufferHeader ebh;
@@ -231,7 +232,7 @@  static int console_init(SCLPEvent *event)
     if (scon->chr) {
         scon->chr_tag =
             qemu_chr_add_handlers(scon->chr, chr_can_read,
-                              chr_read, NULL, scon);
+                                  chr_read, NULL, scon, NULL, &error_abort);
     }
 
     return 0;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 9d7d57b..f877cec 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -895,7 +895,11 @@  void serial_realize_core(SerialState *s, Error **errp)
 
     s->chr_tag =
         qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
-                              serial_event, s);
+                              serial_event, s, NULL, errp);
+    if (s->chr_tag == -1) {
+        return;
+    }
+
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
     serial_reset(s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index e093689..034bc49 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -29,6 +29,7 @@ 
 #include "hw/sh4/sh.h"
 #include "sysemu/char.h"
 #include "exec/address-spaces.h"
+#include "qapi/error.h"
 
 //#define DEBUG_SERIAL
 
@@ -403,7 +404,7 @@  void sh_serial_init(MemoryRegion *sysmem,
         qemu_chr_fe_claim_no_fail(chr);
         tag = qemu_chr_add_handlers(chr, sh_serial_can_receive1,
                                     sh_serial_receive1,
-                                    sh_serial_event, s);
+                                    sh_serial_event, s, NULL, &error_abort);
         assert(tag != -1);
     }
 
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index fdc32e3..dfb12ac 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -77,7 +77,7 @@  static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
 
     dev->chr_tag =
         qemu_chr_add_handlers(dev->chardev, vty_can_receive,
-                          vty_receive, NULL, dev);
+                              vty_receive, NULL, dev, NULL, errp);
 }
 
 static void spapr_vty_unrealize(DeviceState *s, Error **errp)
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 9f8aac5..b1897e9 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -215,7 +215,7 @@  static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
     if (s->chr) {
         s->chr_tag =
             qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
-                              stm32f2xx_usart_receive, NULL, s);
+                                  stm32f2xx_usart_receive, NULL, s, NULL, errp);
     }
 }
 
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index f3f3aa3..984dc25 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -192,13 +192,16 @@  static void virtconsole_realize(DeviceState *dev, Error **errp)
             vcon->chr->explicit_fe_open = 0;
             vcon->chr_tag =
                 qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
-                                  NULL, vcon);
+                                      NULL, vcon, NULL, errp);
+            if (vcon->chr_tag == -1) {
+                return;
+            }
             virtio_serial_open(port);
         } else {
             vcon->chr->explicit_fe_open = 1;
             vcon->chr_tag =
                 qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
-                                  chr_event, vcon);
+                                      chr_event, vcon, NULL, errp);
         }
     }
 }
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index f263dfa..401ec8c 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -26,6 +26,7 @@ 
 #include "hw/hw.h"
 #include "sysemu/char.h"
 #include "hw/xen/xen_backend.h"
+#include "qapi/error.h"
 
 #include <xen/io/console.h>
 
@@ -200,6 +201,7 @@  static int con_init(struct XenDevice *xendev)
         con->chr = serial_hds[con->xendev.dev];
     } else {
         snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
+        /* FIXME: leaks on destroy & initialize error */
         con->chr = qemu_chr_new(label, output, NULL);
     }
 
@@ -213,6 +215,7 @@  out:
 static int con_initialise(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    Error *err = NULL;
     int limit;
 
     if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
@@ -240,7 +243,13 @@  static int con_initialise(struct XenDevice *xendev)
         if (qemu_chr_fe_claim(con->chr) == 0) {
             con->chr_tag =
                 qemu_chr_add_handlers(con->chr, xencons_can_receive,
-                                      xencons_receive, NULL, con);
+                                      xencons_receive, NULL, con, NULL, &err);
+            if (con->chr_tag == -1) {
+                xen_be_printf(xendev, 0, "error: %s\n",
+                              error_get_pretty(err));
+                error_free(err);
+                con->chr = NULL;
+            }
         } else {
             xen_be_printf(xendev, 0,
                           "xen_console_init error chardev %s already used\n",
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index e6b103e..664ac97 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -216,7 +216,8 @@  static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
 
     if (s->chr) {
         s->chr_tag =
-            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+            qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event,
+                                  s, NULL, errp);
     }
 }
 
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index 927bed2..e239834 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -449,7 +449,8 @@  static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
     }
 
     ibe->chr_tag =
-        qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe);
+        qemu_chr_add_handlers(ibe->chr, can_receive, receive,
+                              chr_event, ibe, NULL, errp);
 }
 
 static void ipmi_bmc_extern_unrealize(DeviceState *dev, Error **errp)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 19079f4..9983f7c 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -898,7 +898,10 @@  static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
 
         s->server_chr_tag =
             qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
-                                  ivshmem_read, NULL, s);
+                                  ivshmem_read, NULL, s, NULL, errp);
+        if (s->server_chr_tag == -1) {
+            return;
+        }
 
         if (ivshmem_setup_interrupts(s) < 0) {
             error_setg(errp, "failed to initialize interrupts");
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 8960972..5c0870c 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -14,6 +14,7 @@ 
 #include "qemu/sockets.h"
 #include "ccid.h"
 #include "cacard/vscard_common.h"
+#include "qapi/error.h"
 
 #define DPRINTF(card, lvl, fmt, ...)                    \
 do {                                                    \
@@ -343,6 +344,7 @@  static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
 static int passthru_initfn(CCIDCardState *base)
 {
     PassthruState *card = PASSTHRU_CCID_CARD(base);
+    Error *err = NULL;
 
     card->vscard_in_pos = 0;
     card->vscard_in_hdr = 0;
@@ -351,7 +353,12 @@  static int passthru_initfn(CCIDCardState *base)
         card->chr_tag = qemu_chr_add_handlers(card->cs,
             ccid_card_vscard_can_read,
             ccid_card_vscard_read,
-            ccid_card_vscard_event, card);
+            ccid_card_vscard_event, card,
+            NULL, &err);
+        if (err) {
+            error_report_err(err);
+            return -1;
+        }
         ccid_card_vscard_send_init(card);
     } else {
         error_report("missing chardev");
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 4dcfc68..a1e183a 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -502,7 +502,11 @@  static void usb_serial_realize(USBDevice *dev, Error **errp)
 
     s->chr_tag =
         qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
-                              usb_serial_event, s);
+                              usb_serial_event, s, NULL, errp);
+    if (s->chr_tag == -1) {
+        return;
+    }
+
     usb_serial_handle_reset(dev);
 
     if (s->cs->be_open && !dev->attached) {
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 7d73c93..6dcc56b 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1410,7 +1410,11 @@  static void usbredir_realize(USBDevice *udev, Error **errp)
     /* Let the backend know we are ready */
     dev->chr_tag =
         qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
-                          usbredir_chardev_read, usbredir_chardev_event, dev);
+                              usbredir_chardev_read, usbredir_chardev_event,
+                              dev, NULL, errp);
+    if (dev->chr_tag == -1) {
+        return;
+    }
 
     qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
 }
diff --git a/monitor.c b/monitor.c
index 0d6f0ad..33e063e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3964,7 +3964,7 @@  static void __attribute__((constructor)) monitor_lock_init(void)
     qemu_mutex_init(&monitor_lock);
 }
 
-void monitor_init(CharDriverState *chr, int flags)
+void monitor_init(CharDriverState *chr, int flags, Error **errp)
 {
     static int is_first_init = 1;
     Monitor *mon;
@@ -3991,13 +3991,19 @@  void monitor_init(CharDriverState *chr, int flags)
     if (monitor_is_qmp(mon)) {
         mon->chr_tag =
             qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
-                                  monitor_qmp_event, mon);
+                                  monitor_qmp_event, mon, NULL, errp);
         qemu_chr_fe_set_echo(chr, true);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
     } else {
         mon->chr_tag =
             qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
-                                  monitor_event, mon);
+                                  monitor_event, mon, NULL, errp);
+    }
+
+    if (mon->chr_tag == -1) {
+        monitor_data_destroy(mon);
+        g_free(mon);
+        return;
     }
 
     qemu_mutex_lock(&monitor_lock);
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 88582c8..58e894b 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -481,21 +481,36 @@  static void *colo_compare_thread(void *opaque)
     GMainContext *worker_context;
     GMainLoop *compare_loop;
     CompareState *s = opaque;
+    Error *err = NULL;
 
     worker_context = g_main_context_new();
 
     s->chr_pri_tag =
-        qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read,
-                                   compare_pri_chr_in, NULL, s, worker_context);
+        qemu_chr_add_handlers(s->chr_pri_in, compare_chr_can_read,
+                              compare_pri_chr_in, NULL, s,
+                              worker_context, &err);
+    if (err) {
+        goto end;
+    }
+
     s->chr_sec_tag =
-        qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read,
-                                   compare_sec_chr_in, NULL, s, worker_context);
+        qemu_chr_add_handlers(s->chr_sec_in, compare_chr_can_read,
+                              compare_sec_chr_in, NULL, s,
+                              worker_context, &err);
+    if (err) {
+        goto end;
+    }
 
     compare_loop = g_main_loop_new(worker_context, FALSE);
 
     g_main_loop_run(compare_loop);
 
     g_main_loop_unref(compare_loop);
+
+end:
+    if (err) {
+        error_report_err(err);
+    }
     g_main_context_unref(worker_context);
     return NULL;
 }
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 8c1d613..13ea039 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -258,7 +258,11 @@  static void filter_redirector_setup(NetFilterState *nf, Error **errp)
         qemu_chr_fe_claim_no_fail(s->chr_in);
         s->chr_in_tag =
             qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read,
-                              redirector_chr_read, redirector_chr_event, nf);
+                                  redirector_chr_read, redirector_chr_event,
+                                  nf, NULL, errp);
+        if (s->chr_in_tag == -1) {
+            return;
+        }
     }
 
     if (s->outdev) {
diff --git a/net/slirp.c b/net/slirp.c
index 80eefb0..355c90c 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -40,6 +40,7 @@ 
 #include "sysemu/char.h"
 #include "sysemu/sysemu.h"
 #include "qemu/cutils.h"
+#include "qapi/error.h"
 
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
 {
@@ -704,6 +705,7 @@  static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
 static int slirp_guestfwd(SlirpState *s, const char *config_str,
                           int legacy_format)
 {
+    Error *err = NULL;
     struct in_addr server = { .s_addr = 0 };
     struct GuestFwd *fwd;
     const char *p;
@@ -768,7 +770,11 @@  static int slirp_guestfwd(SlirpState *s, const char *config_str,
         qemu_chr_fe_claim_no_fail(fwd->hd);
         fwd->chr_tag =
             qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
-                                  NULL, fwd);
+                                  NULL, fwd, NULL, &err);
+        if (fwd->chr_tag < 0) {
+            error_report_err(err);
+            return -1;
+        }
     }
     return 0;
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index f3cf623..804ccb7 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -234,7 +234,7 @@  static void net_vhost_user_event(void *opaque, int event)
 
 static int net_vhost_user_init(NetClientState *peer, const char *device,
                                const char *name, CharDriverState *chr,
-                               int queues)
+                               int queues, Error **errp)
 {
     NetClientState *nc, *nc0 = NULL;
     VhostUserState *s;
@@ -261,11 +261,13 @@  static int net_vhost_user_init(NetClientState *peer, const char *device,
     s = DO_UPCAST(VhostUserState, nc, nc0);
     s->chr_tag =
         qemu_chr_add_handlers(chr, NULL, NULL,
-                              net_vhost_user_event, nc0->name);
+                              net_vhost_user_event, nc0->name, NULL, errp);
+    if (s->chr_tag == -1) {
+        return -1;
+    }
+
     do {
-        Error *err = NULL;
-        if (qemu_chr_wait_connected(chr, &err) < 0) {
-            error_report_err(err);
+        if (qemu_chr_wait_connected(chr, errp) < 0) {
             return -1;
         }
     } while (!s->started);
@@ -351,5 +353,5 @@  int net_init_vhost_user(const Netdev *netdev, const char *name,
         return -1;
     }
 
-    return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
+    return net_vhost_user_init(peer, "vhost_user", name, chr, queues, errp);
 }
diff --git a/qemu-char.c b/qemu-char.c
index 261a8f9..775015b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -487,20 +487,22 @@  qemu_chr_set_handlers(CharDriverState *s,
     }
 }
 
-static int mux_chr_new_handler_tag(CharDriverState *chr, GMainContext *context);
+static int mux_chr_new_handler_tag(CharDriverState *chr, GMainContext *context,
+                                   Error **errp);
 static void mux_set_focus(MuxDriver *d, int focus);
 
-int qemu_chr_add_handlers_full(CharDriverState *s,
-                               IOCanReadHandler *fd_can_read,
-                               IOReadHandler *fd_read,
-                               IOEventHandler *fd_event,
-                               void *opaque,
-                               GMainContext *context)
+int qemu_chr_add_handlers(CharDriverState *s,
+                          IOCanReadHandler *fd_can_read,
+                          IOReadHandler *fd_read,
+                          IOEventHandler *fd_event,
+                          void *opaque,
+                          GMainContext *context,
+                          Error **errp)
 {
     int tag = 0;
 
     if (s->is_mux) {
-        tag = mux_chr_new_handler_tag(s, context);
+        tag = mux_chr_new_handler_tag(s, context, errp);
         if (tag < 0) {
             return tag;
         }
@@ -516,16 +518,6 @@  int qemu_chr_add_handlers_full(CharDriverState *s,
     return tag;
 }
 
-int qemu_chr_add_handlers(CharDriverState *s,
-                          IOCanReadHandler *fd_can_read,
-                          IOReadHandler *fd_read,
-                          IOEventHandler *fd_event,
-                          void *opaque)
-{
-    return qemu_chr_add_handlers_full(s, fd_can_read, fd_read,
-                                      fd_event, opaque, NULL);
-}
-
 void qemu_chr_remove_handlers(CharDriverState *s, int tag)
 {
     if (tag < 0) {
@@ -841,21 +833,25 @@  static void mux_chr_close(struct CharDriverState *chr)
     g_free(d);
 }
 
-static int mux_chr_new_handler_tag(CharDriverState *chr, GMainContext *context)
+static int mux_chr_new_handler_tag(CharDriverState *chr, GMainContext *context,
+                                   Error **errp)
 {
     MuxDriver *d = chr->opaque;
 
     if (d->mux_cnt >= MAX_MUX) {
-        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        error_setg(errp, "Cannot add I/O handlers, MUX array is full");
         return -1;
     }
 
     /* Fix up the real driver with mux routines */
     if (d->mux_tag == -1) {
-        d->mux_tag = qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
-                                                mux_chr_read,
-                                                mux_chr_event,
-                                                chr, context);
+        d->mux_tag = qemu_chr_add_handlers(d->drv, mux_chr_can_read,
+                                           mux_chr_read,
+                                           mux_chr_event,
+                                           chr, context, errp);
+        if (d->mux_tag == -1) {
+            return -1;
+        }
     }
 
     return d->mux_cnt++;
@@ -4090,11 +4086,16 @@  CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
 
     chr = qemu_chr_new_from_opts(opts, init, &err);
     if (err) {
-        error_report_err(err);
+        goto end;
     }
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         qemu_chr_fe_claim_no_fail(chr);
-        monitor_init(chr, MONITOR_USE_READLINE);
+        monitor_init(chr, MONITOR_USE_READLINE, &err);
+    }
+
+end:
+    if (err) {
+        error_report_err(err);
     }
     qemu_opts_del(opts);
     return chr;
diff --git a/qtest.c b/qtest.c
index 73e07c2..e3a2a99 100644
--- a/qtest.c
+++ b/qtest.c
@@ -680,8 +680,11 @@  void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
         qtest_log_fp = stderr;
     }
 
-    qtest_chr_tag =
-        qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
+    qtest_chr_tag = qemu_chr_add_handlers(chr, qtest_can_read, qtest_read,
+                                          qtest_event, chr, NULL, errp);
+    if (qtest_chr_tag == -1) {
+        return;
+    }
     qemu_chr_fe_set_echo(chr, true);
 
     inbuf = g_string_new("");
diff --git a/stubs/monitor-init.c b/stubs/monitor-init.c
index de1bc7c..c24a76f 100644
--- a/stubs/monitor-init.c
+++ b/stubs/monitor-init.c
@@ -2,6 +2,6 @@ 
 #include "qemu-common.h"
 #include "monitor/monitor.h"
 
-void monitor_init(CharDriverState *chr, int flags)
+void monitor_init(CharDriverState *chr, int flags, Error **errp)
 {
 }
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 133cbdc..2e349a8 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -11,6 +11,7 @@ 
 #include "qemu/osdep.h"
 
 #include "libqtest.h"
+#include "qapi/error.h"
 #include "qemu/option.h"
 #include "qemu/range.h"
 #include "qemu/sockets.h"
@@ -461,7 +462,7 @@  static void test_server_create_chr(TestServer *server, const gchar *opt)
 
     server->chr_tag =
         qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
-                              chr_event, server);
+                              chr_event, server, NULL, &error_abort);
 }
 
 static void test_server_listen(TestServer *server)
diff --git a/vl.c b/vl.c
index c657acd..bab77e0 100644
--- a/vl.c
+++ b/vl.c
@@ -2418,7 +2418,7 @@  static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
     }
 
     qemu_chr_fe_claim_no_fail(chr);
-    monitor_init(chr, flags);
+    monitor_init(chr, flags, errp);
     return 0;
 }
 
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index a714d8e..7d31d1b 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -16,7 +16,7 @@  extern Monitor *cur_mon;
 
 bool monitor_cur_is_qmp(void);
 
-void monitor_init(CharDriverState *chr, int flags);
+void monitor_init(CharDriverState *chr, int flags, Error **errp);
 void monitor_cleanup(void);
 
 int monitor_suspend(Monitor *mon);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 9632dbb..2c2083d 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -441,19 +441,12 @@  void qemu_chr_be_event(CharDriverState *s, int event);
  */
 G_GNUC_WARN_UNUSED_RESULT
 int qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanReadHandler *fd_can_read,
-                           IOReadHandler *fd_read,
-                           IOEventHandler *fd_event,
-                           void *opaque);
-
-/* This API can make handler run in the context what you pass to. */
-G_GNUC_WARN_UNUSED_RESULT
-int qemu_chr_add_handlers_full(CharDriverState *s,
-                                IOCanReadHandler *fd_can_read,
-                                IOReadHandler *fd_read,
-                                IOEventHandler *fd_event,
-                                void *opaque,
-                                GMainContext *context);
+                          IOCanReadHandler *fd_can_read,
+                          IOReadHandler *fd_read,
+                          IOEventHandler *fd_event,
+                          void *opaque,
+                          GMainContext *context,
+                          Error **errp);
 
 /**
  * @qemu_chr_remove_handlers: