PASSERT() - asserting for panics

John Baldwin jhb at freebsd.org
Thu Sep 11 17:56:41 UTC 2008


On Wednesday 10 September 2008 08:06:57 pm Matthew Dillon wrote:
> 
> :I think part of the pollution is that what I really want to do is treat a 
> :panic like an exception that I can catch.  I could probably make that idiom 
> :work with two macros so your code can be:
> :
> :	PANIC_TRY {
> :		/* do stuff */
> :	} PANIC_CATCH("foo");
> :
> :That could potentially work with some evil goto's that jumped between the 
> :macros (i.e. have the setjmp() in PANIC_CATCH and PANIC_TRY goto's down to 
> :-- 
> :John Baldwin
> 
>     Hmm.  Almost java-like, where an exception pops back through subroutine
>     levels until it finds a match.  That kind of functionality would be a
>     real mess in C.   A limited form would be possible, something like this:
> 
>     #define PANIC_CATCH(label)			\ (...)
> 	static jmpbuf label # _jmpbuf
> 	if (0) {
> 	    for (;;) {
> 		longjmp(&label # _jmpbuf);
> 		label:
> 
>     #define PANIC_RETRY		}}
> 
>     #define PANIC_PANIC		panic(...); }}
> 
>     #define PASSERT(label, cond)		\ (...)
> 	if (__predict_false(!(cond))) {	
> 		setjmp (&label # _jmpbuf);
> 		goto label;
> 	}
> 
>     PANIC_CATCH(badthings) {
> 	...
> 	PANIC_RETRY;
>     }
> 
>     PANIC_CATCH(badthings) {
> 	...
> 	PANIC_PANIC;
>     }
> 
>     PASSERT(badthings, x == 1);

The problem is I want panics in unmodified code to be caught.  For example, I 
want to write regression tests to make sure assertions on locking primivities 
fail when the state of the lock doesn't match what the assertion is 
requiring.  I can do something fairly simple though that lets me do this:

	PANIC_TRY {
		stuff;
	} PANIC_CATCH {
		IGNORE_PANIC("this one is ok");
		/* WITNESS can do different panics in foo_assert() sometimes */
		IGNORE_PANIC("this one is too");
		UNEXPECTED_PANIC();
	}

Without needing goto's.

>     Which would allow you some control over the context plus allow multiple
>     PASSERT's with the same label.  But, OMG I don't know about doing
>     setjmp/longjmp in the kernel.  I don't think it would be worth it.

We use setjmp already if you get a trap in ddb so ddb doesn't crash.

>     Theoretically one could cross procedural boundaries with the longjmp,
>     and place the jmpbuf in a DATASET and have the kernel glue the longjmp
>     address.  That would be a candidate for the C obfuscation contest
>     though.

To catch unmodified panics, I have to have the longjmp in panic() itself, and 
I have the jmpbuf hung off of curthread.

-- 
John Baldwin


More information about the freebsd-arch mailing list