~emersion/mrsh-dev

ensure argv passed to getopt is NULL terminated v1 PROPOSED

Stone Tickle: 1
 ensure argv passed to getopt is NULL terminated

 4 files changed, 9 insertions(+), 2 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/mrsh-dev/patches/9718/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH] ensure argv passed to getopt is NULL terminated Export this patch

This has two fixes, 1: in push_frame allocates an extra array
element, and uses calloc instead of malloc to ensure that element is
NULL.  2: in argv_dup, enough memory is allocated but, the last element
is left uninitialized.  By using calloc instead, the last element is
guaranteed to be NULL.

I also added a test for this, although it does not always fail since it
relies on undefined behavior.
---
 builtin/set.c    | 2 +-
 shell/shell.c    | 2 +-
 test/args.sh     | 6 ++++++
 test/meson.build | 1 +
 4 files changed, 9 insertions(+), 2 deletions(-)
 create mode 100644 test/args.sh

diff --git a/builtin/set.c b/builtin/set.c
index b5a24f1..06a0427 100644
--- a/builtin/set.c
@@ -82,7 +82,7 @@ static const struct option_map *find_long_option(const char *opt) {
}

static char **argv_dup(char *argv_0, int argc, char *argv[]) {
	char **_argv = malloc((argc + 1) * sizeof(char *));
	char **_argv = calloc(argc + 1, sizeof(char *));
	_argv[0] = argv_0;
	for (int i = 1; i < argc; ++i) {
		_argv[i] = strdup(argv[i - 1]);
diff --git a/shell/shell.c b/shell/shell.c
index 192b478..61f561c 100644
--- a/shell/shell.c
+++ b/shell/shell.c
@@ -155,7 +155,7 @@ struct mrsh_call_frame_priv *call_frame_get_priv(struct mrsh_call_frame *frame)
void push_frame(struct mrsh_state *state, int argc, const char *argv[]) {
	struct mrsh_call_frame_priv *next = calloc(1, sizeof(*next));
	next->pub.argc = argc;
	next->pub.argv = malloc(sizeof(char *) * argc);
	next->pub.argv = calloc(argc + 1, sizeof(char *));
	for (int i = 0; i < argc; ++i) {
		next->pub.argv[i] = strdup(argv[i]);
	}
diff --git a/test/args.sh b/test/args.sh
new file mode 100644
index 0000000..a314dfd
--- /dev/null
+++ b/test/args.sh
@@ -0,0 +1,6 @@
func() { getopts "abcd" opt; }

func
func -a
func -ab
func -abc
diff --git a/test/meson.build b/test/meson.build
index b58720a..0bfde71 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -4,6 +4,7 @@ ref_sh = find_program(get_option('reference-shell'), required: false)
test_files = [
	'conformance/if.sh',

	'args.sh',
	'arithm.sh',
	'async.sh',
	'case.sh',
-- 
2.24.1
Pushed, thanks!