tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: KASSERTMSG fix



On 08.09.2011 14:27, Joerg Sonnenberger wrote:
> On Thu, Sep 08, 2011 at 02:06:29PM +0200, Jean-Yves Migeon wrote:
>> I can't expect the kernel to be in a good shape when it calls panic(9)
>> so allocating/copying strings is not possible. So it has to be done at
>> compile time, or the use of panicstr has to be changed.
> 
> There is no reason to allocate a string, just reserve e.g. 160 Bytes or
> so and use snprintf to that. But yes, the current usage is suboptimal.

So let's make it a little bit more helpful: see panicstr.diff.

Summary about my discussion regarding KASSERTMSG(): in its current form
it cannot append the msg passed as argument to it to the panic format
string, which makes it rather impractical: we fail to log the file,
line, expression that triggered the assertion and worse, it does not
conform to its description in KASSERT(9).

It would be very practical to append "msg" to the panic string while
keeping its usefulness: "msg" can specify a format string with optional
arguments (helpful when you are interested in more information that the
assertion alone).

Joerg proposed to introduce a panic_verbose(9) function which is a
panic(9) function enhanced with additional arguments:

panic_verbose(__FILE__, __LINE__, #e, fmt, ##__VA_ARGS__)

This needs to (re)write the string parsing parts of panic(9) to cope
with the additional arguments. I can't simply add a wrapper around
panic(9) with a scratch string for that, concurrent callers could
completely thrash it (due to preemptions etc).

I am not really convinced that we should touch panic(9) to provide
KASSERTMSG() functionality. IMHO we cannot predict future uses and
adapting the prototype each time is cumbersome, especially as
KASSERTMSG(...) isn't widely used throughout the kernel.

Having two format strings in the prototype is a possibility (pointed by
Mouse). va_* plays is something I'd like to keep to the kprintf(9)
functions though.

So I am back with the __VA_ARGS__ tricks; with the attached patch and
all the KASSERT call sites fixed, the ALL kernel size is actually
smaller... ?

# vanilla
16862719 Sep  8 16:26
/home/jym/cvs/src/../obj/sys/arch/i386/compile/ALL/netbsd

# the one with KASSERTMSG patch and fixed call sites
16838041 Sep  8 17:51
/home/jym/cvs/src/../obj/sys/arch/i386/compile/ALL/netbsd

-- 
Jean-Yves Migeon
jeanyves.migeon%free.fr@localhost

Index: sys/kern/subr_prf.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_prf.c,v
retrieving revision 1.141
diff -u -p -r1.141 subr_prf.c
--- sys/kern/subr_prf.c 17 Jul 2011 20:54:52 -0000      1.141
+++ sys/kern/subr_prf.c 8 Sep 2011 13:31:50 -0000
@@ -203,6 +203,7 @@ panic(const char *fmt, ...)
        struct cpu_info *ci, *oci;
        int bootopt;
        va_list ap;
+       static char scratchstr[160]; /* stores panic message */
 
        spldebug_stop();
 
@@ -242,18 +243,23 @@ panic(const char *fmt, ...)
        } else
                printf("Skipping crash dump on recursive panic\n");
 
-       if (!panicstr)
-               panicstr = fmt;
        doing_shutdown = 1;
 
        if (msgbufenabled && msgbufp->msg_magic == MSG_MAGIC)
                panicstart = msgbufp->msg_bufx;
 
-       va_start(ap, fmt);
        printf("panic: ");
-       vprintf(fmt, ap);
-       printf("\n");
+       va_start(ap, fmt);
+       if (panicstr == NULL) {
+               /* first time in panic */
+               panicstr = scratchstr;
+               vsnprintf(scratchstr, sizeof(scratchstr), fmt, ap);
+               printf("%s", scratchstr);
+       } else {
+               vprintf(fmt, ap);
+       }
        va_end(ap);
+       printf("\n");
 
        if (msgbufenabled && msgbufp->msg_magic == MSG_MAGIC)
                panicend = msgbufp->msg_bufx;

Index: sys/lib/libkern/libkern.h
===================================================================
RCS file: /cvsroot/src/sys/lib/libkern/libkern.h,v
retrieving revision 1.99
diff -u -p -u -p -r1.99 libkern.h
--- sys/lib/libkern/libkern.h   1 Sep 2011 22:35:17 -0000       1.99
+++ sys/lib/libkern/libkern.h   8 Sep 2011 15:58:19 -0000
@@ -174,15 +174,17 @@ tolower(int ch)
 
 #define        __NULL_STMT             do { } while (/* CONSTCOND */ 0)
 
+#define ASSERTSTR "kernel %sassertion \"%s\" failed: file \"%s\", line %d "
+
 #ifdef NDEBUG                                          /* tradition! */
 #define        assert(e)       ((void)0)
 #else
 #ifdef __STDC__
 #define        assert(e)       (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("", __FILE__, __LINE__, #e))
+                           panic(ASSERTSTR, "", #e, __FILE__, __LINE__))
 #else
 #define        assert(e)       (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("", __FILE__, __LINE__, "e"))
+                           panic(ASSERTSTR, "", "e", __FILE__, __LINE__))
 #endif
 #endif
 
@@ -197,46 +199,50 @@ tolower(int ch)
 #ifndef DIAGNOSTIC
 #define _DIAGASSERT(a) (void)0
 #ifdef lint
-#define        KASSERTMSG(e, msg)      /* NOTHING */
+#define        KASSERTMSG(e, msg, ...) /* NOTHING */
 #define        KASSERT(e)              /* NOTHING */
 #else /* !lint */
-#define        KASSERTMSG(e, msg)      ((void)0)
+#define        KASSERTMSG(e, msg, ...) ((void)0)
 #define        KASSERT(e)              ((void)0)
 #endif /* !lint */
 #else /* DIAGNOSTIC */
 #define _DIAGASSERT(a) assert(a)
-#define        KASSERTMSG(e, msg) do {         \
-       if (__predict_false(!(e)))      \
-               panic msg;              \
-       } while (/*CONSTCOND*/ 0)
+#define        KASSERTMSG(e, msg, ...)         \
+                       (__predict_true((e)) ? (void)0 :                    \
+                           panic(ASSERTSTR msg, "diagnostic ", #e,         \
+                               __FILE__, __LINE__, ## __VA_ARGS__))
 #ifdef __STDC__
 #define        KASSERT(e)      (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("diagnostic ", __FILE__, __LINE__, #e))
+                           panic(ASSERTSTR, "diagnostic ", #e,             \
+                               __FILE__, __LINE__))
 #else
 #define        KASSERT(e)      (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("diagnostic ", __FILE__, __LINE__,"e"))
+                           panic(ASSERTSTR, "diagnostic ", "e",            \
+                               __FILE__, __LINE__))
 #endif
 #endif
 
 #ifndef DEBUG
 #ifdef lint
-#define        KDASSERTMSG(e,msg)      /* NOTHING */
+#define        KDASSERTMSG(e,msg, ...) /* NOTHING */
 #define        KDASSERT(e)             /* NOTHING */
 #else /* lint */
-#define        KDASSERTMSG(e,msg)      ((void)0)
+#define        KDASSERTMSG(e,msg, ...) ((void)0)
 #define        KDASSERT(e)             ((void)0)
 #endif /* lint */
 #else
-#define        KDASSERTMSG(e, msg) do {        \
-       if (__predict_false(!(e)))      \
-               panic msg;              \
-       } while (/*CONSTCOND*/ 0)
+#define        KDASSERTMSG(e, msg, ...)        \
+                       (__predict_true((e)) ? (void)0 :                    \
+                           panic(ASSERTSTR msg, "debugging ", #e,          \
+                               __FILE__, __LINE__, ## __VA_ARGS__))
 #ifdef __STDC__
 #define        KDASSERT(e)     (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("debugging ", __FILE__, __LINE__, #e))
+                           panic(ASSERTSTR, "debugging ", #e,              \
+                               __FILE__, __LINE__))
 #else
 #define        KDASSERT(e)     (__predict_true((e)) ? (void)0 :                
    \
-                           kern_assert("debugging ", __FILE__, __LINE__, "e"))
+                           panic(ASSERTSTR, "debugging ", "e",             \
+                               __FILE__, __LINE__))
 #endif
 #endif
 /*


Home | Main Index | Thread Index | Old Index