Module Name:    src
Committed By:   riastradh
Date:           Mon Aug 18 03:43:10 UTC 2014

Modified Files:
        src/sys/dev/ic: oosiop.c

Log Message:
Fix leaks in oosiop_alloc_cb error branches, noted by maxv@.

While here, avoid a sketchy pointer cast that probably falls afoul of
strict aliasing rules.

Compile-tested only, with hppa.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/dev/ic/oosiop.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/oosiop.c
diff -u src/sys/dev/ic/oosiop.c:1.13 src/sys/dev/ic/oosiop.c:1.14
--- src/sys/dev/ic/oosiop.c:1.13	Sat Nov 13 13:52:02 2010
+++ src/sys/dev/ic/oosiop.c	Mon Aug 18 03:43:10 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: oosiop.c,v 1.13 2010/11/13 13:52:02 uebayasi Exp $	*/
+/*	$NetBSD: oosiop.c,v 1.14 2014/08/18 03:43:10 riastradh Exp $	*/
 
 /*
  * Copyright (c) 2001 Shuichiro URATA.  All rights reserved.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.13 2010/11/13 13:52:02 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.14 2014/08/18 03:43:10 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -247,6 +247,7 @@ static int
 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
 {
 	struct oosiop_cb *cb;
+	void *xfer_kva;
 	struct oosiop_xfer *xfer;
 	bus_size_t xfersize;
 	bus_dma_segment_t seg;
@@ -258,7 +259,8 @@ oosiop_alloc_cb(struct oosiop_softc *sc,
 	cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT|M_ZERO);
 	if (cb == NULL) {
 		printf(": failed to allocate cb memory\n");
-		return (ENOMEM);
+		err = ENOMEM;
+		goto fail0;
 	}
 
 	/*
@@ -269,57 +271,79 @@ oosiop_alloc_cb(struct oosiop_softc *sc,
 	    &nseg, BUS_DMA_NOWAIT);
 	if (err) {
 		printf(": failed to allocate xfer block memory, err=%d\n", err);
-		return (err);
+		goto fail1;
 	}
-	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
-	    (void **)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
+	KASSERT(nseg == 1);
+	err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, &xfer_kva,
+	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
 	if (err) {
 		printf(": failed to map xfer block memory, err=%d\n", err);
-		return (err);
+		goto fail2;
 	}
+	xfer = xfer_kva;
 
 	/* Initialize each command block */
 	for (i = 0; i < ncb; i++) {
 		err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
-		    0, BUS_DMA_NOWAIT, &cb->cmddma);
+		    0, BUS_DMA_NOWAIT, &cb[i].cmddma);
 		if (err) {
 			printf(": failed to create cmddma map, err=%d\n", err);
-			return (err);
+			goto loop_fail0;
 		}
 		err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
 		    OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
-		    &cb->datadma);
+		    &cb[i].datadma);
 		if (err) {
 			printf(": failed to create datadma map, err=%d\n", err);
-			return (err);
+			goto loop_fail1;
 		}
 
 		err = bus_dmamap_create(sc->sc_dmat,
 		    sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
-		    0, BUS_DMA_NOWAIT, &cb->xferdma);
+		    0, BUS_DMA_NOWAIT, &cb[i].xferdma);
 		if (err) {
 			printf(": failed to create xfer block map, err=%d\n",
 			    err);
-			return (err);
+			goto loop_fail2;
 		}
-		err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
+		err = bus_dmamap_load(sc->sc_dmat, cb[i].xferdma, xfer,
 		    sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
 		if (err) {
 			printf(": failed to load xfer block, err=%d\n", err);
-			return (err);
+			goto loop_fail3;
 		}
 
-		cb->xfer = xfer;
+		cb[i].xfer = &xfer[i];
+		continue;
 
+loop_fail4: __unused
+		bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
+loop_fail3:	bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
+loop_fail2:	bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
+loop_fail1:	bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
+loop_fail0:	goto fail3;
+	}
+
+	for (i = 0; i < ncb; i++) {
 		s = splbio();
-		TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
+		TAILQ_INSERT_TAIL(&sc->sc_free_cb, &cb[i], chain);
 		splx(s);
-
-		cb++;
-		xfer++;
 	}
 
-	return (0);
+	/* Success!  */
+	return 0;
+
+fail3:	while (i--) {
+		bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
+		bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
+		bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
+		bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
+	}
+	bus_dmamem_unmap(sc->sc_dmat, xfer_kva, xfersize);
+fail2:	bus_dmamem_free(sc->sc_dmat, &seg, 1);
+fail1:	free(cb, M_DEVBUF);
+fail0:	KASSERT(err);
+	return err;
 }
 
 static inline void

Reply via email to