diff mbox series

bug_fl(): correctly initialize trace2 va_list

Message ID YquMyakxYnU6mI5a@coredump.intra.peff.net (mailing list archive)
State Accepted
Commit f8535596aa7bd7f6862af3fe6420ac12b17c9912
Headers show
Series bug_fl(): correctly initialize trace2 va_list | expand

Commit Message

Jeff King June 16, 2022, 8:04 p.m. UTC
On Thu, Jun 16, 2022 at 03:20:08PM -0400, Jeff King wrote:

> > > The fix Peff's got here LGTM. I can (re)submit it with
> > > format-patch+send-email after giving it a commit message describing the
> > > issue if you'd like, but the change would be the same.
> > 
> > Yup, I think the code change there looks the most sensible.
> 
> I'll wrap it up with a commit message and modify the test to be more
> thorough.

Here it is. This can replace Johannes's patch 11.

-- >8 --
Subject: bug_fl(): correctly initialize trace2 va_list

The code added 0cc05b044f (usage.c: add a non-fatal bug() function to go
with BUG(), 2022-06-02) sets up two va_list variables: one to output to
stderr, and one to trace2. But the order of initialization is wrong:

  va_list ap, cp;
  va_copy(cp, ap);
  va_start(ap, fmt);

We copy the contents of "ap" into "cp" before it is initialized, meaning
it is full of garbage. The two should be swapped.

However, there's another bug, noticed by Johannes Schindelin: we forget
to call va_end() for the copy. So instead of just fixing the copy's
initialization, let's do two separate start/end pairs. This is allowed
by the standard, and we don't need to use copy here since we have access
to the original varargs. Matching the pairs with the calls makes it more
obvious that everything is being done correctly.

Note that we do call bug_fl() in the tests, but it didn't trigger this
problem because our format string doesn't have any placeholders. So even
though we were passing a garbage va_list through the stack, nobody ever
needed to look at it. We can easily adjust one of the trace2 tests to
trigger this, both for bug() and for BUG(). The latter isn't broken, but
it's nice to exercise both a bit more. Without the fix in this patch
(but with the test change), the bug() case causes a segfault.

Signed-off-by: Jeff King <peff@peff.net>
---
 t/helper/test-trace2.c | 4 ++--
 usage.c                | 8 +++++---
 2 files changed, 7 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c
index 180c7f53f3..a714130ece 100644
--- a/t/helper/test-trace2.c
+++ b/t/helper/test-trace2.c
@@ -224,8 +224,8 @@  static int ut_009bug_BUG(int argc, const char **argv)
 
 static int ut_010bug_BUG(int argc, const char **argv)
 {
-	bug("a bug message");
-	BUG("a BUG message");
+	bug("a %s message", "bug");
+	BUG("a %s message", "BUG");
 }
 
 /*
diff --git a/usage.c b/usage.c
index 79900d0287..56e29d6cd6 100644
--- a/usage.c
+++ b/usage.c
@@ -334,15 +334,17 @@  NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...)
 int bug_called_must_BUG;
 void bug_fl(const char *file, int line, const char *fmt, ...)
 {
-	va_list ap, cp;
+	va_list ap;
 
 	bug_called_must_BUG = 1;
 
-	va_copy(cp, ap);
 	va_start(ap, fmt);
 	BUG_vfl_common(file, line, fmt, ap);
 	va_end(ap);
-	trace2_cmd_error_va(fmt, cp);
+
+	va_start(ap, fmt);
+	trace2_cmd_error_va(fmt, ap);
+	va_end(ap);
 }
 
 #ifdef SUPPRESS_ANNOTATED_LEAKS