From owner-freebsd-bugs@FreeBSD.ORG Thu Jan 3 16:30:04 2008 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1FCD516A421 for ; Thu, 3 Jan 2008 16:30:04 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id F17F113C4E7 for ; Thu, 3 Jan 2008 16:30:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id m03GU3Nq052536 for ; Thu, 3 Jan 2008 16:30:03 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id m03GU305052531; Thu, 3 Jan 2008 16:30:03 GMT (envelope-from gnats) Resent-Date: Thu, 3 Jan 2008 16:30:03 GMT Resent-Message-Id: <200801031630.m03GU305052531@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Doug Moore Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6505316A420 for ; Thu, 3 Jan 2008 16:28:46 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 545BD13C46A for ; Thu, 3 Jan 2008 16:28:46 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id m03GSkLA052316 for ; Thu, 3 Jan 2008 16:28:46 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id m03GSkU2052315; Thu, 3 Jan 2008 16:28:46 GMT (envelope-from gnats) Message-Id: <200801031628.m03GSkU2052315@freefall.freebsd.org> Date: Thu, 3 Jan 2008 16:28:46 GMT From: Doug Moore To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: kern/119307: TRASHIT macro blasts list header if REMOVE invoked with header ref X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Doug Moore List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Jan 2008 16:30:04 -0000 >Number: 119307 >Category: kern >Synopsis: TRASHIT macro blasts list header if REMOVE invoked with header ref >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Jan 03 16:30:03 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Doug Moore >Release: FreeBSD 7.0-CURRENT i386 >Organization: >Environment: System: FreeBSD adsl-216-63-78-19.dsl.hstntx.swbell.net 7.0-CURRENT FreeBSD 7.0-CURRENT #5: Sat Sep 15 00:42:55 CDT 2007 root@adsl-216-63-78-19.dsl.hstntx.swbell.net:/usr/src/sys/i386/compile/ATHEROS i386 >Description: A line like TAILQ_REMOVE(&a->tailq, a->tailq.tqh_first, next); will corrupt the tailq in question if QUEUE_MACRO_DEBUG is on, since after the first tailq item is removed, it is the *new* first tailq item that gets its prev and next pointers trashed. With QUEUE_MACRO_DEBUG off, it removes the first tailq as expected. Therefore, turning on QUEUE_MACRO_DEBUG corrupts the tailq. >How-To-Repeat: Write a self-referential invocation of a removal from tailq, list, etc, and add a couple of items to the list before invoking that removal. >Fix: Use typeof to bind the value of the to-be-removed element to a name, and use that name in the pointer trashing and other debugging code. If typeof is forbidden, then it would seem to require adding type arguments to several macros, a bad thing. --- queue.h.diff begins here --- --- queue.h 2008-01-02 22:53:54.000000000 -0600 +++ queue.h.new 2008-01-02 23:02:28.000000000 -0600 @@ -188,6 +188,7 @@ struct { \ #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_REMOVE(head, elm, type, field) do { \ + typeof (elm) oldelm = (elm); \ if (SLIST_FIRST((head)) == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ @@ -198,7 +199,7 @@ struct { \ SLIST_NEXT(curelm, field) = \ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ } \ - TRASHIT((elm)->field.sle_next); \ + TRASHIT(oldelm->field.sle_next); \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ @@ -280,6 +281,7 @@ struct { \ #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_REMOVE(head, elm, type, field) do { \ + typeof (elm) oldelm = (elm); \ if (STAILQ_FIRST((head)) == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } \ @@ -291,7 +293,7 @@ struct { \ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ } \ - TRASHIT((elm)->field.stqe_next); \ + TRASHIT(oldelm->field.stqe_next); \ } while (0) #define STAILQ_REMOVE_HEAD(head, field) do { \ @@ -392,14 +394,15 @@ struct { \ #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ + typeof (elm) oldelm = (elm); \ QMD_LIST_CHECK_NEXT(elm, field); \ QMD_LIST_CHECK_PREV(elm, field); \ if (LIST_NEXT((elm), field) != NULL) \ LIST_NEXT((elm), field)->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT((elm)->field.le_next); \ - TRASHIT((elm)->field.le_prev); \ + TRASHIT(oldelm->field.le_next); \ + TRASHIT(oldelm->field.le_prev); \ } while (0) /* @@ -554,6 +557,7 @@ struct { \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_REMOVE(head, elm, field) do { \ + typeof (elm) oldelm = (elm); \ QMD_TAILQ_CHECK_NEXT(elm, field); \ QMD_TAILQ_CHECK_PREV(elm, field); \ if ((TAILQ_NEXT((elm), field)) != NULL) \ @@ -564,9 +568,9 @@ struct { \ QMD_TRACE_HEAD(head); \ } \ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT((elm)->field.tqe_next); \ - TRASHIT((elm)->field.tqe_prev); \ - QMD_TRACE_ELEM(&(elm)->field); \ + TRASHIT(oldelm->field.tqe_next); \ + TRASHIT(oldelm->field.tqe_prev); \ + QMD_TRACE_ELEM(&oldelm->field); \ } while (0) --- queue.h.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted: