The following commit has been merged in the master branch:
commit 1a8d12285d650fa4bb13406a515228030d4d9ca1
Author: Guillem Jover <[email protected]>
Date: Wed Sep 30 03:06:55 2009 +0200
libdpkg: Fix varbufprintf to not grow indefinitely
Use the C99 semantics for vsnprintf to get the final formatted string
size, and then call it again to do the actual work. Use varbuf_grow with
the know size, instead of always calling varbufextend, regardles of
needing to extend the buffer, which was making it grow indefinitely.
This also should speed it up a bit by not requiring to call vsnprintf
several times depending on the length of the final string. Only two
calls are required now, always.
diff --git a/debian/changelog b/debian/changelog
index fa8b5eb..870cc0b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -20,6 +20,9 @@ dpkg (1.15.5) UNRELEASED; urgency=low
* Make dpkg as strict as dpkg-statoverride on input when validating the
parsed data from the statdb.
* Rewrite dpkg-statoverride in C.
+ * Use C99 snprintf function family semantics to avoid having to call them
+ in a loop to grow the varbuf buffer. This should reduce memory usage and
+ be slightly faster on varbufprintf calls.
[ Raphaƫl Hertzog ]
* Add versioned dependency on base-files (>= 5.0.0) to dpkg-dev to ensure
diff --git a/lib/dpkg/test/t-varbuf.c b/lib/dpkg/test/t-varbuf.c
index 8d7477c..d6952ff 100644
--- a/lib/dpkg/test/t-varbuf.c
+++ b/lib/dpkg/test/t-varbuf.c
@@ -175,6 +175,33 @@ test_varbuf_substc(void)
}
static void
+test_varbuf_printf(void)
+{
+ struct varbuf vb;
+
+ varbufinit(&vb, 5);
+
+ /* Test normal format printing. */
+ varbufprintf(&vb, "format %s number %d", "string", 10);
+ varbufaddc(&vb, '\0');
+ test_pass(vb.used == sizeof("format string number 10"));
+ test_pass(vb.size >= vb.used);
+ test_str(vb.buf, ==, "format string number 10");
+
+ varbufreset(&vb);
+
+ /* Test concatenated format printing. */
+ varbufprintf(&vb, "format %s number %d", "string", 10);
+ varbufprintf(&vb, " extra %s", "string");
+ varbufaddc(&vb, '\0');
+ test_pass(vb.used == sizeof("format string number 10 extra string"));
+ test_pass(vb.size >= vb.used);
+ test_str(vb.buf, ==, "format string number 10 extra string");
+
+ varbuffree(&vb);
+}
+
+static void
test_varbuf_reset(void)
{
struct varbuf vb;
@@ -205,6 +232,7 @@ test(void)
test_varbuf_addc();
test_varbuf_dupc();
test_varbuf_substc();
+ test_varbuf_printf();
test_varbuf_reset();
/* FIXME: Complete. */
diff --git a/lib/dpkg/varbuf.c b/lib/dpkg/varbuf.c
index f83f35b..fa1ae57 100644
--- a/lib/dpkg/varbuf.c
+++ b/lib/dpkg/varbuf.c
@@ -69,21 +69,27 @@ int varbufprintf(struct varbuf *v, const char *fmt, ...) {
}
int varbufvprintf(struct varbuf *v, const char *fmt, va_list va) {
- size_t ou;
- int r;
va_list al;
+ int needed, r;
+
+ va_copy(al, va);
+ needed = vsnprintf(NULL, 0, fmt, al);
+ va_end(al);
+
+ if (needed < 0)
+ ohshite("error printing into varbuf variable");
+
+ varbuf_grow(v, needed + 1);
+
+ va_copy(al, va);
+ r = vsnprintf(v->buf + v->used, needed + 1, fmt, al);
+ va_end(al);
+
+ if (r < 0)
+ ohshite("error printing into varbuf variable");
+
+ v->used += r;
- ou= v->used;
- v->used+= strlen(fmt);
-
- do {
- varbufextend(v);
- va_copy(al, va);
- r= vsnprintf(v->buf+ou,v->size-ou,fmt,al);
- va_end(al);
- if (r < 0) r= (v->size-ou+1) * 2;
- v->used= ou+r;
- } while (r >= (int)(v->size - ou - 1));
return r;
}
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]