Messages in this thread | | | From | Kyle Moffett <> | Subject | Re: [PATCH 1/4] stringbuf: A string buffer implementation | Date | Wed, 24 Oct 2007 20:07:23 -0400 |
| |
On Oct 24, 2007, at 17:21:10, Matthew Wilcox wrote: > On Wed, Oct 24, 2007 at 04:59:48PM -0400, Kyle Moffett wrote: >> This seems unlikely to work reliably as the various "v*printf" >> functions modify the va_list argument they are passed. It may >> happen to work on your particular architecture depending on how >> that argument data is passed and stored, but you probably actually >> want to make a copy of the varargs list for the first vsnprintf call. > > I based what I did on how printk works: > > va_start(args, fmt); > r = vprintk(fmt, args); > va_end(args); > > It doesn't call va_* anywhere else. I don't claim to be a varargs > expert, but if I'm wrong, I'm at least wrong the same way that > printk is, so not in any way that's significant for any other > architecture Linux runs on.
No, the problem is what happens when you don't have enough space allocated: you call "vsnprintf(s, len, format, args);" and then later call "vsprintf(s, format, args);" with the *SAME* "args". That's what's broken.
So this is wrong: > va_list args; > va_start(args, fmt); > r1 = vprintk(fmt, args); > r2 = vprintk(fmt, args); > va_end(args);
To fix it, you have 2 options.
Option 1: > va_list args; > va_start(args, fmt); > r1 = vprintk(fmt, args); > va_end(args); > va_start(args, fmt); > r2 = vprintk(fmt, args); > va_end(args);
Option 2: > va_list args, argscopy; > va_start(args, fmt); > va_copy(argscopy, args); > r1 = vprintk(fmt, argscopy); > va_end(argscopy); > r2 = vprintk(fmt, args); > va_end(args);
Now in a function which *receives* a va_list from one of its callers, "Option 1" isn't an option because you don't have the original stack frame, so the result looks like this:
> void func1(const char *fmt, ...) > { > va_list ap; > va_start(ap, fmt); > func2(fmt, ap); > va_end(ap); > } > > void func2(const char *fmt, va_list ap) > { > va_list ap2; > va_copy(ap2, ap); > vprintk(fmt, ap2); > va_end(ap2); > vprintk(fmt, ap); > }
Cheers, Kyle Moffett
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |