Skip to contentSkip to conversation

struct argv overhaul

PATCH New Heiko Hund 5 participants 35 messages Oct 28, 2016 – Oct 7, 2018

lore
Share & tools
lore

Heiko Hund

author
#0 lore raw

PATCH 1/1 struct argv overhaul

Hi

This series is a direct outcome of the incident with my previous patch. I've taken on struct argv and related functions and made them like I please.

For a more detailed description what's happening see the comments in the individual patches:

[PATCH 1/7] put argv_* functions into own file, add unit tests [PATCH 2/7] Remove unused and unecessary argv interfaces [PATCH 3/7] remove unused system_str from struct argv [PATCH 4/7] Factor out %sc handling from argv_printf() [PATCH 5/7] re-implement argv_printf_*()
[PATCH 6/7] argv: do fewer memory re-allocations [PATCH 7/7] Add gc_arena to struct argv to save allocations

Code hase only been unit tested, so I'd really also like feedback from someone actually running the code. And if it be buildbot...

Cheers
Heiko

author
#1 lore raw

PATCH 1/7 put argv_* functions into own file, add unit tests

misc.c is too crowded with different things to perform any sane unit testing due to its dependencies. So, in order to re-write the #ifdef'ed tests for the argv_* family of functions into unit tests I moved them into a dedicated file.

---
 configure.ac                         |   1 +
 src/openvpn/Makefile.am              |   1 +
 src/openvpn/argv.c                   | 412 +++++++++++++++++++++++++++++++
 src/openvpn/argv.h                   |  76 ++++++
 src/openvpn/misc.c                   | 459 -----------------------------------
 src/openvpn/misc.h                   |  48 +---
 tests/unit_tests/Makefile.am         |   2 +-
 tests/unit_tests/openvpn/Makefile.am |  15 ++
 tests/unit_tests/openvpn/test_argv.c | 194 +++++++++++++++
 9 files changed, 701 insertions(+), 507 deletions(-)
 create mode 100644 src/openvpn/argv.c
 create mode 100644 src/openvpn/argv.h
 create mode 100644 tests/unit_tests/openvpn/Makefile.am
 create mode 100644 tests/unit_tests/openvpn/test_argv.c
configure.ac +1 -0
index 357ba29..a42257a 100644
@@ -1273,6 +1273,7 @@ AC_CONFIG_FILES([
         tests/unit_tests/plugins/Makefile
         tests/unit_tests/plugins/auth-pam/Makefile
         tests/unit_tests/example_test/Makefile
+        tests/unit_tests/openvpn/Makefile
         vendor/Makefile
 	sample/Makefile
 	doc/Makefile
src/openvpn/Makefile.am +1 -0
index a306726..12b9ebf 100644
@@ -36,6 +36,7 @@ endif
 sbin_PROGRAMS = openvpn
 
 openvpn_SOURCES = \
+	argv.c argv.h \
 	base64.c base64.h \
 	basic.h \
 	buffer.c buffer.h \
src/openvpn/argv.c new file +412 -0

412 lines not on this page · raw message

src/openvpn/argv.h new file +76 -0

76 lines not on this page · raw message

src/openvpn/misc.c +0 -459

465 lines not on this page · raw message

src/openvpn/misc.h +1 -47

66 lines not on this page · raw message

tests/unit_tests/Makefile.am +1 -1
index 8868c1c..44ab26b 100644
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
 
 if CMOCKA_INITIALIZED
-SUBDIRS = example_test plugins
+SUBDIRS = example_test plugins openvpn
 endif
tests/unit_tests/openvpn/Makefile.am new file +15 -0
new file mode 100644
index 0000000..af7f12f
@@ -0,0 +1,15 @@
+AUTOMAKE_OPTIONS = foreign
+
+check_PROGRAMS = argv_testdriver
+
+TESTS = $(check_PROGRAMS)
+
+openvpn_srcdir = $(top_srcdir)/src/openvpn
+compat_srcdir = $(top_srcdir)/src/compat
+
+argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir)
+argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line
+argv_testdriver_SOURCES = test_argv.c \
+	$(openvpn_srcdir)/platform.c \
+	$(openvpn_srcdir)/buffer.c \
+	$(openvpn_srcdir)/argv.c
tests/unit_tests/openvpn/test_argv.c new file +194 -0

194 lines not on this page · raw message

Signature · 1 line
2.7.4
#2 lore raw

Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests

Quoted 6 lines · Heiko Hund

misc.c is too crowded with different things to perform any sane unit testing due to its dependencies. So, in order to re-write the #ifdef'ed tests for the argv_* family of functions into unit tests I moved them into a dedicated file.

Quoted 16 lines
---
 configure.ac                         |   1 +
 src/openvpn/Makefile.am              |   1 +
 src/openvpn/argv.c                   | 412 +++++++++++++++++++++++++++++++
 src/openvpn/argv.h                   |  76 ++++++
 src/openvpn/misc.c                   | 459 -----------------------------------
 src/openvpn/misc.h                   |  48 +---
 tests/unit_tests/Makefile.am         |   2 +-
 tests/unit_tests/openvpn/Makefile.am |  15 ++
 tests/unit_tests/openvpn/test_argv.c | 194 +++++++++++++++
 9 files changed, 701 insertions(+), 507 deletions(-)
 create mode 100644 src/openvpn/argv.c
 create mode 100644 src/openvpn/argv.h
 create mode 100644 tests/unit_tests/openvpn/Makefile.am
 create mode 100644 tests/unit_tests/openvpn/test_argv.c

ACK. Reviewed that all argv_* functions and the related code is just moved from misc.[ch] to argv.[ch]. One minor change was detected, but it makes sense: The argv_clone() function is not declared static in argv.c. This makes sense as it is only used in this scope.

Good to see that we have proper unit testing on argv.c too! These tests doesn't test all functions explicitly, but the majority of them will be tested indirectly through the other calls. The exception is argv_reset(), which I've understood will be changed further later on in this process.

I will wait with applying this patch to the git tree until all the other patches in this series have been reviewed and ACKed.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#3 lore raw

Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests

Hi,

Quoted 2 lines · David Sommerseth

I will wait with applying this patch to the git tree until all the other patches in this series have been reviewed and ACKed.

Actually, this patch does not need the follow-up patches, right? In that case, I would strongly prefer if we didn't wait with applying it. I say this because my --tls-crypt patch set also includes src/openvpn/* unit tests, and it would be a lot better if I could rebase that patch set on this patch before sending it to the list. (Less work for the maintainers, and makes my patch set slightly easier to review.)

-Steffan

#4 lore raw

Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests

In reply to Heiko Hund

Hi,

I didn't look at the code itself (David already did), but two very minor nitpicks I ran into while rebasing my src/openvpn/* unit tests on this patch:

configure.ac AC_CONFIG_FILES([ · line 1277

Quoted 8 lines · Heiko Hund
configure.ac +1 -0
@@ -1273,6 +1273,7 @@ AC_CONFIG_FILES([
         tests/unit_tests/plugins/Makefile
         tests/unit_tests/plugins/auth-pam/Makefile
         tests/unit_tests/example_test/Makefile
+        tests/unit_tests/openvpn/Makefile
         vendor/Makefile

Could we keep this ordering alphabetical? (And fix the example_test occurrence as we go?)

tests/unit_tests/Makefile.am line 5

Quoted 11 lines
tests/unit_tests/Makefile.am +1 -1
index 8868c1c..44ab26b 100644
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
 
 if CMOCKA_INITIALIZED
-SUBDIRS = example_test plugins
+SUBDIRS = example_test plugins openvpn
 endif

Here too alphabetical ordering would be a little nicer.

Maybe David can tackle this when applying?

-Steffan

#5 lore raw

Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests

Hi,

Quoted 5 lines · Steffan Karger

I didn't look at the code itself (David already did), but two very minor nitpicks I ran into while rebasing my src/openvpn/* unit tests on this patch:

[..]

Apart from this, I noticed that builds that depend on OPENSSL_CFLAGS/MBEDTLS_CFLAGS (or LIBS) would fail to compile the testdriver. Attached a proposed fixup that fixes both me previous nitpicks as well as the test driver build. Feel free to squash into the original patch if you agree.

-Steffan

From f2214b435cc4a63cf7a58c78915f445feb9ae014 Mon Sep 17 00:00:00 2001
From: Steffan Karger <[email protected]...>
Date: Tue, 8 Nov 2016 14:42:24 +0100
Subject: [PATCH] argv_test fixups

---
 configure.ac                         | 4 ++--
 tests/unit_tests/Makefile.am         | 2 +-
 tests/unit_tests/openvpn/Makefile.am | 6 ++++--
 3 files changed, 7 insertions(+), 5 deletions(-)
configure.ac +2 -2
index a42257a..bd6797c 100644
@@ -1270,10 +1270,10 @@ AC_CONFIG_FILES([
 	src/plugins/down-root/Makefile
 	tests/Makefile
         tests/unit_tests/Makefile
-        tests/unit_tests/plugins/Makefile
-        tests/unit_tests/plugins/auth-pam/Makefile
         tests/unit_tests/example_test/Makefile
         tests/unit_tests/openvpn/Makefile
+        tests/unit_tests/plugins/Makefile
+        tests/unit_tests/plugins/auth-pam/Makefile
         vendor/Makefile
 	sample/Makefile
 	doc/Makefile
tests/unit_tests/Makefile.am +1 -1
index 44ab26b..31d37b8 100644
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
 
 if CMOCKA_INITIALIZED
-SUBDIRS = example_test plugins openvpn
+SUBDIRS = example_test openvpn plugins
 endif
tests/unit_tests/openvpn/Makefile.am +4 -2
index af7f12f..b706fae 100644
@@ -7,8 +7,10 @@ TESTS = $(check_PROGRAMS)
 openvpn_srcdir = $(top_srcdir)/src/openvpn
 compat_srcdir = $(top_srcdir)/src/compat
 
-argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir)
-argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line
+argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \
+	$(OPTIONAL_CRYPTO_CFLAGS)
+argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \
+	$(OPTIONAL_CRYPTO_LIBS)
 argv_testdriver_SOURCES = test_argv.c \
 	$(openvpn_srcdir)/platform.c \
 	$(openvpn_srcdir)/buffer.c \
Signature · 1 line
2.7.4
#6 lore raw

[Openvpn-devel] [PATCH applied] Re: put argv_* functions into own file, add unit tests

In reply to Heiko Hund

Your patch has been applied to the master branch.

commit 698e268afb53014614f8e90ac8ff0667ce5e555d

Author: Heiko Hund
Date:   Fri Oct 28 18:42:37 2016 +0200
     put argv_* functions into own file, add unit tests

     Signed-off-by: Heiko Hund <[email protected]...>
     Acked-by: David Sommerseth <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg12811.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#7 lore raw

PATCH 1/1 Make argv unit tests obey {MBEDTLS, OPENSSL}_{LIBS, CFLAGS}

Fixes builds that use MBEDTLS_CFLAGS and friends to tell the build where the header files and libraries are. Also alphabetically orders some of the listed files in relates Makefile.am files.

---
 configure.ac                         | 4 ++--
 tests/unit_tests/Makefile.am         | 2 +-
 tests/unit_tests/openvpn/Makefile.am | 6 ++++--
 3 files changed, 7 insertions(+), 5 deletions(-)
configure.ac +2 -2
index a42257a..bd6797c 100644
@@ -1270,10 +1270,10 @@ AC_CONFIG_FILES([
 	src/plugins/down-root/Makefile
 	tests/Makefile
         tests/unit_tests/Makefile
-        tests/unit_tests/plugins/Makefile
-        tests/unit_tests/plugins/auth-pam/Makefile
         tests/unit_tests/example_test/Makefile
         tests/unit_tests/openvpn/Makefile
+        tests/unit_tests/plugins/Makefile
+        tests/unit_tests/plugins/auth-pam/Makefile
         vendor/Makefile
 	sample/Makefile
 	doc/Makefile
tests/unit_tests/Makefile.am +1 -1
index 44ab26b..31d37b8 100644
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
 
 if CMOCKA_INITIALIZED
-SUBDIRS = example_test plugins openvpn
+SUBDIRS = example_test openvpn plugins
 endif
tests/unit_tests/openvpn/Makefile.am +4 -2
index af7f12f..b706fae 100644
@@ -7,8 +7,10 @@ TESTS = $(check_PROGRAMS)
 openvpn_srcdir = $(top_srcdir)/src/openvpn
 compat_srcdir = $(top_srcdir)/src/compat
 
-argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir)
-argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line
+argv_testdriver_CFLAGS  = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \
+	$(OPTIONAL_CRYPTO_CFLAGS)
+argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \
+	$(OPTIONAL_CRYPTO_LIBS)
 argv_testdriver_SOURCES = test_argv.c \
 	$(openvpn_srcdir)/platform.c \
 	$(openvpn_srcdir)/buffer.c \
Signature · 1 line
2.7.4
#8 lore raw

[Openvpn-devel] [PATCH applied] Re: Make argv unit tests obey {MBEDTLS, OPENSSL}_{LIBS, CFLAGS}

ACK. As discussed beforehand, forgot to apply.

Your patch has been applied to the master branch.

commit ac42df1a2e53e84c67397989df3f0650bed3ae7a

Author: Steffan Karger
Date:   Mon Nov 14 20:43:23 2016 +0100
     Make argv unit tests obey {MBEDTLS, OPENSSL}_{LIBS, CFLAGS}

     Signed-off-by: Steffan Karger <[email protected]...>
     Acked-by: Gert Doering <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg13050.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

author
#9 lore raw

PATCH 2/7 Remove unused and unecessary argv interfaces

In reply to Heiko Hund
---
 src/openvpn/argv.c            | 53 +++++++++++++++++++------------------------
 src/openvpn/argv.h            |  6 -----
 src/openvpn/console_systemd.c |  3 +--
 src/openvpn/route.c           | 12 ++++------
 src/openvpn/tun.c             | 42 +++++++++++-----------------------
 5 files changed, 41 insertions(+), 75 deletions(-)
src/openvpn/argv.c +23 -30
index 60534ac..89c9b14 100644
@@ -39,7 +39,7 @@
 #include "argv.h"
 #include "options.h"
 
-void
+static void
 argv_init (struct argv *a)
 {
   a->capacity = 0;
@@ -157,12 +157,6 @@ argv_extract_cmd_name (const char *path)
   return ret;
 }
 
-const char *
-argv_system_str (const struct argv *a)
-{
-  return a->system_str;
-}
-
 static struct argv
 argv_clone (const struct argv *a, const size_t headroom)
 {
@@ -199,7 +193,7 @@ argv_insert_head (const struct argv *a, const char *head)
   return r;
 }
 
-char *
+static char *
 argv_term (const char **f)
 {
   const char *p = *f;
@@ -272,33 +266,13 @@ argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
   gc_free (&gc);
 }
 
-void
-argv_printf (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, 0, arglist);
-  va_end (arglist);
- }
-
-void
-argv_printf_cat (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, APA_CAT, arglist);
-  va_end (arglist);
-}
-
-void
-argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
+static void
+argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
 {
   struct gc_arena gc = gc_new ();
   char *term;
   const char *f = format;
 
-  if (!(flags & APA_CAT))
-    argv_reset (a);
   argv_extend (a, 1); /* ensure trailing NULL */
 
   while ((term = argv_term (&f)) != NULL)
@@ -410,3 +384,22 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag
   gc_free (&gc);
 }
 
+void
+argv_printf (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  argv_reset (a);
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, arglist);
+  va_end (arglist);
+ }
+
+void
+argv_printf_cat (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, arglist);
+  va_end (arglist);
+}
+
src/openvpn/argv.h +0 -6
index df658a0..5f8e21c 100644
@@ -40,18 +40,12 @@ struct argv {
   char *system_str;
 };
 
-void argv_init (struct argv *a);
 struct argv argv_new (void);
 void argv_reset (struct argv *a);
-char *argv_term (const char **f);
 const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
 struct argv argv_insert_head (const struct argv *a, const char *head);
 void argv_msg (const int msglev, const struct argv *a);
 void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
-const char *argv_system_str (const struct argv *a);
-
-#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
-void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
 
 void argv_printf (struct argv *a, const char *format, ...)
 #ifdef __GNUC__
src/openvpn/console_systemd.c +1 -2
index 9cd7575..8a953c9 100644
@@ -60,9 +60,8 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con
 {
     int std_out;
     bool ret = false;
-    struct argv argv;
+    struct argv argv = argv_new ();
 
-    argv_init (&argv);
     argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH);
 #ifdef SYSTEMD_NEWER_THAN_216
     /* the --echo support arrived in upstream systemd 217 */
src/openvpn/route.c +4 -8
index 96d4e11..98bb228 100644
@@ -1395,7 +1395,7 @@ add_route (struct route_ipv4 *r,
 	   const struct env_set *es)
 {
   struct gc_arena gc;
-  struct argv argv;
+  struct argv argv = argv_new ();
   const char *network;
   const char *netmask;
   const char *gateway;
@@ -1406,7 +1406,6 @@ add_route (struct route_ipv4 *r,
     return;
 
   gc_init (&gc);
-  argv_init (&argv);
 
   network = print_in_addr_t (r->network, 0, &gc);
   netmask = print_in_addr_t (r->netmask, 0, &gc);
@@ -1671,7 +1670,7 @@ void
 add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
 {
   struct gc_arena gc;
-  struct argv argv;
+  struct argv argv = argv_new ();
 
   const char *network;
   const char *gateway;
@@ -1693,7 +1692,6 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
 #endif
 
   gc_init (&gc);
-  argv_init (&argv);
 
   route_ipv6_clear_host_bits (r6);
 
@@ -1933,7 +1931,7 @@ delete_route (struct route_ipv4 *r,
 	      const struct env_set *es)
 {
   struct gc_arena gc;
-  struct argv argv;
+  struct argv argv = argv_new ();
   const char *network;
   const char *netmask;
   const char *gateway;
@@ -1943,7 +1941,6 @@ delete_route (struct route_ipv4 *r,
     return;
 
   gc_init (&gc);
-  argv_init (&argv);
 
   network = print_in_addr_t (r->network, 0, &gc);
   netmask = print_in_addr_t (r->netmask, 0, &gc);
@@ -2108,7 +2105,7 @@ void
 delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
 {
   struct gc_arena gc;
-  struct argv argv;
+  struct argv argv = argv_new ();
   const char *network;
   const char *gateway;
   const char *device = tt->actual_name;
@@ -2126,7 +2123,6 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
 #endif
 
   gc_init (&gc);
-  argv_init (&argv);
 
   network = print_in6_addr( r6->network, 0, &gc);
   gateway = print_in6_addr( r6->gateway, 0, &gc);
src/openvpn/tun.c +13 -29

152 lines not on this page · raw message

Signature · 1 line
2.7.4
#10 lore raw

Re: [Openvpn-devel] [PATCH 2/7] Remove unused and unecessary argv interfaces

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 8 lines · Heiko Hund

src/openvpn/argv.c | 53
+++++++++++++++++++------------------------ src/openvpn/argv.h

|  6 ----- src/openvpn/console_systemd.c |  3 +-- 
src/openvpn/route.c           | 12 ++++------ src/openvpn/tun.c
| 42 +++++++++++----------------------- 5 files changed, 41

insertions(+), 75 deletions(-)

ACK. Looks good, cleans up not needed complexity. Passes all tests, valgrind doesn't report any memory leaks.

As for patch 1/7 ... I will wait with applying this patch to the git tree until all the other patches in this series have been reviewed and ACKed.

- --
kind regards,

David Sommerseth
OpenVPN Technologies, Inc

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJYIauUAAoJEIbPlEyWcf3yDWoQAKHRd/4hiM1Bdi4/ilvltZnW ZcUdUsfxB3SUDniyfb6NXSXPkeDNaaqRSGcQNhBZ6MEC1WkRgBYcWL7fy/NEsPlT WyUqTOjWknb9ka+ka1QT3wrhiE/naP4cI3oGxLpfxdRuHOXOwSQAKv3k/vqWWoyh IayIUrFLMPirffogaZTc9Py5/v+s8EonPN+B3rJDC7BrQyRNimnX7s7LldtjLTo6 LhF2zTFBJowtYJryCgaQaaBIUcM8iDe0jZbH4iTqv4XmYtkjgMEWdKxIYyE0XiEk gh4GkmplXaY9YPQJ5nFbKGZKNNyQ9yAESjZ9SkzUiV/U277u7SDdBiRrNS+g4nR3 nsGNwhyxdxnv8ryxaxJcHuXqOmFPr0c+6ZxEwKAEZVUh/q007YqEA8kul3sb5npC BNNGXh03f2SzzMzQ0w9HA/GRFbSlsfMLsR3acVBxXXbrwg/+DttgUac7zFXv3PWm tz4VMjAoi9chc8rY3fTvM4mwJzixeuzBbchLdSh6x8UCVApXlDUrX/DN8mx4DZis EQesuL3bR8Saijn1XXLWcCE1+NDpxih9GBGziEicv84GM1KVRWBXi+7HleUDdgKp B9LA5YzBS2OnjoyPRONrTCkFddaN4iYtNJLUKPSTPefd1q+0uKGyksR2Jft9zP6A b5jdzmfuhbsnqBUEBpY9
=Tlfw
-----END PGP SIGNATURE-----

#11 lore raw

[Openvpn-devel] [PATCH applied] Re: Remove unused and unecessary argv interfaces

In reply to Heiko Hund

Your patch has been applied to the master branch.

commit aed5ef40c47c58b3b7bc624113396a26e5e2cba5

Author: Heiko Hund
Date:   Fri Oct 28 18:42:38 2016 +0200
     Remove unused and unecessary argv interfaces

     Signed-off-by: Heiko Hund <[email protected]...>
     Acked-by: David Sommerseth <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg12812.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

author
#12 lore raw

PATCH 3/7 remove unused system_str from struct argv

In reply to Heiko Hund
---
 src/openvpn/argv.c | 86 ------------------------------------------------------
 src/openvpn/argv.h |  1 -
 2 files changed, 87 deletions(-)
src/openvpn/argv.c +0 -86
index 89c9b14..a279a40 100644
@@ -45,7 +45,6 @@ argv_init (struct argv *a)
   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;
-  a->system_str = NULL;
 }
 
 struct argv
@@ -63,7 +62,6 @@ argv_reset (struct argv *a)
   for (i = 0; i < a->argc; ++i)
     free (a->argv[i]);
   free (a->argv);
-  free (a->system_str);
   argv_init (a);
 }
 
@@ -98,65 +96,6 @@ argv_append (struct argv *a, char *str) /* str must have been malloced or be NUL
   a->argv[a->argc++] = str;
 }
 
-static void
-argv_system_str_append (struct argv *a, const char *str, const bool enquote)
-{
-  if (str)
-    {
-      char *newstr;
-
-      /* compute length of new system_str */
-      size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */
-      if (a->system_str)
-        l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */
-      if (enquote)
-        l += 2; /* space for two quotes */
-
-      /* build new system_str */
-      newstr = (char *) malloc (l);
-      newstr[0] = '\0';
-      check_malloc_return (newstr);
-      if (a->system_str)
-        {
-          strcpy (newstr, a->system_str);
-          strcat (newstr, " ");
-        }
-      if (enquote)
-        strcat (newstr, "\"");
-      strcat (newstr, str);
-      if (enquote)
-        strcat (newstr, "\"");
-      free (a->system_str);
-      a->system_str = newstr;
-    }
-}
-
-static char *
-argv_extract_cmd_name (const char *path)
-{
-  char *ret = NULL;
-  if (path)
-    {
-      char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */
-      const char *bn = basename (path_cp);
-      if (bn)
-        {
-          char *dot = NULL;
-          ret = string_alloc (bn, NULL);
-          dot = strrchr (ret, '.');
-          if (dot)
-            *dot = '\0';
-          free(path_cp);
-          if (ret[0] == '\0')
-            {
-              free(ret);
-              ret = NULL;
-            }
-        }
-    }
-  return ret;
-}
-
 static struct argv
 argv_clone (const struct argv *a, const size_t headroom)
 {
@@ -170,7 +109,6 @@ argv_clone (const struct argv *a, const size_t headroom)
     {
       for (i = 0; i < a->argc; ++i)
         argv_append (&r, string_alloc (a->argv[i], NULL));
-      r.system_str = string_alloc (a->system_str, NULL);
     }
   return r;
 }
@@ -179,17 +117,8 @@ struct argv
 argv_insert_head (const struct argv *a, const char *head)
 {
   struct argv r;
-  char *s;
-
   r = argv_clone (a, 1);
   r.argv[0] = string_alloc (head, NULL);
-  s = r.system_str;
-  r.system_str = string_alloc (head, NULL);
-  if (s)
-    {
-      argv_system_str_append (&r, s, false);
-      free (s);
-    }
   return r;
 }
 
@@ -285,7 +214,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
               if (!s)
                 s = "";
               argv_append (a, string_alloc (s, NULL));
-              argv_system_str_append (a, s, true);
             }
           else if (!strcmp (term, "%sc"))
             {
@@ -304,13 +232,10 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
                     }
                   else
                     argv_append (a, string_alloc (s, NULL));
-
-                  argv_system_str_append (a, s, false);
                 }
               else
                 {
                   argv_append (a, string_alloc ("", NULL));
-                  argv_system_str_append (a, "echo", false);
                 }
             }
           else if (!strcmp (term, "%d"))
@@ -318,14 +243,12 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
               char numstr[64];
               openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
               argv_append (a, string_alloc (numstr, NULL));
-              argv_system_str_append (a, numstr, false);
             }
           else if (!strcmp (term, "%u"))
             {
               char numstr[64];
               openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
               argv_append (a, string_alloc (numstr, NULL));
-              argv_system_str_append (a, numstr, false);
             }
           else if (!strcmp (term, "%s/%d"))
             {
@@ -346,7 +269,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
                 strcat (combined, "/");
                 strcat (combined, numstr);
                 argv_append (a, combined);
-                argv_system_str_append (a, combined, false);
               }
             }
           else if (!strcmp (term, "%s%sc"))
@@ -363,13 +285,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
               strcpy (combined, s1);
               strcat (combined, s2);
               argv_append (a, combined);
-
-              cmd_name = argv_extract_cmd_name (combined);
-              if (cmd_name)
-                {
-                  argv_system_str_append (a, cmd_name, false);
-                  free (cmd_name);
-                }
             }
           else
             ASSERT (0);
@@ -378,7 +293,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
       else
         {
           argv_append (a, term);
-          argv_system_str_append (a, term, false);
         }
     }
   gc_free (&gc);
src/openvpn/argv.h +0 -1
index 5f8e21c..c45bec8 100644
@@ -37,7 +37,6 @@ struct argv {
   size_t capacity;
   size_t argc;
   char **argv;
-  char *system_str;
 };
 
 struct argv argv_new (void);
Signature · 1 line
2.7.4
#13 lore raw

Re: [Openvpn-devel] [PATCH 3/7] remove unused system_str from struct argv

Quoted 5 lines · Heiko Hund
---
 src/openvpn/argv.c | 86 ------------------------------------------------------
 src/openvpn/argv.h |  1 -
 2 files changed, 87 deletions(-)

ACK. Looks good. Valgrind also reports less heap usage, which is expected due to not allocating buffers for system_str. Otherwise tests passed.

As for the prior patches in this series, I will wait with applying this patch to the git tree until all the other patches in this series have been reviewed and ACKed.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#14 lore raw

[Openvpn-devel] [PATCH applied] Re: remove unused system_str from struct argv

In reply to Heiko Hund

Your patch has been applied to the master branch.

commit d6ab1dc49e5c8018f58e7c3c9fe64f4289ccc77b

Author: Heiko Hund
Date:   Fri Oct 28 18:42:39 2016 +0200
     remove unused system_str from struct argv

     Signed-off-by: Heiko Hund <[email protected]...>
     Acked-by: David Sommerseth <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg12813.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

author
#15 lore raw

PATCH 4/7 Factor out %sc handling from argv_printf()

In reply to Heiko Hund

Move functionality to parse command strings into argv_parse_cmd(). That is a preparation for the upcoming refactoring of argv_printf().

---
 src/openvpn/argv.c                   | 47 +++++++++++++++++-------------------
 src/openvpn/argv.h                   |  1 +
 src/openvpn/errlevel.h               |  2 +-
 src/openvpn/init.c                   |  2 +-
 src/openvpn/misc.c                   | 10 +++-----
 src/openvpn/multi.c                  | 13 ++++------
 src/openvpn/options.c                |  2 +-
 src/openvpn/socket.c                 |  7 +++---
 src/openvpn/ssl_verify.c             |  6 +++--
 tests/unit_tests/openvpn/test_argv.c | 18 +++++++++++---
 10 files changed, 56 insertions(+), 52 deletions(-)
src/openvpn/argv.c +22 -25
index a279a40..f8287b7 100644
@@ -198,7 +198,6 @@ argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
 static void
 argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
 {
-  struct gc_arena gc = gc_new ();
   char *term;
   const char *f = format;
 
@@ -215,29 +214,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
                 s = "";
               argv_append (a, string_alloc (s, NULL));
             }
-          else if (!strcmp (term, "%sc"))
-            {
-              char *s = va_arg (arglist, char *);
-              if (s)
-                {
-                  int nparms;
-                  char *parms[MAX_PARMS+1];
-                  int i;
-
-                  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
-                  if (nparms)
-                    {
-                      for (i = 0; i < nparms; ++i)
-                        argv_append (a, string_alloc (parms[i], NULL));
-                    }
-                  else
-                    argv_append (a, string_alloc (s, NULL));
-                }
-              else
-                {
-                  argv_append (a, string_alloc ("", NULL));
-                }
-            }
           else if (!strcmp (term, "%d"))
             {
               char numstr[64];
@@ -295,7 +271,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
           argv_append (a, term);
         }
     }
-  gc_free (&gc);
 }
 
 void
@@ -317,3 +292,25 @@ argv_printf_cat (struct argv *a, const char *format, ...)
   va_end (arglist);
 }
 
+void
+argv_parse_cmd (struct argv *a, const char *s)
+{
+  int nparms;
+  char *parms[MAX_PARMS + 1];
+  struct gc_arena gc = gc_new ();
+
+  argv_reset (a);
+  argv_extend (a, 1); /* ensure trailing NULL */
+
+  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+  if (nparms)
+    {
+      int i;
+      for (i = 0; i < nparms; ++i)
+        argv_append (a, string_alloc (parms[i], NULL));
+    }
+  else
+    argv_append (a, string_alloc (s, NULL));
+
+  gc_free (&gc);
+}
src/openvpn/argv.h +1 -0
index c45bec8..9aee641 100644
@@ -45,6 +45,7 @@ const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned
 struct argv argv_insert_head (const struct argv *a, const char *head);
 void argv_msg (const int msglev, const struct argv *a);
 void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
+void argv_parse_cmd (struct argv *a, const char *s);
 
 void argv_printf (struct argv *a, const char *format, ...)
 #ifdef __GNUC__
src/openvpn/errlevel.h +1 -1
index ae1f8f4..9d56eb4 100644
@@ -142,7 +142,7 @@
 #define D_PS_PROXY_DEBUG     LOGLEV(7, 70, M_DEBUG)  /* port share proxy debug */
 #define D_AUTO_USERID        LOGLEV(7, 70, M_DEBUG)  /* AUTO_USERID debugging */
 #define D_TLS_KEYSELECT      LOGLEV(7, 70, M_DEBUG)  /* show information on key selection for data channel */
-#define D_ARGV_PARSE_CMD     LOGLEV(7, 70, M_DEBUG)  /* show parse_line() errors in argv_printf %sc */
+#define D_ARGV_PARSE_CMD     LOGLEV(7, 70, M_DEBUG)  /* show parse_line() errors in argv_parse_cmd */
 #define D_CRYPTO_DEBUG       LOGLEV(7, 70, M_DEBUG)  /* show detailed info from crypto.c routines */
 #define D_PID_DEBUG          LOGLEV(7, 70, M_DEBUG)  /* show packet-id debugging info */
 #define D_PF_DROPPED_BCAST   LOGLEV(7, 71, M_DEBUG)  /* packet filter dropped a broadcast packet */
src/openvpn/init.c +1 -1
index 73f8c6d..56140b3 100644
@@ -1362,7 +1362,7 @@ do_route (const struct options *options,
     {
       struct argv argv = argv_new ();
       setenv_str (es, "script_type", "route-up");
-      argv_printf (&argv, "%sc", options->route_script);
+      argv_parse_cmd (&argv, options->route_script);
       openvpn_run_script (&argv, es, 0, "--route-up");
       argv_reset (&argv);
     }
src/openvpn/misc.c +3 -7
index af362e9..b433df6 100644
@@ -120,13 +120,9 @@ run_up_down (const char *command,
       struct argv argv = argv_new ();
       ASSERT (arg);
       setenv_str (es, "script_type", script_type);
-      argv_printf (&argv,
-		  "%sc %s %d %d %s %s %s",
-		  command,
-		  arg,
-		  tun_mtu, link_mtu,
-		  ifconfig_local, ifconfig_remote,
-		  context);
+      argv_parse_cmd (&argv, command);
+      argv_printf_cat (&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu,
+                       ifconfig_local, ifconfig_remote, context);
       argv_msg (M_INFO, &argv);
       openvpn_run_script (&argv, es, S_FATAL, "--up/--down");
       argv_reset (&argv);
src/openvpn/multi.c +5 -8
index 93a554d..9c75f7b 100644
@@ -126,10 +126,8 @@ learn_address_script (const struct multi_context *m,
     {
       struct argv argv = argv_new ();
       setenv_str (es, "script_type", "learn-address");
-      argv_printf (&argv, "%sc %s %s",
-		   m->top.options.learn_address_script,
-		   op,
-		   mroute_addr_print (addr, &gc));
+      argv_parse_cmd (&argv, m->top.options.learn_address_script);
+      argv_printf_cat (&argv, "%s %s", op, mroute_addr_print (addr, &gc));
       if (mi)
 	argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
       if (!openvpn_run_script (&argv, es, 0, "--learn-address"))
@@ -545,7 +543,7 @@ multi_client_disconnect_script (struct multi_context *m,
 	{
 	  struct argv argv = argv_new ();
 	  setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
-	  argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
+	  argv_parse_cmd (&argv, mi->context.options.client_disconnect_script);
 	  openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect");
 	  argv_reset (&argv);
 	}
@@ -1834,9 +1832,8 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
             goto script_failed;
           }
 
-	  argv_printf (&argv, "%sc %s",
-		       mi->context.options.client_connect_script,
-		       dc_file);
+          argv_parse_cmd (&argv, mi->context.options.client_connect_script);
+          argv_printf_cat (&argv, "%s", dc_file);
 
 	  if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect"))
 	    {
src/openvpn/options.c +1 -1
index 996c26e..557299a 100644
@@ -2778,7 +2778,7 @@ check_cmd_access(const char *command, const char *opt, const char *chroot)
 
   /* Extract executable path and arguments */
   argv = argv_new ();
-  argv_printf (&argv, "%sc", command);
+  argv_parse_cmd (&argv, command);
 
   /* if an executable is specified then check it; otherwise, complain */
   if (argv.argv[0])
src/openvpn/socket.c +4 -3
index 184c7ad..bb7cba1 100644
@@ -2022,9 +2022,10 @@ ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socke
 {
   const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);
   if (include_cmd)
-    argv_printf (argv, "%sc %s",
-		 info->ipchange_command,
-		 host);
+    {
+      argv_parse_cmd (argv, info->ipchange_command);
+      argv_printf_cat (argv, "%s", host);
+    }
   else
     argv_printf (argv, "%s", host);
 
src/openvpn/ssl_verify.c +4 -2
index d0c22b8..be9f224 100644
@@ -514,7 +514,8 @@ verify_cert_call_command(const char *verify_command, struct env_set *es,
        }
     }
 
-  argv_printf (&argv, "%sc %d %s", verify_command, cert_depth, subject);
+  argv_parse_cmd (&argv, verify_command);
+  argv_printf_cat (&argv, "%d %s", cert_depth, subject);
 
   argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
   ret = openvpn_run_script (&argv, es, 0, "--tls-verify script");
@@ -981,7 +982,8 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
       setenv_untrusted (session);
 
       /* format command line */
-      argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
+      argv_parse_cmd (&argv, session->opt->auth_user_pass_verify_script);
+      argv_printf_cat (&argv, "%s", tmp_file);
 
       /* call command */
       ret = openvpn_run_script (&argv, session->opt->es, 0,
tests/unit_tests/openvpn/test_argv.c +14 -4
index f07a5fb..3945634 100644
@@ -99,14 +99,23 @@ argv_printf__combined_path_with_spaces__argc_correct (void **state)
 }
 
 static void
-argv_printf__script_command__argc_correct (void **state)
+argv_parse_cmd__command_string__argc_correct (void **state)
 {
   struct argv a = argv_new ();
 
-  argv_printf (&a, "%sc", SCRIPT_CMD);
+  argv_parse_cmd (&a, SCRIPT_CMD);
   assert_int_equal (a.argc, 3);
 
-  argv_printf (&a, "bar baz %sc %d %s", SCRIPT_CMD, 42, PATH1);
+  argv_reset (&a);
+}
+
+static void
+argv_parse_cmd__command_and_extra_options__argc_correct (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_parse_cmd (&a, SCRIPT_CMD);
+  argv_printf_cat (&a, "bar baz %d %s", 42, PATH1);
   assert_int_equal (a.argc, 7);
 
   argv_reset (&a);
@@ -184,7 +193,8 @@ main(void)
     cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one),
     cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one),
     cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct),
-    cmocka_unit_test (argv_printf__script_command__argc_correct),
+    cmocka_unit_test (argv_parse_cmd__command_string__argc_correct),
+    cmocka_unit_test (argv_parse_cmd__command_and_extra_options__argc_correct),
     cmocka_unit_test (argv_printf_cat__used_twice__argc_correct),
     cmocka_unit_test (argv_str__multiple_argv__correct_output),
     cmocka_unit_test (argv_insert_head__non_empty_argv__head_added),
Signature · 1 line
2.7.4
#16 lore raw

Re: [Openvpn-devel] [PATCH 4/7] Factor out %sc handling from argv_printf()

Quoted 4 lines · Heiko Hund

Move functionality to parse command strings into argv_parse_cmd(). That is a preparation for the upcoming refactoring of argv_printf().

Quoted 12 lines
---
 src/openvpn/argv.c                   | 47 +++++++++++++++++-------------------
 src/openvpn/argv.h                   |  1 +
 src/openvpn/errlevel.h               |  2 +-
 src/openvpn/init.c                   |  2 +-
 src/openvpn/misc.c                   | 10 +++-----
 src/openvpn/multi.c                  | 13 ++++------
 src/openvpn/options.c                |  2 +-
 src/openvpn/socket.c                 |  7 +++---
 src/openvpn/ssl_verify.c             |  6 +++--
 tests/unit_tests/openvpn/test_argv.c | 18 +++++++++++---
 10 files changed, 56 insertions(+), 52 deletions(-)

ACK. This is a bit more invasive, but all testing looks good. Code changes are reasonable. Tested with 'make check', separate tests using --auth-user-pass-verify on server side and a couple of valgrind checks. In addition, 'ip route' was executed.

The argv_parse_cmd() is also generic and used all places where %sc was used before, I consider this smoke-testing good enough for now.

As for the prior patches in this series, I will wait with applying this patch to the git tree until all the other patches in this series have been reviewed and ACKed.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#17 lore raw

[Openvpn-devel] [PATCH applied] Re: Factor out %sc handling from argv_printf()

In reply to Heiko Hund

Your patch has been applied to the master branch.

commit 253609124459f8df96e059bba9c164299a32318e

Author: Heiko Hund
Date:   Fri Oct 28 18:42:40 2016 +0200
     Factor out %sc handling from argv_printf()

     Signed-off-by: Heiko Hund <[email protected]...>
     Acked-by: David Sommerseth <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg12816.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

author
#18 lore raw

PATCH 5/7 re-implement argv_printf_*()

In reply to Heiko Hund

The previous implementation had the problem that it was not fully compatible with printf() and could only detect % format directives following a space character (0x20).

It modifies the format string and inserts marks to separate groups before passing it to the regular printf in libc. The marks are later used to separate the output string into individual command line arguments.

The choice of '\035' as the argument delimiter is based on the assumption that no "regular" string passed to argv_printf_*() will ever have to contain that byte (and the fact that it actually is the ASCII "group separator" control character, which fits its purpose).

---
 src/openvpn/argv.c                   | 203 ++++++++++++++---------------------
 src/openvpn/argv.h                   |   4 +-
 src/openvpn/route.c                  |   8 +-
 src/openvpn/tun.c                    |  22 ++--
 tests/unit_tests/openvpn/test_argv.c |  34 +++++-
 5 files changed, 130 insertions(+), 141 deletions(-)
src/openvpn/argv.c +83 -120
index f8287b7..dcfbd76 100644
@@ -6,6 +6,7 @@
  *             packet compression.
  *
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <[email protected]...>
+ *                2016      Heiko Hund <[email protected]...>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -122,54 +123,6 @@ argv_insert_head (const struct argv *a, const char *head)
   return r;
 }
 
-static char *
-argv_term (const char **f)
-{
-  const char *p = *f;
-  const char *term = NULL;
-  size_t termlen = 0;
-
-  if (*p == '\0')
-    return NULL;
-
-  while (true)
-    {
-      const int c = *p;
-      if (c == '\0')
-        break;
-      if (term)
-        {
-          if (!isspace (c))
-            ++termlen;
-          else
-            break;
-        }
-      else
-        {
-          if (!isspace (c))
-            {
-              term = p;
-              termlen = 1;
-            }
-        }
-      ++p;
-    }
-  *f = p;
-
-  if (term)
-    {
-      char *ret;
-      ASSERT (termlen > 0);
-      ret = malloc (termlen + 1);
-      check_malloc_return (ret);
-      memcpy (ret, term, termlen);
-      ret[termlen] = '\0';
-      return ret;
-    }
-  else
-    return NULL;
-}
-
 const char *
 argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {
@@ -195,101 +148,111 @@ argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
   gc_free (&gc);
 }
 
-static void
-argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
+static char *
+argv_prep_format (const char *format, const char delim, size_t *count, struct gc_arena *gc)
 {
-  char *term;
-  const char *f = format;
+  int i, j;
+  char *f;
+  bool in_token = false;
 
-  argv_extend (a, 1); /* ensure trailing NULL */
+  if (format == NULL)
+    return NULL;
 
-  while ((term = argv_term (&f)) != NULL)
+  f = gc_malloc (strlen (format) + 1, true, gc);
+  for (i = 0, j = 0; i < strlen (format); i++)
     {
-      if (term[0] == '%')
+      if (format[i] == ' ')
         {
-          if (!strcmp (term, "%s"))
-            {
-              char *s = va_arg (arglist, char *);
-              if (!s)
-                s = "";
-              argv_append (a, string_alloc (s, NULL));
-            }
-          else if (!strcmp (term, "%d"))
-            {
-              char numstr[64];
-              openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-              argv_append (a, string_alloc (numstr, NULL));
-            }
-          else if (!strcmp (term, "%u"))
-            {
-              char numstr[64];
-              openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
-              argv_append (a, string_alloc (numstr, NULL));
-            }
-          else if (!strcmp (term, "%s/%d"))
-            {
-              char numstr[64];
-              char *s = va_arg (arglist, char *);
-
-              if (!s)
-                s = "";
-
-              openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-
-              {
-                const size_t len = strlen(s) + strlen(numstr) + 2;
-                char *combined = (char *) malloc (len);
-                check_malloc_return (combined);
-
-                strcpy (combined, s);
-                strcat (combined, "/");
-                strcat (combined, numstr);
-                argv_append (a, combined);
-              }
-            }
-          else if (!strcmp (term, "%s%sc"))
-            {
-              char *s1 = va_arg (arglist, char *);
-              char *s2 = va_arg (arglist, char *);
-              char *combined;
-              char *cmd_name;
-
-              if (!s1) s1 = "";
-              if (!s2) s2 = "";
-              combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
-              check_malloc_return (combined);
-              strcpy (combined, s1);
-              strcat (combined, s2);
-              argv_append (a, combined);
-            }
-          else
-            ASSERT (0);
-          free (term);
+          in_token = false;
+          continue;
         }
-      else
+
+      if (!in_token)
         {
-          argv_append (a, term);
+          ++*count;
+          if (f[0])
+            f[j++] = delim;
         }
+
+      f[j++] = format[i];
+      in_token = true;
     }
+  return f;
 }
 
-void
+static bool
+argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
+{
+  struct gc_arena gc = gc_new ();
+  const char *delim = "\035";
+  char *f, *buf, *token;
+  size_t argc, size;
+  bool res = false;
+  va_list tmplist;
+  int len;
+
+  argv_extend (a, 1); /* ensure trailing NULL */
+
+  argc = a->argc;
+  f = argv_prep_format (format, delim[0], &argc, &gc);
+  if (f == NULL)
+    goto out;
+
+  va_copy (tmplist, arglist);
+  len = vsnprintf (NULL, 0, f, tmplist);
+  va_end (tmplist);
+  if (len < 0)
+    goto out;
+
+  size = adjust_power_of_2 (len + 1);
+  buf = gc_malloc (size, false, &gc);
+  len = vsnprintf (buf, size, f, arglist);
+  if (len < 0 || len >= size)
+    goto out;
+
+  token = strtok (buf, delim);
+  while (token)
+    {
+      argv_append (a, string_alloc (token, NULL));
+      token = strtok (NULL, delim);
+    }
+
+  if (a->argc != argc)
+    {
+      /* Someone snuck in a \035, fail gracefully */
+      argv_reset (a);
+      argv_extend (a, 1); /* ensure trailing NULL */
+      goto out;
+    }
+
+  res = true;
+
+out:
+  gc_free (&gc);
+  return res;
+}
+
+bool
 argv_printf (struct argv *a, const char *format, ...)
 {
+  bool res;
   va_list arglist;
-  argv_reset (a);
   va_start (arglist, format);
-  argv_printf_arglist (a, format, arglist);
+  argv_reset (a);
+  res = argv_printf_arglist (a, format, arglist);
   va_end (arglist);
+  return res;
  }
 
-void
+bool
 argv_printf_cat (struct argv *a, const char *format, ...)
 {
+  bool res;
   va_list arglist;
   va_start (arglist, format);
-  argv_printf_arglist (a, format, arglist);
+  res = argv_printf_arglist (a, format, arglist);
   va_end (arglist);
+  return res;
 }
 
 void
src/openvpn/argv.h +2 -2
index 9aee641..ff3933e 100644
@@ -47,7 +47,7 @@ void argv_msg (const int msglev, const struct argv *a);
 void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
 void argv_parse_cmd (struct argv *a, const char *s);
 
-void argv_printf (struct argv *a, const char *format, ...)
+bool argv_printf (struct argv *a, const char *format, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
         __attribute__ ((format (gnu_printf, 2, 3)))
@@ -57,7 +57,7 @@ void argv_printf (struct argv *a, const char *format, ...)
 #endif
   ;
 
-void argv_printf_cat (struct argv *a, const char *format, ...)
+bool argv_printf_cat (struct argv *a, const char *format, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
         __attribute__ ((format (gnu_printf, 2, 3)))
src/openvpn/route.c +4 -4
index 98bb228..ca1e0a7 100644
@@ -1457,7 +1457,7 @@ add_route (struct route_ipv4 *r,
 #elif defined (WIN32)
   {
     DWORD ai = TUN_ADAPTER_INDEX_INVALID;
-    argv_printf (&argv, "%s%sc ADD %s MASK %s %s",
+    argv_printf (&argv, "%s%s ADD %s MASK %s %s",
 		 get_win_sys_path(),
 		 WIN_ROUTE_PATH_SUFFIX,
 		 network,
@@ -1796,7 +1796,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
       device = buf_bptr(&out);
 
       /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
-      argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
+      argv_printf (&argv, "%s%s interface ipv6 add route %s/%d %s",
 		   get_win_sys_path(),
 		   NETSH_PATH_SUFFIX,
 		   network,
@@ -1969,7 +1969,7 @@ delete_route (struct route_ipv4 *r,
 
 #elif defined (WIN32)
   
-  argv_printf (&argv, "%s%sc DELETE %s MASK %s %s",
+  argv_printf (&argv, "%s%s DELETE %s MASK %s %s",
 	       get_win_sys_path(),
 	       WIN_ROUTE_PATH_SUFFIX,
 	       network,
@@ -2199,7 +2199,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
       device = buf_bptr(&out);
 
       /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
-      argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
+      argv_printf (&argv, "%s%s interface ipv6 delete route %s/%d %s",
 		   get_win_sys_path(),
 		   NETSH_PATH_SUFFIX,
 		   network,
src/openvpn/tun.c +11 -11
index 12c6976..843df16 100644
@@ -1362,7 +1362,7 @@ do_ifconfig (struct tuntap *tt,
 	    char iface[64];
 	    openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index );
 	    argv_printf (&argv,
-			 "%s%sc interface ipv6 set address %s %s store=active",
+			 "%s%s interface ipv6 set address %s %s store=active",
 			 get_win_sys_path(),
 			 NETSH_PATH_SUFFIX,
 			 iface,
@@ -4490,28 +4490,28 @@ ipconfig_register_dns (const struct env_set *es)
   msg (D_TUNTAP_INFO, "Start net commands...");
   netcmd_semaphore_lock ();
 
-  argv_printf (&argv, "%s%sc stop dnscache",
+  argv_printf (&argv, "%s%s stop dnscache",
 	       get_win_sys_path(),
 	       WIN_NET_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
   argv_reset(&argv);
 
-  argv_printf (&argv, "%s%sc start dnscache",
+  argv_printf (&argv, "%s%s start dnscache",
 	       get_win_sys_path(),
 	       WIN_NET_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
   argv_reset(&argv);
 
-  argv_printf (&argv, "%s%sc /flushdns",
+  argv_printf (&argv, "%s%s /flushdns",
 	       get_win_sys_path(),
 	       WIN_IPCONFIG_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
   argv_reset(&argv);
 
-  argv_printf (&argv, "%s%sc /registerdns",
+  argv_printf (&argv, "%s%s /registerdns",
 	       get_win_sys_path(),
 	       WIN_IPCONFIG_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
@@ -4620,7 +4620,7 @@ netsh_ifconfig_options (const char *type,
   /* delete existing DNS/WINS settings from TAP interface */
   if (delete_first)
     {
-      argv_printf (&argv, "%s%sc interface ip delete %s %s all",
+      argv_printf (&argv, "%s%s interface ip delete %s %s all",
 		   get_win_sys_path(),
 		   NETSH_PATH_SUFFIX,
 		   type,
@@ -4637,8 +4637,8 @@ netsh_ifconfig_options (const char *type,
 	if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current))
 	  {
 	    const char *fmt = count ?
-	        "%s%sc interface ip add %s %s %s"
-	      : "%s%sc interface ip set %s %s static %s";
+	        "%s%s interface ip add %s %s %s"
+	      : "%s%s interface ip set %s %s static %s";
 
 	    argv_printf (&argv, fmt,
 			 get_win_sys_path(),
@@ -4714,7 +4714,7 @@ netsh_ifconfig (const struct tuntap_options *to,
       else
 	{
 	  /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
-	  argv_printf (&argv, "%s%sc interface ip set address %s static %s %s",
+	  argv_printf (&argv, "%s%s interface ip set address %s static %s %s",
 		       get_win_sys_path(),
 		       NETSH_PATH_SUFFIX,
 		       flex_name,
@@ -4761,7 +4761,7 @@ netsh_enable_dhcp (const struct tuntap_options *to,
 
   /* example: netsh interface ip set address my-tap dhcp */
   argv_printf (&argv,
-	      "%s%sc interface ip set address %s dhcp",
+	      "%s%s interface ip set address %s dhcp",
 	       get_win_sys_path(),
 	       NETSH_PATH_SUFFIX,
 	       actual_name);
@@ -5535,7 +5535,7 @@ close_tun (struct tuntap *tt)
               /* netsh interface ipv6 delete address \"%s\" %s */
               ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0,  &gc);
               argv_printf (&argv,
-                           "%s%sc interface ipv6 delete address %s %s store=active",
+                           "%s%s interface ipv6 delete address %s %s store=active",
                            get_win_sys_path(),
                            NETSH_PATH_SUFFIX,
                            tt->actual_name,
tests/unit_tests/openvpn/test_argv.c +30 -4
index 3945634..0371c78 100644
@@ -9,6 +9,7 @@
 #include <setjmp.h>
 #include <cmocka.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "argv.h"
 #include "buffer.h"
@@ -82,17 +83,40 @@ argv_printf_cat__multiple_spaces_in_format__parsed_as_one (void **state)
 }
 
 static void
+argv_printf__embedded_format_directive__replaced_in_output (void **state)
+{
+  struct argv a = argv_new ();
+
+  argv_printf (&a, "<p1:%s>", PATH1);
+  assert_int_equal (a.argc, 1);
+  assert_string_equal (a.argv[0], "<p1:" PATH1 ">");
+
+  argv_reset (&a);
+}
+
+static void
+argv_printf__group_sep_in_arg__fail_no_ouput (void **state)
+{
+  struct argv a = argv_new ();
+
+  assert_false (argv_printf (&a, "tool --do %s", "this\035--harmful"));
+  assert_int_equal (a.argc, 0);
+
+  argv_reset (&a);
+}
+
+static void
 argv_printf__combined_path_with_spaces__argc_correct (void **state)
 {
   struct argv a = argv_new ();
 
-  argv_printf (&a, "%s%sc", PATH1, PATH2);
+  argv_printf (&a, "%s%s", PATH1, PATH2);
   assert_int_equal (a.argc, 1);
 
-  argv_printf (&a, "%s%sc %d", PATH1, PATH2, 42);
+  argv_printf (&a, "%s%s %d", PATH1, PATH2, 42);
   assert_int_equal (a.argc, 2);
 
-  argv_printf (&a, "foo %s%sc %s x y", PATH2, PATH1, "foo");
+  argv_printf (&a, "foo %s%s %s x y", PATH2, PATH1, "foo");
   assert_int_equal (a.argc, 5);
 
   argv_reset (&a);
@@ -141,7 +165,7 @@ argv_str__multiple_argv__correct_output (void **state)
   struct gc_arena gc = gc_new ();
   const char *output;
 
-  argv_printf (&a, "%s%sc", PATH1, PATH2);
+  argv_printf (&a, "%s%s", PATH1, PATH2);
   argv_printf_cat (&a, "%s", PARAM1);
   argv_printf_cat (&a, "%s", PARAM2);
   output = argv_str (&a, &gc, PA_BRACKET);
@@ -192,6 +216,8 @@ main(void)
   const struct CMUnitTest tests[] = {
     cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one),
     cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one),
+    cmocka_unit_test (argv_printf__embedded_format_directive__replaced_in_output),
+    cmocka_unit_test (argv_printf__group_sep_in_arg__fail_no_ouput),
     cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct),
     cmocka_unit_test (argv_parse_cmd__command_string__argc_correct),
     cmocka_unit_test (argv_parse_cmd__command_and_extra_options__argc_correct),
Signature · 1 line
2.7.4
#19 lore raw

Re: [Openvpn-devel] [PATCH 5/7] re-implement argv_printf_*()

Quoted 15 lines · Heiko Hund

The previous implementation had the problem that it was not fully compatible with printf() and could only detect % format directives following a space character (0x20).

It modifies the format string and inserts marks to separate groups before passing it to the regular printf in libc. The marks are later used to separate the output string into individual command line arguments.

The choice of '\035' as the argument delimiter is based on the assumption that no "regular" string passed to argv_printf_*() will ever have to contain that byte (and the fact that it actually is the ASCII "group separator" control character, which fits its purpose).

Quoted 8 lines
---
 src/openvpn/argv.c                   | 203 ++++++++++++++---------------------
 src/openvpn/argv.h                   |   4 +-
 src/openvpn/route.c                  |   8 +-
 src/openvpn/tun.c                    |  22 ++--
 tests/unit_tests/openvpn/test_argv.c |  34 +++++-
 5 files changed, 130 insertions(+), 141 deletions(-)

This one was harder to review. Had to use 'git diff --histogram' to make it easier to read and parse. And there I spotted a few odd things.

In the new argv_prep_format() function:

+ if (!in_token)
+ {
+ ++*count;
+ if (f[0])
+ f[j++] = delim;
+ }

What is the purpose of the f[0] check? At first glance it looks like a NOOP, as you'd expect f[0] to always have a value > 0. But that is just until you've parsed something which have been put into f, so I presume it is some kind of "lock" to not write a delimiter as the first byte in a string.

Can this whole function be made a bit simpler to understand, as I'm struggling to fully follow what happens and why? If I spend enough time digging into this, I will understand it ... but I prefer code which is easier to understand at first glance, unless the task can't be resolved with less complexity.

Suggestion: Why not just do a memmove()/memcpy() to the destination buffer first, then loop through the destination buffer and flip the in_token flag and replace spaces with delim where needed, but directly on the destination buffer? With this method, you could even skip the first byte easily before the loop.

So to argv_printf_arglist():

+  va_copy (tmplist, arglist);
+  len = vsnprintf (NULL, 0, f, tmplist);
+  va_end (tmplist);
+  if (len < 0)

+ goto out;

This is reasonably okay, but would benefit from a comment simply explaining what you do here. I presume it is a kind of estimated strlen() operation of the final formatted string.

The vsnprintf(NULL, 0, ...) should also have a little note, as this requires C99 mode to work - otherwise it will return something completely unexpected.

Otherwise it looks good. Valgrind tests reports no leaks, t_client.sh and t_lpback.sh tests are good. BUT t_cltsrv.sh fails, so that is also something which needs to be fixed. The error is:

Wed Nov  9 21:37:26 2016
Wed Nov  9 21:37:26 2016 openvpn_execve: called with empty argv
Wed Nov  9 21:37:26 2016 Exiting due to fatal error

Reverting this patch makes t_cltsrv.sh succeed, so pretty sure this patch is the one to blame for this error.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
author
#20 lore raw

Re: [Openvpn-devel] [PATCH 5/7] re-implement argv_printf_*()

Hi David,

Quoted 9 lines · CET David Sommerseth

In the new argv_prep_format() function:

src/openvpn/argv.c +6 -0
+      if (!in_token)
+        {
+          ++*count;
+          if (f[0])
+            f[j++] = delim;
+        }
Quoted 5 lines

What is the purpose of the f[0] check? At first glance it looks like a NOOP, as you'd expect f[0] to always have a value > 0. But that is just until you've parsed something which have been put into f, so I presume it is some kind of "lock" to not write a delimiter as the first byte in a string.

That check is there to not add a delimiter after leading spaces, I've added a comment in v2 of the patch.

Quoted 5 lines

Can this whole function be made a bit simpler to understand, as I'm struggling to fully follow what happens and why? If I spend enough time digging into this, I will understand it ... but I prefer code which is easier to understand at first glance, unless the task can't be resolved with less complexity.

Added comments to explain what's happening in argv_prep_format() and argv_printf_arglist(). Especially the first one does more than just copying the format string buffer, so its complexity is justified.

Quoted 11 lines

So to argv_printf_arglist():

src/openvpn/argv.c +5 -0
+  va_copy (tmplist, arglist);
+  len = vsnprintf (NULL, 0, f, tmplist);
+  va_end (tmplist);
+  if (len < 0)
+    goto out;

This is reasonably okay, but would benefit from a comment simply explaining what you do here. I presume it is a kind of estimated strlen() operation of the final formatted string.

Done.

Quoted 6 lines
Wed Nov  9 21:37:26 2016
Wed Nov  9 21:37:26 2016 openvpn_execve: called with empty argv
Wed Nov  9 21:37:26 2016 Exiting due to fatal error

Reverting this patch makes t_cltsrv.sh succeed, so pretty sure this patch is the one to blame for this error.

Nice catch! This was triggered by the use of strtok(), which only returns nonempty tokens. During shutdown openvpn passes empty strings to the down script, which triggered this. Not using strtok() anymore and also added a unit test for empty string parameters.

Cheers
Heiko

author
#21 lore raw

PATCH v2 5/7 re-implement argv_printf_*()

In reply to Heiko Hund

The previous implementation had the problem that it was not fully compatible with printf() and could only detect % format directives following a space character (0x20).

It modifies the format string and inserts marks to separate groups before passing it to the regular printf in libc. The marks are later used to separate the output string into individual command line arguments.

The choice of 035 as the argument delimiter is based on the assumption that no "regular" string passed to argv_printf_*() will ever have to contain that byte (and the fact that it actually is the ASCII "group separator" control character, which fits its purpose).

---
 src/openvpn/argv.c                   | 253 ++++++++++++++++-------------------
 src/openvpn/argv.h                   |   4 +-
 src/openvpn/route.c                  |   8 +-
 src/openvpn/tun.c                    |  24 ++--
 tests/unit_tests/openvpn/test_argv.c |  58 +++++++-
 5 files changed, 184 insertions(+), 163 deletions(-)
src/openvpn/argv.c +112 -141
index 95bdfeac..afe8efff 100644
@@ -130,64 +130,6 @@ argv_insert_head(const struct argv *a, const char *head)
     return r;
 }
 
-static char *
-argv_term(const char **f)
-{
-    const char *p = *f;
-    const char *term = NULL;
-    size_t termlen = 0;
-
-    if (*p == '\0')
-    {
-        return NULL;
-    }
-
-    while (true)
-    {
-        const int c = *p;
-        if (c == '\0')
-        {
-            break;
-        }
-        if (term)
-        {
-            if (!isspace(c))
-            {
-                ++termlen;
-            }
-            else
-            {
-                break;
-            }
-        }
-        else
-        {
-            if (!isspace(c))
-            {
-                term = p;
-                termlen = 1;
-            }
-        }
-        ++p;
-    }
-    *f = p;
-
-    if (term)
-    {
-        char *ret;
-        ASSERT(termlen > 0);
-        ret = malloc(termlen + 1);
-        check_malloc_return(ret);
-        memcpy(ret, term, termlen);
-        ret[termlen] = '\0';
-        return ret;
-    }
-    else
-    {
-        return NULL;
-    }
-}
-
 const char *
 argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {
@@ -217,112 +159,141 @@ argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
     gc_free(&gc);
 }
 
-static void
-argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
+/*
+ * argv_prep_format - prepare argv format string for further processing
+ *
+ * Individual argument must be separated by space. Ignores leading and trailing spaces.
+ * Consecutive spaces count as one. Returns prepared format string, with space replaced
+ * by delim and adds the number of arguments to the count parameter.
+ */
+static char *
+argv_prep_format(const char *format, const char delim, size_t *count, struct gc_arena *gc)
 {
-    char *term;
-    const char *f = format;
+    int i, j;
+    char *f;
+    bool in_token = false;
 
-    argv_extend(a, 1); /* ensure trailing NULL */
+    if (format == NULL)
+    {
+        return NULL;
+    }
 
-    while ((term = argv_term(&f)) != NULL)
+    f = gc_malloc(strlen(format) + 1, true, gc);
+    for (i = 0, j = 0; i < strlen(format); i++)
     {
-        if (term[0] == '%')
+        if (format[i] == ' ')
         {
-            if (!strcmp(term, "%s"))
-            {
-                char *s = va_arg(arglist, char *);
-                if (!s)
-                {
-                    s = "";
-                }
-                argv_append(a, string_alloc(s, NULL));
-            }
-            else if (!strcmp(term, "%d"))
-            {
-                char numstr[64];
-                openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int));
-                argv_append(a, string_alloc(numstr, NULL));
-            }
-            else if (!strcmp(term, "%u"))
-            {
-                char numstr[64];
-                openvpn_snprintf(numstr, sizeof(numstr), "%u", va_arg(arglist, unsigned int));
-                argv_append(a, string_alloc(numstr, NULL));
-            }
-            else if (!strcmp(term, "%s/%d"))
-            {
-                char numstr[64];
-                char *s = va_arg(arglist, char *);
-
-                if (!s)
-                {
-                    s = "";
-                }
-
-                openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int));
-
-                {
-                    const size_t len = strlen(s) + strlen(numstr) + 2;
-                    char *combined = (char *) malloc(len);
-                    check_malloc_return(combined);
-
-                    strcpy(combined, s);
-                    strcat(combined, "/");
-                    strcat(combined, numstr);
-                    argv_append(a, combined);
-                }
-            }
-            else if (!strcmp(term, "%s%sc"))
-            {
-                char *s1 = va_arg(arglist, char *);
-                char *s2 = va_arg(arglist, char *);
-                char *combined;
-
-                if (!s1)
-                {
-                    s1 = "";
-                }
-                if (!s2)
-                {
-                    s2 = "";
-                }
-                combined = (char *) malloc(strlen(s1) + strlen(s2) + 1);
-                check_malloc_return(combined);
-                strcpy(combined, s1);
-                strcat(combined, s2);
-                argv_append(a, combined);
-            }
-            else
-            {
-                ASSERT(0);
-            }
-            free(term);
+            in_token = false;
+            continue;
         }
-        else
+
+        if (!in_token)
         {
-            argv_append(a, term);
+            ++*count;
+            if (f[0]) /* not after leading spaces */
+            {
+                f[j++] = delim;
+            }
         }
+
+        f[j++] = format[i];
+        in_token = true;
     }
+
+    return f;
 }
 
-void
+/*
+ * argv_printf_arglist - create a struct argv from a format string
+ *
+ * Instead of parsing the format string ourselves place delimiters via argv_prep_format()
+ * before we let libc's printf() do the parsing. Then split the resulting string at the
+ * injected delimiters.
+ */
+static bool
+argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
+{
+    struct gc_arena gc = gc_new();
+    const char *delim = 035;
+    char *f, *buf, *end;
+    size_t argc, size;
+    bool res = false;
+    va_list tmplist;
+    int len;
+
+    argv_extend(a, 1); /* ensure trailing NULL */
+
+    argc = a->argc;
+    f = argv_prep_format(format, delim, &argc, &gc);
+    if (f == NULL)
+    {
+        goto out;
+    }
+
+    /* determine minimum buffer size */
+    va_copy(tmplist, arglist);
+    len = vsnprintf(NULL, 0, f, tmplist);
+    va_end(tmplist);
+    if (len < 0)
+    {
+        goto out;
+    }
+
+    size = adjust_power_of_2(len + 1);
+    buf = gc_malloc(size, false, &gc);
+    len = vsnprintf(buf, size, f, arglist);
+    if (len < 0 || len >= size)
+    {
+        goto out;
+    }
+
+    /* split the string at the delimiters */
+    end = strchr(buf, delim);
+    while (end)
+    {
+        *end = '\0';
+        argv_append(a, string_alloc(buf, NULL));
+        buf = end + 1;
+        end = strchr(buf, delim);
+    }
+    argv_append(a, string_alloc(buf, NULL));
+
+    if (a->argc != argc)
+    {
+        /* Someone snuck in a \035, fail gracefully */
+        argv_reset(a);
+        argv_extend(a, 1); /* ensure trailing NULL */
+        goto out;
+    }
+
+    res = true;
+
+out:
+    gc_free(&gc);
+    return res;
+}
+
+bool
 argv_printf(struct argv *a, const char *format, ...)
 {
+    bool res;
     va_list arglist;
-    argv_reset(a);
     va_start(arglist, format);
-    argv_printf_arglist(a, format, arglist);
+    argv_reset(a);
+    res = argv_printf_arglist(a, format, arglist);
     va_end(arglist);
+    return res;
 }
 
-void
+bool
 argv_printf_cat(struct argv *a, const char *format, ...)
 {
+    bool res;
     va_list arglist;
     va_start(arglist, format);
-    argv_printf_arglist(a, format, arglist);
+    res = argv_printf_arglist(a, format, arglist);
     va_end(arglist);
+    return res;
 }
 
 void
src/openvpn/argv.h +2 -2
index 7d0754c9..a24ba98f 100644
@@ -52,7 +52,7 @@ void argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
 
 void argv_parse_cmd(struct argv *a, const char *s);
 
-void argv_printf(struct argv *a, const char *format, ...)
+bool argv_printf(struct argv *a, const char *format, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
 __attribute__ ((format(gnu_printf, 2, 3)))
@@ -62,7 +62,7 @@ __attribute__ ((format(__printf__, 2, 3)))
 #endif
 ;
 
-void argv_printf_cat(struct argv *a, const char *format, ...)
+bool argv_printf_cat(struct argv *a, const char *format, ...)
 #ifdef __GNUC__
 #if __USE_MINGW_ANSI_STDIO
 __attribute__ ((format(gnu_printf, 2, 3)))
src/openvpn/route.c +4 -4
index 8c71e6ec..02f7299f 100644
@@ -1614,7 +1614,7 @@ add_route(struct route_ipv4 *r,
 #elif defined (_WIN32)
     {
         DWORD ai = TUN_ADAPTER_INDEX_INVALID;
-        argv_printf(&argv, "%s%sc ADD %s MASK %s %s",
+        argv_printf(&argv, "%s%s ADD %s MASK %s %s",
                     get_win_sys_path(),
                     WIN_ROUTE_PATH_SUFFIX,
                     network,
@@ -1979,7 +1979,7 @@ add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flag
         device = buf_bptr(&out);
 
         /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
-        argv_printf(&argv, "%s%sc interface ipv6 add route %s/%d %s",
+        argv_printf(&argv, "%s%s interface ipv6 add route %s/%d %s",
                     get_win_sys_path(),
                     NETSH_PATH_SUFFIX,
                     network,
@@ -2186,7 +2186,7 @@ delete_route(struct route_ipv4 *r,
 
 #elif defined (_WIN32)
 
-    argv_printf(&argv, "%s%sc DELETE %s MASK %s %s",
+    argv_printf(&argv, "%s%s DELETE %s MASK %s %s",
                 get_win_sys_path(),
                 WIN_ROUTE_PATH_SUFFIX,
                 network,
@@ -2426,7 +2426,7 @@ delete_route_ipv6(const struct route_ipv6 *r6, const struct tuntap *tt, unsigned
         device = buf_bptr(&out);
 
         /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
-        argv_printf(&argv, "%s%sc interface ipv6 delete route %s/%d %s",
+        argv_printf(&argv, "%s%s interface ipv6 delete route %s/%d %s",
                     get_win_sys_path(),
                     NETSH_PATH_SUFFIX,
                     network,
src/openvpn/tun.c +12 -12
index 25831ce3..61d6b9eb 100644
@@ -1565,7 +1565,7 @@ do_ifconfig(struct tuntap *tt,
                 char iface[64];
                 openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index );
                 argv_printf(&argv,
-                            "%s%sc interface ipv6 set address %s %s store=active",
+                            "%s%s interface ipv6 set address %s %s store=active",
                             get_win_sys_path(),
                             NETSH_PATH_SUFFIX,
                             iface,
@@ -5023,14 +5023,14 @@ ipconfig_register_dns(const struct env_set *es)
     msg(D_TUNTAP_INFO, "Start ipconfig commands for register-dns...");
     netcmd_semaphore_lock();
 
-    argv_printf(&argv, "%s%sc /flushdns",
+    argv_printf(&argv, "%s%s /flushdns",
                 get_win_sys_path(),
                 WIN_IPCONFIG_PATH_SUFFIX);
     argv_msg(D_TUNTAP_INFO, &argv);
     status = openvpn_execve_check(&argv, es, 0, err);
     argv_reset(&argv);
 
-    argv_printf(&argv, "%s%sc /registerdns",
+    argv_printf(&argv, "%s%s /registerdns",
                 get_win_sys_path(),
                 WIN_IPCONFIG_PATH_SUFFIX);
     argv_msg(D_TUNTAP_INFO, &argv);
@@ -5144,8 +5144,8 @@ netsh_set_dns6_servers(const struct in6_addr *addr_list,
     for (int i = 0; i < addr_len; ++i)
     {
         const char *fmt = (i == 0) ?
-                          "%s%sc interface ipv6 set dns %s static %s"
-                          : "%s%sc interface ipv6 add dns %s %s";
+                          "%s%s interface ipv6 set dns %s static %s"
+                          : "%s%s interface ipv6 add dns %s %s";
         argv_printf(&argv, fmt, get_win_sys_path(),
                     NETSH_PATH_SUFFIX, flex_name,
                     print_in6_addr(addr_list[i], 0, &gc));
@@ -5192,7 +5192,7 @@ netsh_ifconfig_options(const char *type,
     /* delete existing DNS/WINS settings from TAP interface */
     if (delete_first)
     {
-        argv_printf(&argv, "%s%sc interface ip delete %s %s all",
+        argv_printf(&argv, "%s%s interface ip delete %s %s all",
                     get_win_sys_path(),
                     NETSH_PATH_SUFFIX,
                     type,
@@ -5209,8 +5209,8 @@ netsh_ifconfig_options(const char *type,
             if (delete_first || !test_first || !ip_addr_member_of(addr_list[i], current))
             {
                 const char *fmt = count ?
-                                  "%s%sc interface ip add %s %s %s"
-                                  : "%s%sc interface ip set %s %s static %s";
+                                  "%s%s interface ip add %s %s %s"
+                                  : "%s%s interface ip set %s %s static %s";
 
                 argv_printf(&argv, fmt,
                             get_win_sys_path(),
@@ -5286,7 +5286,7 @@ netsh_ifconfig(const struct tuntap_options *to,
         else
         {
             /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
-            argv_printf(&argv, "%s%sc interface ip set address %s static %s %s",
+            argv_printf(&argv, "%s%s interface ip set address %s static %s %s",
                         get_win_sys_path(),
                         NETSH_PATH_SUFFIX,
                         flex_name,
@@ -5335,7 +5335,7 @@ netsh_enable_dhcp(const struct tuntap_options *to,
 
     /* example: netsh interface ip set address my-tap dhcp */
     argv_printf(&argv,
-                "%s%sc interface ip set address %s dhcp",
+                "%s%s interface ip set address %s dhcp",
                 get_win_sys_path(),
                 NETSH_PATH_SUFFIX,
                 actual_name);
@@ -6197,7 +6197,7 @@ close_tun(struct tuntap *tt)
                 /* netsh interface ipv6 delete address \"%s\" %s */
                 ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0,  &gc);
                 argv_printf(&argv,
-                            "%s%sc interface ipv6 delete address %s %s store=active",
+                            "%s%s interface ipv6 delete address %s %s store=active",
                             get_win_sys_path(),
                             NETSH_PATH_SUFFIX,
                             tt->actual_name,
@@ -6209,7 +6209,7 @@ close_tun(struct tuntap *tt)
                 if (tt->options.dns6_len > 0)
                 {
                     argv_printf(&argv,
-                                "%s%sc interface ipv6 delete dns %s all",
+                                "%s%s interface ipv6 delete dns %s all",
                                 get_win_sys_path(),
                                 NETSH_PATH_SUFFIX,
                                 tt->actual_name);
tests/unit_tests/openvpn/test_argv.c +54 -4

97 lines not on this page · raw message

Signature · 1 line
2.11.0
#22 lore raw

Re: [Openvpn-devel] [PATCHv2 5/7] re-implement argv_printf_*()

Hey,

Thanks a lot for putting a renewed effort into this. I've reviewed this and compile tested with GCC 4.8.5, 6.3.1 and 7.2.1 - as there are some warnings appearing; I'll come back to them in a bit.

Quoted 10 lines · Heiko Hund

The previous implementation had the problem that it was not fully compatible with printf() and could only detect % format directives following a space character (0x20).

It modifies the format string and inserts marks to separate groups before passing it to the regular printf in libc. The marks are later used to separate the output string into individual command line arguments.

The choice of 035 as the argument delimiter is based on the

Perhaps we should use the hex notation (0x1D) instead of the octal notation (035). The octal notation is just so similar to decimal notation and the leading 0 is quite a critical difference.

Quoted 18 lines

assumption that no "regular" string passed to argv_printf_*() will ever have to contain that byte (and the fact that it actually is the ASCII "group separator" control character, which fits its purpose).

---
 src/openvpn/argv.c                   | 253 ++++++++++++++++-------------------
 src/openvpn/argv.h                   |   4 +-
 src/openvpn/route.c                  |   8 +-
 src/openvpn/tun.c                    |  24 ++--
 tests/unit_tests/openvpn/test_argv.c |  58 +++++++-
 5 files changed, 184 insertions(+), 163 deletions(-)
src/openvpn/argv.c +0 -0
index 95bdfeac..afe8efff 100644

[...snip...]

src/openvpn/argv.c argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) · line 168

Quoted 10 lines
src/openvpn/argv.c +7 -2
-static void
-argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
+/*
+ * argv_prep_format - prepare argv format string for further processing
+ *
+ * Individual argument must be separated by space. Ignores leading and trailing spaces.
+ * Consecutive spaces count as one. Returns prepared format string, with space replaced
+ * by delim and adds the number of arguments to the count parameter.
+ */

Could we make this comment proper Doxygen? (As well as adding similar things for the other functions as well?)

Quoted 3 lines
src/openvpn/argv.c +2 -0
+static char *
+argv_prep_format(const char *format, const char delim, size_t *count, struct gc_arena *gc)
 {

[...snip...]

src/openvpn/argv.c argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) · line 193

Quoted 6 lines
src/openvpn/argv.c +4 -1
+
+        if (!in_token)
         {
-            argv_append(a, term);
+            ++*count;
+            if (f[0]) /* not after leading spaces */

This comment still confuses me :-/

Would this be a correct understanding?

/*
* We don't add any delimiter (group separator)
* to the resulting format string before something
* has been added there. The resulting format
* string will never start with a delimiter. */

Quoted 15 lines
src/openvpn/argv.c +10 -1
+            {
+                f[j++] = delim;
+            }
         }
+
+        f[j++] = format[i];
+        in_token = true;
     }
+
+    return f;
 }
 
-void
+/*
+ * argv_printf_arglist - create a struct argv from a format string

src/openvpn/argv.c argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) · line 217

Quoted 10 lines
src/openvpn/argv.c +10 -0
+ *
+ * Instead of parsing the format string ourselves place delimiters via argv_prep_format()
+ * before we let libc's printf() do the parsing. Then split the resulting string at the
+ * injected delimiters.
+ */
+static bool
+argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
+{
+    struct gc_arena gc = gc_new();
+    const char *delim = 035;

argv.c:217:25: warning: initialization makes pointer from integer without a cast [-Wint-conversion]

     const char *delim = 035;

argv.c:227:34: warning: passing argument 2 of ‘argv_prep_format’ makes integer from pointer without a cast [-Wint-conversion]

     f = argv_prep_format(format, delim, &argc, &gc);
                                  ^~~~~

argv.c:170:1: note: expected ‘char’ but argument is of type ‘const char *’
argv_prep_format(const char *format, const char delim, size_t *count, struct gc_arena *gc) ^~~~~~~~~~~~~~~~
argv.c:251:23: warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast [-Wint-conversion]

     end = strchr(buf, delim);
                       ^~~~~
In file included from /usr/include/sys/un.h:37:0,
                 from syshead.h:88,
                 from argv.c:36:
/usr/include/string.h:232:14: note: expected ‘int’ but argument is of type ‘const char *’
 extern char *strchr (const char *__s, int __c)
              ^~~~~~
argv.c:257:27: warning: passing argument 2 of ‘strchr’ makes integer from pointer without a cast [-Wint-conversion]
         end = strchr(buf, delim);
                           ^~~~~
In file included from /usr/include/sys/un.h:37:0,
                 from syshead.h:88,
                 from argv.c:36:
/usr/include/string.h:232:14: note: expected ‘int’ but argument is of type ‘const char *’
 extern char *strchr (const char *__s, int __c)
              ^~~~~~

Shouldn't *delim be just delim? I'd propose using:

const char delim = 0x1D; /* ASCII group separator character */

This also kills all the warnings above.

Quoted 36 lines
src/openvpn/argv.c +36 -0
+    char *f, *buf, *end;
+    size_t argc, size;
+    bool res = false;
+    va_list tmplist;
+    int len;
+
+    argv_extend(a, 1); /* ensure trailing NULL */
+
+    argc = a->argc;
+    f = argv_prep_format(format, delim, &argc, &gc);
+    if (f == NULL)
+    {
+        goto out;
+    }
+
+    /* determine minimum buffer size */
+    va_copy(tmplist, arglist);
+    len = vsnprintf(NULL, 0, f, tmplist);
+    va_end(tmplist);
+    if (len < 0)
+    {
+        goto out;
+    }
+
+    size = adjust_power_of_2(len + 1);
+    buf = gc_malloc(size, false, &gc);
+    len = vsnprintf(buf, size, f, arglist);
+    if (len < 0 || len >= size)
+    {
+        goto out;
+    }
+
+    /* split the string at the delimiters */
+    end = strchr(buf, delim);
+    while (end)
+    {

src/openvpn/argv.c argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) · line 263

Quoted 10 lines
src/openvpn/argv.c +10 -0
+        *end = '\0';
+        argv_append(a, string_alloc(buf, NULL));
+        buf = end + 1;
+        end = strchr(buf, delim);
+    }
+    argv_append(a, string_alloc(buf, NULL));
+
+    if (a->argc != argc)
+    {
+        /* Someone snuck in a \035, fail gracefully */

I'd prefer 0x1D here too.

src/openvpn/route.c add_route(struct route_ipv4 *r, · line 1617

Quoted 10 lines
src/openvpn/route.c +1 -1
index 8c71e6ec..02f7299f 100644
@@ -1614,7 +1614,7 @@ add_route(struct route_ipv4 *r,
 #elif defined (_WIN32)
     {
         DWORD ai = TUN_ADAPTER_INDEX_INVALID;
-        argv_printf(&argv, "%s%sc ADD %s MASK %s %s",
+        argv_printf(&argv, "%s%s ADD %s MASK %s %s",

[...snip... comment to follow ....]

src/openvpn/tun.c do_ifconfig(struct tuntap *tt, · line 1568

Quoted 10 lines
src/openvpn/tun.c +1 -1
index 25831ce3..61d6b9eb 100644
@@ -1565,7 +1565,7 @@ do_ifconfig(struct tuntap *tt,
                 char iface[64];
                 openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index );
                 argv_printf(&argv,
-                            "%s%sc interface ipv6 set address %s %s store=active",
+                            "%s%s interface ipv6 set address %s %s store=active",

Even though these changes from %sc to %s are no-brainers; I wonder if we should try to trick our buildbot to test these changes on all platforms we have there before pushing it out.

Quoted 4 lines
tests/unit_tests/openvpn/test_argv.c +0 -0
index 4a3ba559..a09e92fb 100644

[...snip...]

Quoted 11 lines

static void

tests/unit_tests/openvpn/test_argv.c +10 -0
+argv_printf__empty_parameter__argc_correct(void **state)
+{
+    struct argv a = argv_new();
+
+    argv_printf(&a, "%s", "");
+    assert_int_equal(a.argc, 1);
+
+    argv_printf(&a, "%s %s", PATH1, "");
+    assert_int_equal(a.argc, 2);
+

tests/unit_tests/openvpn/test_argv.c argv_printf_cat__multiple_spaces_in_format__parsed_as_one(void **state) · line 117

Quoted 10 lines
tests/unit_tests/openvpn/test_argv.c +10 -0
+    argv_printf(&a, "%s %s %s", PATH1, "", PARAM1);
+    assert_int_equal(a.argc, 3);
+
+    argv_printf(&a, "%s %s %s %s", PATH1, "", "", PARAM1);
+    assert_int_equal(a.argc, 4);
+
+    argv_printf(&a, "%s %s", "", PARAM1);
+    assert_int_equal(a.argc, 2);
+
+    argv_free(&a);

This gives another warning:

est_argv.c: In function ‘argv_printf__empty_parameter__argc_correct’:
test_argv.c:117:5: warning: implicit declaration of function ‘argv_free’; did you mean ‘argv_reset’? [-Wimplicit-function-declaration]

     argv_free(&a);
     ^~~~~~~~~
     argv_reset

This stops the build of argv_testdriver. Changing it to argv_reset() completes and runs the unit test.

Quoted 1 line

+}

[...snip...]

I'm also getting this warning:

test_argv.c:174:1: warning: ‘argv_insert_head__empty_argv__head_only’ defined but not used [-Wunused-function]
argv_insert_head__empty_argv__head_only(void **state)

Otherwise, this patch looks reasonable and good to me. And it passes 'make check' when fixing those various warnings mentioned above

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN, Inc
#23 lore raw

Re: [Openvpn-devel] [PATCHv2 5/7] re-implement argv_printf_*()

Hi,

I'm going through open patches in patchwork, and noticed the argv stuff
- I remembered that David had reviewed it, but going through the mails now I can see that we have no ACK yet, because there are changes needed.

Quoted 3 lines · David Sommerseth

Thanks a lot for putting a renewed effort into this. I've reviewed this and compile tested with GCC 4.8.5, 6.3.1 and 7.2.1 - as there are some warnings appearing; I'll come back to them in a bit.

[..]

Quoted 11 lines

src/openvpn/argv.c argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) · line 217

Quoted 4 lines
src/openvpn/argv.c +4 -0
+argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
+{
+    struct gc_arena gc = gc_new();
+    const char *delim = 035;

argv.c:217:25: warning: initialization makes pointer from integer without a cast [-Wint-conversion]

     const char *delim = 035;

argv.c:227:34: warning: passing argument 2 of ???argv_prep_format??? makes integer from pointer without a cast [-Wint-conversion]

     f = argv_prep_format(format, delim, &argc, &gc);
                                  ^~~~~

This really is a bug. It's declared to be a pointer, but it is used to just transport "an integer value" (035). It is valid C, but the compiler is correct in questioning our motives...

Quoted 5 lines

Shouldn't *delim be just delim? I'd propose using:

const char delim = 0x1D; /* ASCII group separator character */

This also kills all the warnings above.

Yes.

Heiko, can you do a v3 round of the remaining argv patches, taking David's comments into account? Then we can get it into master and finish this work...

thanks!

gert

Signature · 6 lines
"If was one thing all people took for granted, was conviction that if you 
 feed honest figures into a computer, honest figures come out. Never doubted 
 it myself till I met a computer with a sense of humor."
                             Robert A. Heinlein, The Moon is a Harsh Mistress

Gert Doering - Munich, Germany                             [email protected]...
author
#24 lore raw

PATCH 6/7 argv: do fewer memory re-allocations

In reply to Heiko Hund

Prevent the re-allocations of memory when the internal argv grows beyond 2 and 4 arguments by initially allocating argv to hold up to 7 (+ trailing NULL) pointers.

While at it rename argv_reset to argv_free to actually express what's going on. Redo the argv_reset functionality so that it can be used to actually reset the argv without re-allocation.

---
 src/openvpn/argv.c                   | 45 ++++++++++++++++++++----------------
 src/openvpn/argv.h                   |  2 +-
 src/openvpn/console_systemd.c        |  2 +-
 src/openvpn/init.c                   |  2 +-
 src/openvpn/lladdr.c                 |  2 +-
 src/openvpn/misc.c                   |  4 ++--
 src/openvpn/multi.c                  | 10 ++++----
 src/openvpn/options.c                |  2 +-
 src/openvpn/plugin.c                 |  2 +-
 src/openvpn/route.c                  |  8 +++----
 src/openvpn/socket.c                 |  4 ++--
 src/openvpn/ssl_verify.c             |  6 ++---
 src/openvpn/tun.c                    | 23 ++++++++----------
 tests/unit_tests/openvpn/test_argv.c | 41 +++++++++++++++++++++-----------
 14 files changed, 85 insertions(+), 68 deletions(-)
src/openvpn/argv.c +25 -20
index dcfbd76..664785b 100644
@@ -41,11 +41,28 @@
 #include "options.h"
 
 static void
+argv_extend (struct argv *a, const size_t newcap)
+{
+  if (newcap > a->capacity)
+    {
+      char **newargv;
+      size_t i;
+      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
+      for (i = 0; i < a->argc; ++i)
+        newargv[i] = a->argv[i];
+      free (a->argv);
+      a->argv = newargv;
+      a->capacity = newcap;
+    }
+}
+
+static void
 argv_init (struct argv *a)
 {
   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;
+  argv_extend (a, 8);
 }
 
 struct argv
@@ -57,29 +74,24 @@ argv_new (void)
 }
 
 void
-argv_reset (struct argv *a)
+argv_free (struct argv *a)
 {
   size_t i;
   for (i = 0; i < a->argc; ++i)
     free (a->argv[i]);
   free (a->argv);
-  argv_init (a);
 }
 
 static void
-argv_extend (struct argv *a, const size_t newcap)
+argv_reset (struct argv *a)
 {
-  if (newcap > a->capacity)
+  size_t i;
+  for (i = 0; i < a->argc; ++i)
     {
-      char **newargv;
-      size_t i;
-      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
-      for (i = 0; i < a->argc; ++i)
-        newargv[i] = a->argv[i];
-      free (a->argv);
-      a->argv = newargv;
-      a->capacity = newcap;
+      free (a->argv[i]);
+      a->argv[i] = NULL;
     }
+  a->argc = 0;
 }
 
 static void
@@ -126,10 +138,7 @@ argv_insert_head (const struct argv *a, const char *head)
 const char *
 argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {
-  if (a->argv)
-    return print_argv ((const char **)a->argv, gc, flags);
-  else
-    return "";
+  return print_argv ((const char **)a->argv, gc, flags);
 }
 
 void
@@ -191,8 +200,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
   va_list tmplist;
   int len;
 
-  argv_extend (a, 1); /* ensure trailing NULL */
-
   argc = a->argc;
   f = argv_prep_format (format, delim[0], &argc, &gc);
   if (f == NULL)
@@ -221,7 +228,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
     {
       /* Someone snuck in a \035, fail gracefully */
       argv_reset (a);
-      argv_extend (a, 1); /* ensure trailing NULL */
       goto out;
     }
 
@@ -263,7 +269,6 @@ argv_parse_cmd (struct argv *a, const char *s)
   struct gc_arena gc = gc_new ();
 
   argv_reset (a);
-  argv_extend (a, 1); /* ensure trailing NULL */
 
   nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
   if (nparms)
src/openvpn/argv.h +1 -1
index ff3933e..99fd7ad 100644
@@ -40,7 +40,7 @@ struct argv {
 };
 
 struct argv argv_new (void);
-void argv_reset (struct argv *a);
+void argv_free (struct argv *a);
 const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
 struct argv argv_insert_head (const struct argv *a, const char *head);
 void argv_msg (const int msglev, const struct argv *a);
src/openvpn/console_systemd.c +1 -1
index 8a953c9..c8edf67 100644
@@ -84,7 +84,7 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con
     }
     close (std_out);
 
-    argv_reset (&argv);
+    argv_free (&argv);
 
     return ret;
 }
src/openvpn/init.c +1 -1
index 56140b3..ab49262 100644
@@ -1364,7 +1364,7 @@ do_route (const struct options *options,
       setenv_str (es, "script_type", "route-up");
       argv_parse_cmd (&argv, options->route_script);
       openvpn_run_script (&argv, es, 0, "--route-up");
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
 #ifdef WIN32
src/openvpn/lladdr.c +1 -1
index 57f447b..94d9f08 100644
@@ -62,6 +62,6 @@ int set_lladdr(const char *ifname, const char *lladdr,
   if (r)
     msg (M_INFO, "TUN/TAP link layer address set to %s", lladdr);
 
-  argv_reset (&argv);
+  argv_free (&argv);
   return r;
 }
src/openvpn/misc.c +2 -2
index b433df6..309cc5f 100644
@@ -112,7 +112,7 @@ run_up_down (const char *command,
       if (plugin_call (plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
 	msg (M_FATAL, "ERROR: up/down plugin call failed");
 
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   if (command)
@@ -125,7 +125,7 @@ run_up_down (const char *command,
                        ifconfig_local, ifconfig_remote, context);
       argv_msg (M_INFO, &argv);
       openvpn_run_script (&argv, es, S_FATAL, "--up/--down");
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   gc_free (&gc);
src/openvpn/multi.c +5 -5
index 9c75f7b..deb80f7 100644
@@ -119,7 +119,7 @@ learn_address_script (const struct multi_context *m,
 	  msg (M_WARN, "WARNING: learn-address plugin call failed");
 	  ret = false;
 	}
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   if (m->top.options.learn_address_script)
@@ -132,7 +132,7 @@ learn_address_script (const struct multi_context *m,
 	argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
       if (!openvpn_run_script (&argv, es, 0, "--learn-address"))
 	ret = false;
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   gc_free (&gc);
@@ -545,7 +545,7 @@ multi_client_disconnect_script (struct multi_context *m,
 	  setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
 	  argv_parse_cmd (&argv, mi->context.options.client_disconnect_script);
 	  openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect");
-	  argv_reset (&argv);
+	  argv_free (&argv);
 	}
 #ifdef MANAGEMENT_DEF_AUTH
       if (management)
@@ -1791,7 +1791,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 		 dc_file);
 
         script_depr_failed:
-	  argv_reset (&argv);
+	  argv_free (&argv);
 	}
 
       /* V2 callback, use a plugin_return struct for passing back return info */
@@ -1848,7 +1848,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 		 dc_file);
 
         script_failed:
-	  argv_reset (&argv);
+	  argv_free (&argv);
 	}
 
       /*
src/openvpn/options.c +1 -1
index 557299a..fda51ac 100644
@@ -2794,7 +2794,7 @@ check_cmd_access(const char *command, const char *opt, const char *chroot)
       return_code = true;
     }
 
-  argv_reset (&argv);
+  argv_free (&argv);
 
   return return_code;
 }
src/openvpn/plugin.c +1 -1
index 542e5b1..439ec00 100644
@@ -500,7 +500,7 @@ plugin_call_item (const struct plugin *p,
 	     status,
 	     p->so_pathname);
 
-      argv_reset (&a);
+      argv_free (&a);
       gc_free (&gc);
     }
   return status;
src/openvpn/route.c +4 -4
index ca1e0a7..07ab2b2 100644
@@ -1642,7 +1642,7 @@ add_route (struct route_ipv4 *r,
     r->flags |= RT_ADDED;
   else
     r->flags &= ~RT_ADDED;
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
@@ -1919,7 +1919,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
     r6->flags |= RT_ADDED;
   else
     r6->flags &= ~RT_ADDED;
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
@@ -2097,7 +2097,7 @@ delete_route (struct route_ipv4 *r,
 
  done:
   r->flags &= ~RT_ADDED;
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
@@ -2307,7 +2307,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
   msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-down script");
 #endif
 
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
src/openvpn/socket.c +2 -2
index bb7cba1..c9067a5 100644
@@ -2063,7 +2063,7 @@ link_socket_connection_initiated (const struct buffer *buf,
       ipchange_fmt (false, &argv, info, &gc);
       if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
 	msg (M_WARN, "WARNING: ipchange plugin call failed");
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   /* Process --ipchange option */
@@ -2073,7 +2073,7 @@ link_socket_connection_initiated (const struct buffer *buf,
       setenv_str (es, "script_type", "ipchange");
       ipchange_fmt (true, &argv, info, &gc);
       openvpn_run_script (&argv, es, 0, "--ipchange");
-      argv_reset (&argv);
+      argv_free (&argv);
     }
 
   gc_free (&gc);
src/openvpn/ssl_verify.c +3 -3
index be9f224..7dbf2e6 100644
@@ -447,7 +447,7 @@ verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es,
 
       ret = plugin_call_ssl (plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert);
 
-      argv_reset (&argv);
+      argv_free (&argv);
 
       if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
 	{
@@ -527,7 +527,7 @@ verify_cert_call_command(const char *verify_command, struct env_set *es,
     }
 
   gc_free(&gc);
-  argv_reset (&argv);
+  argv_free (&argv);
 
   if (ret)
     {
@@ -1001,7 +1001,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
   if (tmp_file && strlen (tmp_file) > 0)
     platform_unlink (tmp_file);
 
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
   return ret;
 }
src/openvpn/tun.c +10 -13
index 843df16..ab0c168 100644
@@ -1376,7 +1376,7 @@ do_ifconfig (struct tuntap *tt,
 #else
       msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system.  You should ifconfig your TUN/TAP device manually or use an --up script.");
 #endif
-      argv_reset (&argv);
+      argv_free (&argv);
     }
   gc_free (&gc);
 }
@@ -1903,7 +1903,7 @@ close_tun (struct tuntap *tt)
 #endif
               }
 
-	    argv_reset (&argv);
+	    argv_free (&argv);
 	    gc_free (&gc);
 	  }
       close_tun_generic (tt);
@@ -2131,7 +2131,7 @@ solaris_close_tun (struct tuntap *tt)
 		       IFCONFIG_PATH, tt->actual_name );
 	  argv_msg (M_INFO, &argv);
 	  openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
-	  argv_reset (&argv);
+	  argv_free (&argv);
 	}
 
       if (tt->ip_fd >= 0)
@@ -2208,7 +2208,7 @@ solaris_error_close (struct tuntap *tt, const struct env_set *es,
   openvpn_execve_check (&argv, es, 0, "Solaris ifconfig unplumb failed");
   close_tun (tt);
   msg (M_FATAL, "Solaris ifconfig failed");
-  argv_reset (&argv);
+  argv_free (&argv);
 }
 
 int
@@ -2835,7 +2835,7 @@ close_tun (struct tuntap* tt)
 
       close_tun_generic (tt);
       free (tt);
-      argv_reset (&argv);
+      argv_free (&argv);
       gc_free (&gc);
     }
 }
@@ -4495,31 +4495,28 @@ ipconfig_register_dns (const struct env_set *es)
 	       WIN_NET_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
-  argv_reset(&argv);
 
   argv_printf (&argv, "%s%s start dnscache",
 	       get_win_sys_path(),
 	       WIN_NET_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
-  argv_reset(&argv);
 
   argv_printf (&argv, "%s%s /flushdns",
 	       get_win_sys_path(),
 	       WIN_IPCONFIG_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
-  argv_reset(&argv);
 
   argv_printf (&argv, "%s%s /registerdns",
 	       get_win_sys_path(),
 	       WIN_IPCONFIG_PATH_SUFFIX);
   argv_msg (D_TUNTAP_INFO, &argv);
   status = openvpn_execve_check (&argv, es, 0, err);
-  argv_reset(&argv);
 
   netcmd_semaphore_release ();
   msg (D_TUNTAP_INFO, "End net commands...");
+  argv_free (&argv);
 }
 
 void
@@ -4660,7 +4657,7 @@ netsh_ifconfig_options (const char *type,
       }
   }
 
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
@@ -4749,7 +4746,7 @@ netsh_ifconfig (const struct tuntap_options *to,
 			      BOOL_CAST (flags & NI_TEST_FIRST));
     }
   
-  argv_reset (&argv);
+  argv_free (&argv);
   gc_free (&gc);
 }
 
@@ -4768,7 +4765,7 @@ netsh_enable_dhcp (const struct tuntap_options *to,
 
   netsh_command (&argv, 4, M_FATAL);
 
-  argv_reset (&argv);
+  argv_free (&argv);
 }
 
 /*
@@ -5542,7 +5539,7 @@ close_tun (struct tuntap *tt)
                            ifconfig_ipv6_local);
 
               netsh_command (&argv, 1, M_WARN);
-              argv_reset (&argv);
+              argv_free (&argv);
             }
 	}
 #if 1
tests/unit_tests/openvpn/test_argv.c +28 -13

115 lines not on this page · raw message

Signature · 1 line
2.7.4
#25 lore raw

Re: [Openvpn-devel] [PATCH 6/7] argv: do fewer memory re-allocations

Quoted 9 lines · Heiko Hund

Prevent the re-allocations of memory when the internal argv grows beyond 2 and 4 arguments by initially allocating argv to hold up to 7 (+ trailing NULL) pointers.

While at it rename argv_reset to argv_free to actually express what's going on. Redo the argv_reset functionality so that it can be used to actually reset the argv without re-allocation.

Quoted 17 lines
---
 src/openvpn/argv.c                   | 45 ++++++++++++++++++++----------------
 src/openvpn/argv.h                   |  2 +-
 src/openvpn/console_systemd.c        |  2 +-
 src/openvpn/init.c                   |  2 +-
 src/openvpn/lladdr.c                 |  2 +-
 src/openvpn/misc.c                   |  4 ++--
 src/openvpn/multi.c                  | 10 ++++----
 src/openvpn/options.c                |  2 +-
 src/openvpn/plugin.c                 |  2 +-
 src/openvpn/route.c                  |  8 +++----
 src/openvpn/socket.c                 |  4 ++--
 src/openvpn/ssl_verify.c             |  6 ++---
 src/openvpn/tun.c                    | 23 ++++++++----------
 tests/unit_tests/openvpn/test_argv.c | 41 +++++++++++++++++++++-----------
 14 files changed, 85 insertions(+), 68 deletions(-)

Code looks fairly reasonable, but I have a few comments ...

Quoted 6 lines

argv_init (struct argv *a)

 {
   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;

+ argv_extend (a, 8);

Why 8? Done any performance and/or memory utilization tests? Does the overall memory consumption increase with this?

src/openvpn/argv.c argv_new (void) · line 77

Quoted 3 lines

void

src/openvpn/argv.c +1 -1
-argv_reset (struct argv *a)
+argv_free (struct argv *a)

This makes more sense :)

src/openvpn/argv.c argv_insert_head (const struct argv *a, const char *head) · line 141

Quoted 9 lines
src/openvpn/argv.c +1 -4
@@ -126,10 +138,7 @@ argv_insert_head (const struct argv *a, const char *head)
 const char *
 argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {
-  if (a->argv)
-    return print_argv ((const char **)a->argv, gc, flags);
-  else
-    return "";
+  return print_argv ((const char **)a->argv, gc, flags);

There are very few callers of print_argv() (defined in buffer.c). Should we migrate print_argv() into this function and move all callers over to argv_str() instead?

src/openvpn/tun.c

Quoted 3 lines
src/openvpn/tun.c +0 -0

tun.c:2360 close_tun() seems to be missing a argv_free(), or? The same goes for close_tun() in tun.c:2482 and tun.c:2956 (tun.c:2821 does have it though).

Similarly, in open_tun() [tun.c:2926], argv_new() is called but no argv_free() calls.

On a not so related note. I noticed that init.c have a #ifdef ARGV_TEST block. That should probably also be killed; no need for that as we have unit tests - and the argv_test() function it calls no longer exists.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
author
#26 lore raw

Re: [Openvpn-devel] [PATCH 6/7] argv: do fewer memory re-allocations

Quoted 11 lines · CET David Sommerseth
Quoted 8 lines

argv_init (struct argv *a)
{

   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;

+ argv_extend (a, 8);

Why 8? Done any performance and/or memory utilization tests? Does the overall memory consumption increase with this?

I figured it is a fine initial length for the argv vector. No science behind it whatsoever. If 8 doesn't suffice the argv is reallocated.

Quoted 6 lines
Quoted 6 lines
(quoted diff) +0 -0
@@ -126,10 +138,7 @@ argv_insert_head (const struct argv *a, const char
 *head)> 
 const char *
 argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int
 flags) {
 
Quoted 9 lines

src/openvpn/argv.c argv_insert_head (const struct argv *a, const char *head) · line 141

Quoted 5 lines
src/openvpn/argv.c +1 -4
-  if (a->argv)
-    return print_argv ((const char **)a->argv, gc, flags);
-  else
-    return "";
+  return print_argv ((const char **)a->argv, gc, flags);

There are very few callers of print_argv() (defined in buffer.c). Should we migrate print_argv() into this function and move all callers over to argv_str() instead?

print_argv actually prints a char** and is not affiliated with struct argv, even though its name suggests it. So, if we want to do it it should be an add-on done after this patchset.

Quoted 10 lines

src/openvpn/tun.c

Quoted 3 lines
src/openvpn/tun.c +0 -0

tun.c:2360 close_tun() seems to be missing a argv_free(), or? The same goes for close_tun() in tun.c:2482 and tun.c:2956 (tun.c:2821 does have it though).

Similarly, in open_tun() [tun.c:2926], argv_new() is called but no argv_free() calls.

Nice catch, they were missing back in the argv_reset days as well. While at it, also removed a couple of unused struct gc_arena.

Quoted 4 lines

On a not so related note. I noticed that init.c have a #ifdef ARGV_TEST block. That should probably also be killed; no need for that as we have unit tests - and the argv_test() function it calls no longer exists.

Aaand it's gone.

Cheers
Heiko

author
#27 lore raw

PATCH v2 6/7 argv: do fewer memory re-allocations

In reply to Heiko Hund

Prevent the re-allocations of memory when the internal argv grows beyond 2 and 4 arguments by initially allocating argv to hold up to 7 (+ trailing NULL) pointers.

While at it rename argv_reset to argv_free to actually express what's going on. Redo the argv_reset functionality so that it can be used to actually reset the argv without re-allocation.

---
 src/openvpn/argv.c                   | 53 ++++++++++++++++++------------------
 src/openvpn/argv.h                   |  2 +-
 src/openvpn/console_systemd.c        |  2 +-
 src/openvpn/init.c                   | 15 ++--------
 src/openvpn/lladdr.c                 |  2 +-
 src/openvpn/multi.c                  | 10 +++----
 src/openvpn/options.c                |  2 +-
 src/openvpn/plugin.c                 |  2 +-
 src/openvpn/route.c                  |  8 +++---
 src/openvpn/socket.c                 |  4 +--
 src/openvpn/ssl_verify.c             |  6 ++--
 src/openvpn/tun.c                    | 32 ++++++++++++----------
 tests/unit_tests/openvpn/test_argv.c | 41 +++++++++++++++++++---------
 13 files changed, 94 insertions(+), 85 deletions(-)
src/openvpn/argv.c +27 -26
index afe8efff..419b1dc6 100644
@@ -40,11 +40,30 @@
 #include "options.h"
 
 static void
+argv_extend(struct argv *a, const size_t newcap)
+{
+    if (newcap > a->capacity)
+    {
+        char **newargv;
+        size_t i;
+        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
+        for (i = 0; i < a->argc; ++i)
+        {
+            newargv[i] = a->argv[i];
+        }
+        free(a->argv);
+        a->argv = newargv;
+        a->capacity = newcap;
+    }
+}
+
+static void
 argv_init(struct argv *a)
 {
     a->capacity = 0;
     a->argc = 0;
     a->argv = NULL;
+    argv_extend(a, 8);
 }
 
 struct argv
@@ -56,7 +75,7 @@ argv_new(void)
 }
 
 void
-argv_reset(struct argv *a)
+argv_free(struct argv *a)
 {
     size_t i;
     for (i = 0; i < a->argc; ++i)
@@ -64,25 +83,18 @@ argv_reset(struct argv *a)
         free(a->argv[i]);
     }
     free(a->argv);
-    argv_init(a);
 }
 
 static void
-argv_extend(struct argv *a, const size_t newcap)
+argv_reset(struct argv *a)
 {
-    if (newcap > a->capacity)
+    size_t i;
+    for (i = 0; i < a->argc; ++i)
     {
-        char **newargv;
-        size_t i;
-        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
-        for (i = 0; i < a->argc; ++i)
-        {
-            newargv[i] = a->argv[i];
-        }
-        free(a->argv);
-        a->argv = newargv;
-        a->capacity = newcap;
+        free(a->argv[i]);
+        a->argv[i] = NULL;
     }
+    a->argc = 0;
 }
 
 static void
@@ -133,14 +145,7 @@ argv_insert_head(const struct argv *a, const char *head)
 const char *
 argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {
-    if (a->argv)
-    {
-        return print_argv((const char **)a->argv, gc, flags);
-    }
-    else
-    {
-        return "";
-    }
+    return print_argv((const char **)a->argv, gc, flags);
 }
 
 void
@@ -221,8 +226,6 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     va_list tmplist;
     int len;
 
-    argv_extend(a, 1); /* ensure trailing NULL */
-
     argc = a->argc;
     f = argv_prep_format(format, delim, &argc, &gc);
     if (f == NULL)
@@ -262,7 +265,6 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     {
         /* Someone snuck in a \035, fail gracefully */
         argv_reset(a);
-        argv_extend(a, 1); /* ensure trailing NULL */
         goto out;
     }
 
@@ -304,7 +306,6 @@ argv_parse_cmd(struct argv *a, const char *s)
     struct gc_arena gc = gc_new();
 
     argv_reset(a);
-    argv_extend(a, 1); /* ensure trailing NULL */
 
     nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
     if (nparms)
src/openvpn/argv.h +1 -1
index a24ba98f..2a1945e3 100644
@@ -40,7 +40,7 @@ struct argv {
 
 struct argv argv_new(void);
 
-void argv_reset(struct argv *a);
+void argv_free(struct argv *a);
 
 const char *argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags);
 
src/openvpn/console_systemd.c +1 -1
index e7a72ae3..5b09dee4 100644
@@ -84,7 +84,7 @@ get_console_input_systemd(const char *prompt, const bool echo, char *input, cons
     }
     close(std_out);
 
-    argv_reset(&argv);
+    argv_free(&argv);
 
     return ret;
 }
src/openvpn/init.c +3 -12
index 1ed2c55e..25962958 100644
@@ -162,7 +162,7 @@ run_up_down(const char *command,
             msg(M_FATAL, "ERROR: up/down plugin call failed");
         }
 
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     if (command)
@@ -175,7 +175,7 @@ run_up_down(const char *command,
                         ifconfig_local, ifconfig_remote, context);
         argv_msg(M_INFO, &argv);
         openvpn_run_script(&argv, es, S_FATAL, "--up/--down");
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     gc_free(&gc);
@@ -824,15 +824,6 @@ init_static(void)
     return false;
 #endif
 
-#ifdef ARGV_TEST
-    {
-        void argv_test(void);
-
-        argv_test();
-        return false;
-    }
-#endif
-
 #ifdef PRNG_TEST
     {
         struct gc_arena gc = gc_new();
@@ -1627,7 +1618,7 @@ do_route(const struct options *options,
         setenv_str(es, "script_type", "route-up");
         argv_parse_cmd(&argv, options->route_script);
         openvpn_run_script(&argv, es, 0, "--route-up");
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
 #ifdef _WIN32
src/openvpn/lladdr.c +1 -1
index ff71e48c..4df4151a 100644
@@ -67,6 +67,6 @@ set_lladdr(const char *ifname, const char *lladdr,
         msg(M_INFO, "TUN/TAP link layer address set to %s", lladdr);
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
     return r;
 }
src/openvpn/multi.c +5 -5
index 4545bce1..df0531e0 100644
@@ -136,7 +136,7 @@ learn_address_script(const struct multi_context *m,
             msg(M_WARN, "WARNING: learn-address plugin call failed");
             ret = false;
         }
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     if (m->top.options.learn_address_script)
@@ -153,7 +153,7 @@ learn_address_script(const struct multi_context *m,
         {
             ret = false;
         }
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     gc_free(&gc);
@@ -594,7 +594,7 @@ multi_client_disconnect_script(struct multi_context *m,
             setenv_str(mi->context.c2.es, "script_type", "client-disconnect");
             argv_parse_cmd(&argv, mi->context.options.client_disconnect_script);
             openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-disconnect");
-            argv_reset(&argv);
+            argv_free(&argv);
         }
 #ifdef MANAGEMENT_DEF_AUTH
         if (management)
@@ -1908,7 +1908,7 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi)
             }
 
 script_depr_failed:
-            argv_reset(&argv);
+            argv_free(&argv);
         }
 
         /* V2 callback, use a plugin_return struct for passing back return info */
@@ -1970,7 +1970,7 @@ script_depr_failed:
             }
 
 script_failed:
-            argv_reset(&argv);
+            argv_free(&argv);
         }
 
         /*
src/openvpn/options.c +1 -1
index 7aa311aa..edab9066 100644
@@ -3245,7 +3245,7 @@ check_cmd_access(const char *command, const char *opt, const char *chroot)
         return_code = true;
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
 
     return return_code;
 }
src/openvpn/plugin.c +1 -1
index 557b6bc7..65b113af 100644
@@ -591,7 +591,7 @@ plugin_call_item(const struct plugin *p,
                 p->so_pathname);
         }
 
-        argv_reset(&a);
+        argv_free(&a);
         gc_free(&gc);
     }
     return status;
src/openvpn/route.c +4 -4
index 02f7299f..0e4237d6 100644
@@ -1815,7 +1815,7 @@ done:
     {
         r->flags &= ~RT_ADDED;
     }
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -2122,7 +2122,7 @@ add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flag
     {
         r6->flags &= ~RT_ADDED;
     }
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -2314,7 +2314,7 @@ delete_route(struct route_ipv4 *r,
 
 done:
     r->flags &= ~RT_ADDED;
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -2548,7 +2548,7 @@ delete_route_ipv6(const struct route_ipv6 *r6, const struct tuntap *tt, unsigned
     msg(M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-down script");
 #endif /* if defined(TARGET_LINUX) */
 
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
src/openvpn/socket.c +2 -2
index 0fc91f21..2f373116 100644
@@ -2334,7 +2334,7 @@ link_socket_connection_initiated(const struct buffer *buf,
         {
             msg(M_WARN, "WARNING: ipchange plugin call failed");
         }
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     /* Process --ipchange option */
@@ -2344,7 +2344,7 @@ link_socket_connection_initiated(const struct buffer *buf,
         setenv_str(es, "script_type", "ipchange");
         ipchange_fmt(true, &argv, info, &gc);
         openvpn_run_script(&argv, es, 0, "--ipchange");
-        argv_reset(&argv);
+        argv_free(&argv);
     }
 
     gc_free(&gc);
src/openvpn/ssl_verify.c +3 -3
index 9cd36d7a..65342860 100644
@@ -524,7 +524,7 @@ verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es,
 
         ret = plugin_call_ssl(plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert);
 
-        argv_reset(&argv);
+        argv_free(&argv);
 
         if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
         {
@@ -610,7 +610,7 @@ verify_cert_call_command(const char *verify_command, struct env_set *es,
     }
 
     gc_free(&gc);
-    argv_reset(&argv);
+    argv_free(&argv);
 
     if (ret)
     {
@@ -1153,7 +1153,7 @@ done:
         platform_unlink(tmp_file);
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
     return ret;
 }
src/openvpn/tun.c +17 -15
index 61d6b9eb..d0e56bf1 100644
@@ -1584,7 +1584,7 @@ do_ifconfig(struct tuntap *tt,
 #else  /* if defined(TARGET_LINUX) */
         msg(M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system.  You should ifconfig your TUN/TAP device manually or use an --up script.");
 #endif /* if defined(TARGET_LINUX) */
-        argv_reset(&argv);
+        argv_free(&argv);
     }
     gc_free(&gc);
 }
@@ -2166,7 +2166,7 @@ close_tun(struct tuntap *tt)
 #endif
             }
 
-            argv_reset(&argv);
+            argv_free(&argv);
             gc_free(&gc);
         }
         close_tun_generic(tt);
@@ -2439,7 +2439,7 @@ solaris_close_tun(struct tuntap *tt)
                          IFCONFIG_PATH, tt->actual_name );
             argv_msg(M_INFO, &argv);
             openvpn_execve_check(&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
-            argv_reset(&argv);
+            argv_free(&argv);
         }
 
         if (tt->ip_fd >= 0)
@@ -2526,7 +2526,7 @@ solaris_error_close(struct tuntap *tt, const struct env_set *es,
     openvpn_execve_check(&argv, es, 0, "Solaris ifconfig unplumb failed");
     close_tun(tt);
     msg(M_FATAL, "Solaris ifconfig failed");
-    argv_reset(&argv);
+    argv_free(&argv);
 }
 
 int
@@ -2598,7 +2598,6 @@ close_tun(struct tuntap *tt)
     }
     else if (tt)
     {
-        struct gc_arena gc = gc_new();
         struct argv argv = argv_new();
 
         /* setup command, close tun dev (clears tt->actual_name!), run command
@@ -2612,6 +2611,7 @@ close_tun(struct tuntap *tt)
         argv_msg(M_INFO, &argv);
         openvpn_execve_check(&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
 
+        argv_free(&argv);
         free(tt);
     }
 }
@@ -2683,7 +2683,6 @@ close_tun(struct tuntap *tt)
     }
     else if (tt)
     {
-        struct gc_arena gc = gc_new();
         struct argv argv = argv_new();
 
         /* setup command, close tun dev (clears tt->actual_name!), run command
@@ -2697,6 +2696,7 @@ close_tun(struct tuntap *tt)
         argv_msg(M_INFO, &argv);
         openvpn_execve_check(&argv, NULL, 0, "NetBSD 'destroy tun interface' failed (non-critical)");
 
+        argv_free(&argv);
         free(tt);
     }
 }
@@ -2834,6 +2834,7 @@ close_tun(struct tuntap *tt)
         argv_msg(M_INFO, &argv);
         openvpn_execve_check(&argv, NULL, 0, "FreeBSD 'destroy tun interface' failed (non-critical)");
 
+        argv_free(&argv);
         free(tt);
     }
 }
@@ -3201,7 +3202,7 @@ close_tun(struct tuntap *tt)
 
         close_tun_generic(tt);
         free(tt);
-        argv_reset(&argv);
+        argv_free(&argv);
         gc_free(&gc);
     }
 }
@@ -3306,6 +3307,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
         env_set_add( es, "ODMDIR=/etc/objrepos" );
         openvpn_execve_check(&argv, es, S_FATAL, "AIX 'create tun interface' failed");
         env_set_destroy(es);
+        argv_free(&argv);
     }
     else
     {
@@ -3331,7 +3333,6 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
 void
 close_tun(struct tuntap *tt)
 {
-    struct gc_arena gc = gc_new();
     struct argv argv = argv_new();
     struct env_set *es = env_set_create(NULL);
 
@@ -3360,6 +3361,7 @@ close_tun(struct tuntap *tt)
 
     free(tt);
     env_set_destroy(es);
+    argv_free(&argv);
 }
 
 int
@@ -5028,14 +5030,14 @@ ipconfig_register_dns(const struct env_set *es)
                 WIN_IPCONFIG_PATH_SUFFIX);
     argv_msg(D_TUNTAP_INFO, &argv);
     status = openvpn_execve_check(&argv, es, 0, err);
-    argv_reset(&argv);
+    argv_free(&argv);
 
     argv_printf(&argv, "%s%s /registerdns",
                 get_win_sys_path(),
                 WIN_IPCONFIG_PATH_SUFFIX);
     argv_msg(D_TUNTAP_INFO, &argv);
     status = openvpn_execve_check(&argv, es, 0, err);
-    argv_reset(&argv);
+    argv_free(&argv);
 
     netcmd_semaphore_release();
     msg(D_TUNTAP_INFO, "End ipconfig commands for register-dns...");
@@ -5160,7 +5162,7 @@ netsh_set_dns6_servers(const struct in6_addr *addr_list,
         netsh_command(&argv, 1, (i==0) ? M_FATAL : M_NONFATAL);
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -5232,7 +5234,7 @@ netsh_ifconfig_options(const char *type,
         }
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -5323,7 +5325,7 @@ netsh_ifconfig(const struct tuntap_options *to,
                                BOOL_CAST(flags & NI_TEST_FIRST));
     }
 
-    argv_reset(&argv);
+    argv_free(&argv);
     gc_free(&gc);
 }
 
@@ -5342,7 +5344,7 @@ netsh_enable_dhcp(const struct tuntap_options *to,
 
     netsh_command(&argv, 4, M_FATAL);
 
-    argv_reset(&argv);
+    argv_free(&argv);
 }
 
 /*
@@ -6215,7 +6217,7 @@ close_tun(struct tuntap *tt)
                                 tt->actual_name);
                     netsh_command(&argv, 1, M_WARN);
                 }
-                argv_reset(&argv);
+                argv_free(&argv);
             }
         }
 #if 1
tests/unit_tests/openvpn/test_argv.c +28 -13

115 lines not on this page · raw message

Signature · 1 line
2.11.0
#28 lore raw

Re: [Openvpn-devel] [PATCHv2 6/7] argv: do fewer memory re-allocations

Quoted 30 lines · Heiko Hund

Prevent the re-allocations of memory when the internal argv grows beyond 2 and 4 arguments by initially allocating argv to hold up to 7 (+ trailing NULL) pointers.

While at it rename argv_reset to argv_free to actually express what's going on. Redo the argv_reset functionality so that it can be used to actually reset the argv without re-allocation.

---
 src/openvpn/argv.c                   | 53 ++++++++++++++++++------------------
 src/openvpn/argv.h                   |  2 +-
 src/openvpn/console_systemd.c        |  2 +-
 src/openvpn/init.c                   | 15 ++--------
 src/openvpn/lladdr.c                 |  2 +-
 src/openvpn/multi.c                  | 10 +++----
 src/openvpn/options.c                |  2 +-
 src/openvpn/plugin.c                 |  2 +-
 src/openvpn/route.c                  |  8 +++---
 src/openvpn/socket.c                 |  4 +--
 src/openvpn/ssl_verify.c             |  6 ++--
 src/openvpn/tun.c                    | 32 ++++++++++++----------
 tests/unit_tests/openvpn/test_argv.c | 41 +++++++++++++++++++---------
 13 files changed, 94 insertions(+), 85 deletions(-)
src/openvpn/argv.c +0 -0
index afe8efff..419b1dc6 100644

src/openvpn/argv.c line 49

Quoted 10 lines
src/openvpn/argv.c +7 -0
@@ -40,11 +40,30 @@
 #include "options.h"
 
 static void
+argv_extend(struct argv *a, const size_t newcap)
+{
+    if (newcap > a->capacity)
+    {
+        char **newargv;
+        size_t i;
+        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);

Did we agree on using the intern gc_arena for this array? Or not? I remember we talked about ALLOC_ARRAY_CLEAR_GC() instead.

[...snip...]

Quoted 5 lines
src/openvpn/argv.c +0 -0
 static void
@@ -133,14 +145,7 @@ argv_insert_head(const struct argv *a, const char *head)
 const char *
 argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
 {

src/openvpn/argv.c argv_insert_head(const struct argv *a, const char *head) · line 149

Quoted 10 lines
src/openvpn/argv.c +1 -8
-    if (a->argv)
-    {
-        return print_argv((const char **)a->argv, gc, flags);
-    }
-    else
-    {
-        return "";
-    }
+    return print_argv((const char **)a->argv, gc, flags);
 }

Hmmm .... do we _really_ need argv_str()?

 $ git grep argv_str
src/openvpn/argv.c:argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
src/openvpn/argv.c:    msg(msglev, "%s", argv_str(a, &gc, 0));
src/openvpn/argv.c:    msg(msglev, "%s: %s", prefix, argv_str(a, &gc, 0));
src/openvpn/argv.h:const char *argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags);

(ignoring unit tests).

Or if we want it for convenience for those two callers in argv.c, remove it from the header and make it static inline. But I'm still not really convinced we really need it; as the usage is limited to within the argv.c code base.

Otherwise, this looks good. Once we have figured out these two comments, this is fairly straight-forward to include.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN, Inc
author
#29 lore raw

PATCH 7/7 Add gc_arena to struct argv to save allocations

In reply to Heiko Hund

With the private gc_arena we do not have to allocate the strings found during parsing again, since we know the arena they are allocated in is valid as long as the argv vector is.

---
 src/openvpn/argv.c                   | 37 ++++++++++++++++++------------------
 src/openvpn/argv.h                   |  1 +
 tests/unit_tests/openvpn/test_argv.c | 21 ++++++++++++++++++++
 3 files changed, 40 insertions(+), 19 deletions(-)
src/openvpn/argv.c +18 -19
index 664785b..9f139bb 100644
@@ -62,6 +62,7 @@ argv_init (struct argv *a)
   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;
+  a->gc = gc_new ();
   argv_extend (a, 8);
 }
 
@@ -76,22 +77,23 @@ argv_new (void)
 void
 argv_free (struct argv *a)
 {
-  size_t i;
-  for (i = 0; i < a->argc; ++i)
-    free (a->argv[i]);
+  gc_free (&a->gc);
   free (a->argv);
 }
 
 static void
 argv_reset (struct argv *a)
 {
-  size_t i;
-  for (i = 0; i < a->argc; ++i)
+  if (a->argc)
     {
-      free (a->argv[i]);
-      a->argv[i] = NULL;
+      size_t i;
+      for (i = 0; i < a->argc; ++i)
+        a->argv[i] = NULL;
+      a->argc = 0;
+
+      gc_free (&a->gc);
+      a->gc = gc_new ();
     }
-  a->argc = 0;
 }
 
 static void
@@ -103,7 +105,7 @@ argv_grow (struct argv *a, const size_t add)
 }
 
 static void
-argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
+argv_append (struct argv *a, char *str) /* str must have been gc_malloced or be NULL */
 {
   argv_grow (a, 1);
   a->argv[a->argc++] = str;
@@ -121,7 +123,7 @@ argv_clone (const struct argv *a, const size_t headroom)
   if (a)
     {
       for (i = 0; i < a->argc; ++i)
-        argv_append (&r, string_alloc (a->argv[i], NULL));
+        argv_append (&r, string_alloc (a->argv[i], &r.gc));
     }
   return r;
 }
@@ -131,7 +133,7 @@ argv_insert_head (const struct argv *a, const char *head)
 {
   struct argv r;
   r = argv_clone (a, 1);
-  r.argv[0] = string_alloc (head, NULL);
+  r.argv[0] = string_alloc (head, &r.gc);
   return r;
 }
 
@@ -212,7 +214,7 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
     goto out;
 
   size = adjust_power_of_2 (len + 1);
-  buf = gc_malloc (size, false, &gc);
+  buf = gc_malloc (size, false, &a->gc);
   len = vsnprintf (buf, size, f, arglist);
   if (len < 0 || len >= size)
     goto out;
@@ -220,7 +222,7 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
   token = strtok (buf, delim);
   while (token)
     {
-      argv_append (a, string_alloc (token, NULL));
+      argv_append (a, token);
       token = strtok (NULL, delim);
     }
 
@@ -266,19 +268,16 @@ argv_parse_cmd (struct argv *a, const char *s)
 {
   int nparms;
   char *parms[MAX_PARMS + 1];
-  struct gc_arena gc = gc_new ();
 
   argv_reset (a);
 
-  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &a->gc);
   if (nparms)
     {
       int i;
       for (i = 0; i < nparms; ++i)
-        argv_append (a, string_alloc (parms[i], NULL));
+        argv_append (a, parms[i]);
     }
   else
-    argv_append (a, string_alloc (s, NULL));
-
-  gc_free (&gc);
+    argv_append (a, string_alloc (s, &a->gc));
 }
src/openvpn/argv.h +1 -0
index 99fd7ad..7169f1d 100644
@@ -34,6 +34,7 @@
 #include "buffer.h"
 
 struct argv {
+  struct gc_arena gc;
   size_t capacity;
   size_t argc;
   char **argv;
tests/unit_tests/openvpn/test_argv.c +21 -0
index d2cd96d..3de1897 100644
@@ -123,6 +123,27 @@ argv_printf__combined_path_with_spaces__argc_correct (void **state)
 }
 
 static void
+argv_printf__long_args__data_correct (void **state)
+{
+  int i;
+  struct argv a = argv_new ();
+  const char *args[] = {
+    "good_tools_have_good_names_even_though_it_might_impair_typing",
+    "--long-opt=looooooooooooooooooooooooooooooooooooooooooooooooong",
+    "--long-cat=loooooooooooooooooooooooooooooooooooooooooooooooooooonger",
+    "file_with_very_descriptive_filename_that_leaves_no_questions_open.jpg.exe"
+  };
+
+  argv_printf (&a, "%s %s %s %s", args[0], args[1], args[2], args[3]);
+  assert_int_equal (a.argc, 4);
+  for (i = 0; i < a.argc; i++) {
+    assert_string_equal (a.argv[i], args[i]);
+  }
+
+  argv_free (&a);
+}
+
+static void
 argv_parse_cmd__command_string__argc_correct (void **state)
 {
   struct argv a = argv_new ();
Signature · 1 line
2.7.4
#30 lore raw

Re: [Openvpn-devel] [PATCH 7/7] Add gc_arena to struct argv to save allocations

Quoted 16 lines · Heiko Hund

With the private gc_arena we do not have to allocate the strings found during parsing again, since we know the arena they are allocated in is valid as long as the argv vector is.

---
 src/openvpn/argv.c                   | 37 ++++++++++++++++++------------------
 src/openvpn/argv.h                   |  1 +
 tests/unit_tests/openvpn/test_argv.c | 21 ++++++++++++++++++++
 3 files changed, 40 insertions(+), 19 deletions(-)
src/openvpn/argv.c +0 -0
index 664785b..9f139bb 100644

src/openvpn/argv.c argv_init (struct argv *a) · line 67

Quoted 6 lines
src/openvpn/argv.c +1 -0
@@ -62,6 +62,7 @@ argv_init (struct argv *a)
   a->capacity = 0;
   a->argc = 0;
   a->argv = NULL;
+  a->gc = gc_new ();
   argv_extend (a, 8);
 }

Any specific reason we want to keep our own gc_arena on argv? Why not pass an existing gc_arena pointer to the argv_new()/argv_init() functions? I believe the majority of places argv functions are called already have a gc_arena prepared. But I do see it may complicate the argv_reset() function.

src/openvpn/argv.c argv_init (struct argv *a)

Quoted 4 lines
src/openvpn/argv.c +4 -0
+  const char *args[] = {
+    "good_tools_have_good_names_even_though_it_might_impair_typing",
+    "--long-opt=looooooooooooooooooooooooooooooooooooooooooooooooong",
+    "--long-cat=loooooooooooooooooooooooooooooooooooooooooooooooooooonger",

Great examples! :)

Quoted 1 line

+ "file_with_very_descriptive_filename_that_leaves_no_questions_open.jpg.exe"

And this made me laugh! Leaves absolutely no open questions ;)

When looking over the final argv.c file, I also wonder about this:

const char *
argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
{
return print_argv ((const char **)a->argv, gc, flags);
}

Why not use our own internal gc_arena? Especially when considering the current callers:

void
argv_msg (const int msglev, const struct argv *a)
{
struct gc_arena gc = gc_new ();
msg (msglev, "%s", argv_str (a, &gc, 0));
gc_free (&gc);
}

The situation is identical for argv_msg_prefix().

AFAICS, struct argv objects doesn't live very long, so it would be minimal impact on the overall memory usage. At least when we have our own internal gc_arena. Using a more global gc_arena (provided via argv_new()/argv_init()) makes the object live somewhat longer. But even most of those places the gc_arenas doesn't live very much longer.

The overall impression I have is that this patch-set is truly valuable and does important clean-ups and fixes a lot of ambiguity and odd behaviours. And getting proper unit tests on top of it all is truly great! But there's still some improvements needed in the last 3 patches (patch 5, 6 and 7).

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
author
#31 lore raw

Re: [Openvpn-devel] [PATCH 7/7] Add gc_arena to struct argv to save allocations

Quoted 11 lines · CET David Sommerseth
Quoted 4 lines · Heiko Hund
+  a->gc = gc_new ();
   argv_extend (a, 8);

}

Any specific reason we want to keep our own gc_arena on argv? Why not pass an existing gc_arena pointer to the argv_new()/argv_init() functions? I believe the majority of places argv functions are called already have a gc_arena prepared. But I do see it may complicate the argv_reset() function.

The idea was that struct argv is usually very short lived. Some callers do not have a gc and would need to create one just for using struct argv, others have one and it is rather long lived, so it would hang on to the memory much longer than needed.

Quoted 20 lines

When looking over the final argv.c file, I also wonder about this:

const char *
argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
{
return print_argv ((const char **)a->argv, gc, flags);
}

Why not use our own internal gc_arena? Especially when considering the current callers:

void
argv_msg (const int msglev, const struct argv *a)
{
struct gc_arena gc = gc_new ();
msg (msglev, "%s", argv_str (a, &gc, 0));
gc_free (&gc);
}

Quoted 1 line

The situation is identical for argv_msg_prefix().

The difference between argv_str and argv_msg is that the latter one doesn't pass the gc_alloced string to the calling scope. In that case the caller shoul take care of when the string is freed.

Quoted 5 lines

The overall impression I have is that this patch-set is truly valuable and does important clean-ups and fixes a lot of ambiguity and odd behaviours. And getting proper unit tests on top of it all is truly great! But there's still some improvements needed in the last 3 patches (patch 5, 6 and 7).

Thanks for taking the time to review this. Let's do another round for 5-7.

Cheers
Heiko

author
#32 lore raw

PATCH v2 7/7 Add gc_arena to struct argv to save allocations

In reply to Heiko Hund

With the private gc_arena we do not have to allocate the strings found during parsing again, since we know the arena they are allocated in is valid as long as the argv vector is.

---
 src/openvpn/argv.c                   | 44 ++++++++++++++++--------------------
 src/openvpn/argv.h                   |  1 +
 tests/unit_tests/openvpn/test_argv.c | 23 +++++++++++++++++++
 3 files changed, 43 insertions(+), 25 deletions(-)
src/openvpn/argv.c +19 -25
index 419b1dc6..51dd1b22 100644
@@ -46,12 +46,11 @@ argv_extend(struct argv *a, const size_t newcap)
     {
         char **newargv;
         size_t i;
-        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
+        ALLOC_ARRAY_CLEAR_GC(newargv, char *, newcap, &a->gc);
         for (i = 0; i < a->argc; ++i)
         {
             newargv[i] = a->argv[i];
         }
-        free(a->argv);
         a->argv = newargv;
         a->capacity = newcap;
     }
@@ -63,6 +62,7 @@ argv_init(struct argv *a)
     a->capacity = 0;
     a->argc = 0;
     a->argv = NULL;
+    a->gc = gc_new();
     argv_extend(a, 8);
 }
 
@@ -77,24 +77,21 @@ argv_new(void)
 void
 argv_free(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
-    {
-        free(a->argv[i]);
-    }
-    free(a->argv);
+    gc_free(&a->gc);
 }
 
 static void
 argv_reset(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
+    if (a->argc)
     {
-        free(a->argv[i]);
-        a->argv[i] = NULL;
+        size_t i;
+        for (i = 0; i < a->argc; ++i)
+        {
+            a->argv[i] = NULL;
+        }
+        a->argc = 0;
     }
-    a->argc = 0;
 }
 
 static void
@@ -106,7 +103,7 @@ argv_grow(struct argv *a, const size_t add)
 }
 
 static void
-argv_append(struct argv *a, char *str)  /* str must have been malloced or be NULL */
+argv_append(struct argv *a, char *str)  /* str must have been gc_malloced or be NULL */
 {
     argv_grow(a, 1);
     a->argv[a->argc++] = str;
@@ -127,7 +124,7 @@ argv_clone(const struct argv *a, const size_t headroom)
     {
         for (i = 0; i < a->argc; ++i)
         {
-            argv_append(&r, string_alloc(a->argv[i], NULL));
+            argv_append(&r, string_alloc(a->argv[i], &r.gc));
         }
     }
     return r;
@@ -138,7 +135,7 @@ argv_insert_head(const struct argv *a, const char *head)
 {
     struct argv r;
     r = argv_clone(a, 1);
-    r.argv[0] = string_alloc(head, NULL);
+    r.argv[0] = string_alloc(head, &r.gc);
     return r;
 }
 
@@ -243,7 +240,7 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     }
 
     size = adjust_power_of_2(len + 1);
-    buf = gc_malloc(size, false, &gc);
+    buf = gc_malloc(size, false, &a->gc);
     len = vsnprintf(buf, size, f, arglist);
     if (len < 0 || len >= size)
     {
@@ -255,11 +252,11 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     while (end)
     {
         *end = '\0';
-        argv_append(a, string_alloc(buf, NULL));
+        argv_append(a, buf);
         buf = end + 1;
         end = strchr(buf, delim);
     }
-    argv_append(a, string_alloc(buf, NULL));
+    argv_append(a, buf);
 
     if (a->argc != argc)
     {
@@ -303,23 +300,20 @@ argv_parse_cmd(struct argv *a, const char *s)
 {
     int nparms;
     char *parms[MAX_PARMS + 1];
-    struct gc_arena gc = gc_new();
 
     argv_reset(a);
 
-    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &a->gc);
     if (nparms)
     {
         int i;
         for (i = 0; i < nparms; ++i)
         {
-            argv_append(a, string_alloc(parms[i], NULL));
+            argv_append(a, parms[i]);
         }
     }
     else
     {
-        argv_append(a, string_alloc(s, NULL));
+        argv_append(a, string_alloc(s, &a->gc));
     }
-
-    gc_free(&gc);
 }
src/openvpn/argv.h +1 -0
index 2a1945e3..a1aa7ebb 100644
@@ -33,6 +33,7 @@
 #include "buffer.h"
 
 struct argv {
+    struct gc_arena gc;
     size_t capacity;
     size_t argc;
     char **argv;
tests/unit_tests/openvpn/test_argv.c +23 -0
index e15e2fe5..5bfef8af 100644
@@ -118,6 +118,28 @@ argv_printf__empty_parameter__argc_correct(void **state)
 }
 
 static void
+argv_printf__long_args__data_correct(void **state)
+{
+    int i;
+    struct argv a = argv_new();
+    const char *args[] = {
+        "good_tools_have_good_names_even_though_it_might_impair_typing",
+        "--long-opt=looooooooooooooooooooooooooooooooooooooooooooooooong",
+        "--long-cat=loooooooooooooooooooooooooooooooooooooooooooooooooooonger",
+        "file_with_very_descriptive_filename_that_leaves_no_questions_open.jpg.exe"
+    };
+
+    argv_printf(&a, "%s %s %s %s", args[0], args[1], args[2], args[3]);
+    assert_int_equal(a.argc, 4);
+    for (i = 0; i < a.argc; i++)
+    {
+        assert_string_equal(a.argv[i], args[i]);
+    }
+
+    argv_free(&a);
+}
+
+static void
 argv_parse_cmd__command_string__argc_correct(void **state)
 {
     struct argv a = argv_new();
@@ -233,6 +255,7 @@ main(void)
         cmocka_unit_test(argv_printf__group_sep_in_arg__fail_no_ouput),
         cmocka_unit_test(argv_printf__combined_path_with_spaces__argc_correct),
         cmocka_unit_test(argv_printf__empty_parameter__argc_correct),
+        cmocka_unit_test(argv_printf__long_args__data_correct),
         cmocka_unit_test(argv_parse_cmd__command_string__argc_correct),
         cmocka_unit_test(argv_parse_cmd__command_and_extra_options__argc_correct),
         cmocka_unit_test(argv_printf_cat__used_twice__argc_correct),
Signature · 1 line
2.11.0
author
#33 lore raw

PATCH v2 7/7 Add gc_arena to struct argv to save allocations

In reply to Heiko Hund

With the private gc_arena we do not have to allocate the strings found during parsing again, since we know the arena they are allocated in is valid as long as the argv vector is.

---
 src/openvpn/argv.c                   | 44 ++++++++++++++++--------------------
 src/openvpn/argv.h                   |  1 +
 tests/unit_tests/openvpn/test_argv.c | 23 +++++++++++++++++++
 3 files changed, 43 insertions(+), 25 deletions(-)
src/openvpn/argv.c +19 -25
index 419b1dc6..51dd1b22 100644
@@ -46,12 +46,11 @@ argv_extend(struct argv *a, const size_t newcap)
     {
         char **newargv;
         size_t i;
-        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
+        ALLOC_ARRAY_CLEAR_GC(newargv, char *, newcap, &a->gc);
         for (i = 0; i < a->argc; ++i)
         {
             newargv[i] = a->argv[i];
         }
-        free(a->argv);
         a->argv = newargv;
         a->capacity = newcap;
     }
@@ -63,6 +62,7 @@ argv_init(struct argv *a)
     a->capacity = 0;
     a->argc = 0;
     a->argv = NULL;
+    a->gc = gc_new();
     argv_extend(a, 8);
 }
 
@@ -77,24 +77,21 @@ argv_new(void)
 void
 argv_free(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
-    {
-        free(a->argv[i]);
-    }
-    free(a->argv);
+    gc_free(&a->gc);
 }
 
 static void
 argv_reset(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
+    if (a->argc)
     {
-        free(a->argv[i]);
-        a->argv[i] = NULL;
+        size_t i;
+        for (i = 0; i < a->argc; ++i)
+        {
+            a->argv[i] = NULL;
+        }
+        a->argc = 0;
     }
-    a->argc = 0;
 }
 
 static void
@@ -106,7 +103,7 @@ argv_grow(struct argv *a, const size_t add)
 }
 
 static void
-argv_append(struct argv *a, char *str)  /* str must have been malloced or be NULL */
+argv_append(struct argv *a, char *str)  /* str must have been gc_malloced or be NULL */
 {
     argv_grow(a, 1);
     a->argv[a->argc++] = str;
@@ -127,7 +124,7 @@ argv_clone(const struct argv *a, const size_t headroom)
     {
         for (i = 0; i < a->argc; ++i)
         {
-            argv_append(&r, string_alloc(a->argv[i], NULL));
+            argv_append(&r, string_alloc(a->argv[i], &r.gc));
         }
     }
     return r;
@@ -138,7 +135,7 @@ argv_insert_head(const struct argv *a, const char *head)
 {
     struct argv r;
     r = argv_clone(a, 1);
-    r.argv[0] = string_alloc(head, NULL);
+    r.argv[0] = string_alloc(head, &r.gc);
     return r;
 }
 
@@ -243,7 +240,7 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     }
 
     size = adjust_power_of_2(len + 1);
-    buf = gc_malloc(size, false, &gc);
+    buf = gc_malloc(size, false, &a->gc);
     len = vsnprintf(buf, size, f, arglist);
     if (len < 0 || len >= size)
     {
@@ -255,11 +252,11 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     while (end)
     {
         *end = '\0';
-        argv_append(a, string_alloc(buf, NULL));
+        argv_append(a, buf);
         buf = end + 1;
         end = strchr(buf, delim);
     }
-    argv_append(a, string_alloc(buf, NULL));
+    argv_append(a, buf);
 
     if (a->argc != argc)
     {
@@ -303,23 +300,20 @@ argv_parse_cmd(struct argv *a, const char *s)
 {
     int nparms;
     char *parms[MAX_PARMS + 1];
-    struct gc_arena gc = gc_new();
 
     argv_reset(a);
 
-    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &a->gc);
     if (nparms)
     {
         int i;
         for (i = 0; i < nparms; ++i)
         {
-            argv_append(a, string_alloc(parms[i], NULL));
+            argv_append(a, parms[i]);
         }
     }
     else
     {
-        argv_append(a, string_alloc(s, NULL));
+        argv_append(a, string_alloc(s, &a->gc));
     }
-
-    gc_free(&gc);
 }
src/openvpn/argv.h +1 -0
index 2a1945e3..a1aa7ebb 100644
@@ -33,6 +33,7 @@
 #include "buffer.h"
 
 struct argv {
+    struct gc_arena gc;
     size_t capacity;
     size_t argc;
     char **argv;
tests/unit_tests/openvpn/test_argv.c +23 -0
index e15e2fe5..5bfef8af 100644
@@ -118,6 +118,28 @@ argv_printf__empty_parameter__argc_correct(void **state)
 }
 
 static void
+argv_printf__long_args__data_correct(void **state)
+{
+    int i;
+    struct argv a = argv_new();
+    const char *args[] = {
+        "good_tools_have_good_names_even_though_it_might_impair_typing",
+        "--long-opt=looooooooooooooooooooooooooooooooooooooooooooooooong",
+        "--long-cat=loooooooooooooooooooooooooooooooooooooooooooooooooooonger",
+        "file_with_very_descriptive_filename_that_leaves_no_questions_open.jpg.exe"
+    };
+
+    argv_printf(&a, "%s %s %s %s", args[0], args[1], args[2], args[3]);
+    assert_int_equal(a.argc, 4);
+    for (i = 0; i < a.argc; i++)
+    {
+        assert_string_equal(a.argv[i], args[i]);
+    }
+
+    argv_free(&a);
+}
+
+static void
 argv_parse_cmd__command_string__argc_correct(void **state)
 {
     struct argv a = argv_new();
@@ -233,6 +255,7 @@ main(void)
         cmocka_unit_test(argv_printf__group_sep_in_arg__fail_no_ouput),
         cmocka_unit_test(argv_printf__combined_path_with_spaces__argc_correct),
         cmocka_unit_test(argv_printf__empty_parameter__argc_correct),
+        cmocka_unit_test(argv_printf__long_args__data_correct),
         cmocka_unit_test(argv_parse_cmd__command_string__argc_correct),
         cmocka_unit_test(argv_parse_cmd__command_and_extra_options__argc_correct),
         cmocka_unit_test(argv_printf_cat__used_twice__argc_correct),
Signature · 1 line
2.11.0
#34 lore raw

Re: [Openvpn-devel] [PATCHv2 7/7] Add gc_arena to struct argv to save allocations

Quoted 16 lines · Heiko Hund

With the private gc_arena we do not have to allocate the strings found during parsing again, since we know the arena they are allocated in is valid as long as the argv vector is.

---
 src/openvpn/argv.c                   | 44 ++++++++++++++++--------------------
 src/openvpn/argv.h                   |  1 +
 tests/unit_tests/openvpn/test_argv.c | 23 +++++++++++++++++++
 3 files changed, 43 insertions(+), 25 deletions(-)
src/openvpn/argv.c +0 -0
index 419b1dc6..51dd1b22 100644

src/openvpn/argv.c argv_extend(struct argv *a, const size_t newcap) · line 49

Quoted 5 lines
src/openvpn/argv.c +1 -1
@@ -46,12 +46,11 @@ argv_extend(struct argv *a, const size_t newcap)
     {
         char **newargv;
         size_t i;
-        ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
+        ALLOC_ARRAY_CLEAR_GC(newargv, char *, newcap, &a->gc);

Ahh! Here it is :) Disregard my comment about this in PATCH v2 6/7 :)

Quoted 173 lines
src/openvpn/argv.c +18 -24
         for (i = 0; i < a->argc; ++i)
         {
             newargv[i] = a->argv[i];
         }
-        free(a->argv);
         a->argv = newargv;
         a->capacity = newcap;
     }
@@ -63,6 +62,7 @@ argv_init(struct argv *a)
     a->capacity = 0;
     a->argc = 0;
     a->argv = NULL;
+    a->gc = gc_new();
     argv_extend(a, 8);
 }
 
@@ -77,24 +77,21 @@ argv_new(void)
 void
 argv_free(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
-    {
-        free(a->argv[i]);
-    }
-    free(a->argv);
+    gc_free(&a->gc);
 }
 
 static void
 argv_reset(struct argv *a)
 {
-    size_t i;
-    for (i = 0; i < a->argc; ++i)
+    if (a->argc)
     {
-        free(a->argv[i]);
-        a->argv[i] = NULL;
+        size_t i;
+        for (i = 0; i < a->argc; ++i)
+        {
+            a->argv[i] = NULL;
+        }
+        a->argc = 0;
     }
-    a->argc = 0;
 }
 
 static void
@@ -106,7 +103,7 @@ argv_grow(struct argv *a, const size_t add)
 }
 
 static void
-argv_append(struct argv *a, char *str)  /* str must have been malloced or be NULL */
+argv_append(struct argv *a, char *str)  /* str must have been gc_malloced or be NULL */
 {
     argv_grow(a, 1);
     a->argv[a->argc++] = str;
@@ -127,7 +124,7 @@ argv_clone(const struct argv *a, const size_t headroom)
     {
         for (i = 0; i < a->argc; ++i)
         {
-            argv_append(&r, string_alloc(a->argv[i], NULL));
+            argv_append(&r, string_alloc(a->argv[i], &r.gc));
         }
     }
     return r;
@@ -138,7 +135,7 @@ argv_insert_head(const struct argv *a, const char *head)
 {
     struct argv r;
     r = argv_clone(a, 1);
-    r.argv[0] = string_alloc(head, NULL);
+    r.argv[0] = string_alloc(head, &r.gc);
     return r;
 }
 
@@ -243,7 +240,7 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     }
 
     size = adjust_power_of_2(len + 1);
-    buf = gc_malloc(size, false, &gc);
+    buf = gc_malloc(size, false, &a->gc);
     len = vsnprintf(buf, size, f, arglist);
     if (len < 0 || len >= size)
     {
@@ -255,11 +252,11 @@ argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
     while (end)
     {
         *end = '\0';
-        argv_append(a, string_alloc(buf, NULL));
+        argv_append(a, buf);
         buf = end + 1;
         end = strchr(buf, delim);
     }
-    argv_append(a, string_alloc(buf, NULL));
+    argv_append(a, buf);
 
     if (a->argc != argc)
     {
@@ -303,23 +300,20 @@ argv_parse_cmd(struct argv *a, const char *s)
 {
     int nparms;
     char *parms[MAX_PARMS + 1];
-    struct gc_arena gc = gc_new();
 
     argv_reset(a);
 
-    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+    nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &a->gc);
     if (nparms)
     {
         int i;
         for (i = 0; i < nparms; ++i)
         {
-            argv_append(a, string_alloc(parms[i], NULL));
+            argv_append(a, parms[i]);
         }
     }
     else
     {
-        argv_append(a, string_alloc(s, NULL));
+        argv_append(a, string_alloc(s, &a->gc));
     }
-
-    gc_free(&gc);
 }
src/openvpn/argv.h +1 -0
index 2a1945e3..a1aa7ebb 100644
@@ -33,6 +33,7 @@
 #include "buffer.h"
 
 struct argv {
+    struct gc_arena gc;
     size_t capacity;
     size_t argc;
     char **argv;
tests/unit_tests/openvpn/test_argv.c +22 -0
index e15e2fe5..5bfef8af 100644
@@ -118,6 +118,28 @@ argv_printf__empty_parameter__argc_correct(void **state)
 }
 
 static void
+argv_printf__long_args__data_correct(void **state)
+{
+    int i;
+    struct argv a = argv_new();
+    const char *args[] = {
+        "good_tools_have_good_names_even_though_it_might_impair_typing",
+        "--long-opt=looooooooooooooooooooooooooooooooooooooooooooooooong",
+        "--long-cat=loooooooooooooooooooooooooooooooooooooooooooooooooooonger",
+        "file_with_very_descriptive_filename_that_leaves_no_questions_open.jpg.exe"
+    };
+
+    argv_printf(&a, "%s %s %s %s", args[0], args[1], args[2], args[3]);
+    assert_int_equal(a.argc, 4);
+    for (i = 0; i < a.argc; i++)
+    {
+        assert_string_equal(a.argv[i], args[i]);
+    }
+
+    argv_free(&a);
+}
+
+static void
 argv_parse_cmd__command_string__argc_correct(void **state)
 {
     struct argv a = argv_new();

tests/unit_tests/openvpn/test_argv.c main(void) · line 261

Quoted 7 lines
tests/unit_tests/openvpn/test_argv.c +1 -0
@@ -233,6 +255,7 @@ main(void)
         cmocka_unit_test(argv_printf__group_sep_in_arg__fail_no_ouput),
         cmocka_unit_test(argv_printf__combined_path_with_spaces__argc_correct),
         cmocka_unit_test(argv_printf__empty_parameter__argc_correct),
+        cmocka_unit_test(argv_printf__long_args__data_correct),
         cmocka_unit_test(argv_parse_cmd__command_string__argc_correct),
         cmocka_unit_test(argv_parse_cmd__command_and_extra_options__argc_correct),
         cmocka_unit_test(argv_printf_cat__used_twice__argc_correct),

Only glared at these changes. They make sense and the Acked-By is not far away at all! Just want to run some build tests with the other final patches in place first.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN, Inc