struct argv overhaul
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
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
@@ -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
@@ -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
@@ -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
@@ -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
Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests
Quoted 6 lines · Heiko Hund
misc.cis 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.Signed-off-by Heiko Hund <[email protected]...>
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
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
Re: [Openvpn-devel] [PATCH 1/7] put argv_* functions into own file, add unit tests
In reply to Heiko HundHi,
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@@ -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
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
@@ -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
@@ -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
@@ -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
[Openvpn-devel] [PATCH applied] Re: put argv_* functions into own file, add unit tests
In reply to Heiko HundYour 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
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
@@ -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
@@ -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
@@ -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
[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
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
@@ -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 flaggc_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
@@ -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
@@ -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
@@ -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
Re: [Openvpn-devel] [PATCH 2/7] Remove unused and unecessary argv interfaces
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Quoted 8 lines · Heiko Hund
Signed-off-by Heiko Hund <[email protected]...> ---
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, 41insertions(+), 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-----
[Openvpn-devel] [PATCH applied] Re: Remove unused and unecessary argv interfaces
In reply to Heiko HundYour 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
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
@@ -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
@@ -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
Re: [Openvpn-devel] [PATCH 3/7] remove unused system_str from struct argv
Quoted 5 lines · Heiko Hund
Signed-off-by Heiko Hund <[email protected]...>--- 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
[Openvpn-devel] [PATCH applied] Re: remove unused system_str from struct argv
In reply to Heiko HundYour 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
PATCH 4/7 Factor out %sc handling from argv_printf()
In reply to Heiko HundMove 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
@@ -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
@@ -45,6 +45,7 @@ const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsignedstruct 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 *upsetenv_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
@@ -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
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 ofargv_printf().Signed-off-by Heiko Hund <[email protected]...>
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
[Openvpn-devel] [PATCH applied] Re: Factor out %sc handling from argv_printf()
In reply to Heiko HundYour 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
PATCH 5/7 re-implement argv_printf_*()
In reply to Heiko HundThe 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
Signed-off-by Heiko Hund <[email protected]...>--- 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
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 errorReverting this patch makes
t_cltsrv.shsucceed, 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
PATCH v2 5/7 re-implement argv_printf_*()
In reply to Heiko HundThe 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
@@ -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
@@ -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
@@ -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
@@ -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
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).
Signed-off-by Heiko Hund <[email protected]...>--- 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
[...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@@ -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@@ -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
[...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_resetThis 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
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]...PATCH 6/7 argv: do fewer memory re-allocations
In reply to Heiko HundPrevent 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, unsignemsg (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
@@ -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
@@ -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 *upif (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
@@ -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
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_resettoargv_freeto actually express what's going on. Redo theargv_resetfunctionality so that it can be used to actually reset the argv without re-allocation.Signed-off-by Heiko Hund <[email protected]...>
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
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 inbuffer.c). Should we migrateprint_argv()into this function and move all callers over toargv_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
-0tun.c:2360
close_tun()seems to be missing aargv_free(), or? The same goes forclose_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 noargv_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.chave a #ifdefARGV_TESTblock. That should probably also be killed; no need for that as we have unit tests - and theargv_test()function it calls no longer exists.
Aaand it's gone.
Cheers
Heiko
PATCH v2 6/7 argv: do fewer memory re-allocations
In reply to Heiko HundPrevent 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, unsignedmsg (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
@@ -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
@@ -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
@@ -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 tunenv_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 tunvoid 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
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_resettoargv_freeto actually express what's going on. Redo theargv_resetfunctionality so that it can be used to actually reset the argv without re-allocation.Signed-off-by Heiko Hund <[email protected]...>--- 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
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
-0static 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
PATCH 7/7 Add gc_arena to struct argv to save allocations
In reply to Heiko HundWith 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
@@ -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
@@ -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
@@ -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
Re: [Openvpn-devel] [PATCH 7/7] Add gc_arena to struct argv to save allocations
Quoted 16 lines · Heiko Hund
With the private
gc_arenawe 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.Signed-off-by Heiko Hund <[email protected]...>--- 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
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:
voidargv_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
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_arenaon argv? Why not pass an existinggc_arenapointer to the argv_new()/argv_init() functions? I believe the majority of places argv functions are called already have agc_arenaprepared. But I do see it may complicate theargv_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.cfile, I also wonder about this:const char *
argv_str(const struct argv *a, structgc_arena*gc, const unsigned int flags)
{
returnprint_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)
{
structgc_arenagc =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
PATCH v2 7/7 Add gc_arena to struct argv to save allocations
In reply to Heiko HundWith 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
@@ -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
@@ -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
@@ -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
PATCH v2 7/7 Add gc_arena to struct argv to save allocations
In reply to Heiko HundWith 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
@@ -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
@@ -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
@@ -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
Re: [Openvpn-devel] [PATCHv2 7/7] Add gc_arena to struct argv to save allocations
Quoted 16 lines · Heiko Hund
With the private
gc_arenawe 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.Signed-off-by Heiko Hund <[email protected]...>--- 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
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
-24for (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@@ -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@@ -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