argcargv.i: NULL terminate argv with empty input

Fixes needed for: C# R
This commit is contained in:
Olly Betts 2023-05-23 09:41:20 +12:00
parent de4adea210
commit 8a73e25fe2
19 changed files with 103 additions and 4 deletions

View File

@ -15,7 +15,7 @@ int mainc(size_t argc, const char **argv)
const char* mainv(size_t argc, const char **argv, int idx)
{
return argv[idx];
return argv[idx] ? argv[idx] : "<<NULL>>";
}
void initializeApp(size_t argc, const char **argv, bool setPGid = true, bool isMakeline = false)

View File

@ -13,6 +13,8 @@ public class argcargvtest_runme {
throw new Exception("bad main typemap");
if (!argcargvtest.mainv(targs, 1).Equals("hola"))
throw new Exception("bad main typemap");
if (!argcargvtest.mainv(targs, 2).Equals("<<NULL>>"))
throw new Exception("bad main typemap");
// For dynamically typed languages we test this throws an exception or similar
// at runtime, but for C# this doesn't even compile (but we can't easily
@ -25,6 +27,8 @@ public class argcargvtest_runme {
string[] empty_args = {};
if (argcargvtest.mainc(empty_args) != 0)
throw new Exception("bad main typemap");
if (!argcargvtest.mainv(empty_args, 0).Equals("<<NULL>>"))
throw new Exception("bad main typemap");
// Check that empty strings are handled.
string[] empty_string = {"hello", "", "world"};
@ -36,5 +40,7 @@ public class argcargvtest_runme {
throw new Exception("bad main typemap");
if (argcargvtest.mainv(empty_string, 2) != "world")
throw new Exception("bad main typemap");
if (argcargvtest.mainv(empty_string, 3) != "<<NULL>>")
throw new Exception("bad main typemap");
}
}

View File

@ -10,6 +10,7 @@ void main() {
auto targs = ["hi", "hola"];
enforce(mainv(targs, 0) == "hi", "calling mainv failed");
enforce(mainv(targs, 1) == "hola", "calling mainv failed");
enforce(mainv(targs, 2) == "<<NULL>>", "calling mainv failed");
// For dynamically typed languages we test this throws an exception or similar
// at runtime, but for D language this doesn't even compile (but we can't easily
@ -21,6 +22,7 @@ void main() {
// Check that an empty array works.
string[] empty_args;
enforce(mainc(empty_args) == 0, "calling mainc failed");
enforce(mainv(empty_args, 0) == "<<NULL>>", "calling mainv failed");
// In D, an empty array created like empty_args is identical to null.
enforce(mainc(null) == 0, "calling mainc failed");
// However an empty array created like this has a non-null .array so test
@ -38,4 +40,5 @@ void main() {
enforce(mainv(empty_string, 0) == "hello", "calling mainv failed");
enforce(mainv(empty_string, 1) == "", "calling mainv failed");
enforce(mainv(empty_string, 2) == "world", "calling mainv failed");
enforce(mainv(empty_string, 3) == "<<NULL>>", "calling mainv failed");
}

View File

@ -15,6 +15,9 @@ func main() {
if rs := wrap.Mainv(targs, 1); rs != "hola" {
panic(rs)
}
if rs := wrap.Mainv(targs, 2); rs != "<<NULL>>" {
panic(rs)
}
// For dynamically typed languages we test this throws an exception or similar
// at runtime, but for Go this doesn't even compile (but we can't easily
@ -28,6 +31,9 @@ func main() {
if ri := wrap.Mainc(empty_args); ri != 0 {
panic(ri)
}
if rs := wrap.Mainv(empty_args, 0); rs != "<<NULL>>" {
panic(rs)
}
// Check that empty strings are handled.
empty_string := []string{"hello", "", "world"};
@ -43,4 +49,7 @@ func main() {
if rs := wrap.Mainv(empty_string, 2); rs != "world" {
panic(rs)
}
if rs := wrap.Mainv(empty_string, 3); rs != "<<NULL>>" {
panic(rs)
}
}

View File

@ -23,6 +23,8 @@ public class argcargvtest_runme {
throw new RuntimeException("bad main typemap");
if (!test.mainv(targs, 1).equals("hola"))
throw new RuntimeException("bad main typemap");
if (!test.mainv(targs, 2).equals("<<NULL>>"))
throw new RuntimeException("bad main typemap");
// For dynamically typed languages we test this throws an exception or similar
// at runtime, but for Java this doesn't even compile (but we can't easily
@ -35,6 +37,8 @@ public class argcargvtest_runme {
String[] empty_args = {};
if (test.mainc(empty_args) != 0)
throw new RuntimeException("bad main typemap");
if (!test.mainv(empty_args, 0).equals("<<NULL>>"))
throw new RuntimeException("bad main typemap");
// Check that empty strings are handled.
String[] empty_string = {"hello", "", "world"};
@ -46,5 +50,7 @@ public class argcargvtest_runme {
throw new RuntimeException("bad main typemap");
if (!test.mainv(empty_string, 2).equals("world"))
throw new RuntimeException("bad main typemap");
if (!test.mainv(empty_string, 3).equals("<<NULL>>"))
throw new RuntimeException("bad main typemap");
}
}

View File

@ -9,6 +9,8 @@ if (test.mainv(targs, 0) != "hi")
throw "calling mainv failed";
if (test.mainv(targs, 1) != "hola")
throw "calling mainv failed";
if (test.mainv(targs, 2) != "<<NULL>>")
throw "calling mainv failed";
caughtException = false;
try {
@ -26,6 +28,8 @@ test.initializeApp(largs);
const empty_args = [];
if (test.mainc(empty_args) != 0)
throw "bad main typemap";
if (test.mainv(empty_args, 0) != "<<NULL>>")
throw "calling mainv failed";
// Check that empty strings are handled.
const empty_string = ["hello", "", "world"];
@ -37,3 +41,5 @@ if (test.mainv(empty_string, 1) != "")
throw "bad main typemap";
if (test.mainv(empty_string, 2) != "world")
throw "bad main typemap";
if (test.mainv(empty_string, 3) != "<<NULL>>")
throw "bad main typemap";

View File

@ -13,6 +13,7 @@ assert(v.mainc(largs) == 3, "bad main typemap")
targs = {"hi", "hola"}
assert(v.mainv(targs, 0) == "hi", "bad main typemap")
assert(v.mainv(targs, 1) == "hola", "bad main typemap")
assert(v.mainv(targs, 2) == "<<NULL>>", "bad main typemap")
errorVal = 0
function try()
@ -26,6 +27,7 @@ v.initializeApp(largs)
-- Check that an empty array works.
empty_args = {}
assert(v.mainc(empty_args) == 0, "bad main typemap")
assert(v.mainv(empty_args, 0) == "<<NULL>>", "bad main typemap")
-- Check that empty strings are handled.
empty_string = {"hello", "", "world"}
@ -33,3 +35,4 @@ assert(v.mainc(empty_string) == 3, "bad main typemap")
assert(v.mainv(empty_string, 0) == "hello", "bad main typemap")
assert(v.mainv(empty_string, 1) == "", "bad main typemap")
assert(v.mainv(empty_string, 2) == "world", "bad main typemap")
assert(v.mainv(empty_string, 3) == "<<NULL>>", "bad main typemap")

View File

@ -9,6 +9,8 @@
(error "calling mainv failed"))
(when (not (string=? (mainv targs 1) "hola"))
(error "calling mainv failed"))
(when (not (string=? (mainv targs 2) "<<NULL>>"))
(error "calling mainv failed"))
(with-handlers ([exn:fail? (lambda (exn)
(when (not (string=? (exn-message exn)
@ -23,6 +25,8 @@
(define empty_args #())
(when (not (= (mainc empty_args) 0))
(error "calling mainc failed"))
(when (not (string=? (mainv empty_args 0) "<<NULL>>"))
(error "calling mainv failed"))
; Check that empty strings are handled.
(define empty_string #("hello" "" "world"))
@ -34,5 +38,7 @@
(error "calling mainv 1 failed"))
(when (not (string=? (mainv empty_string 2) "world"))
(error "calling mainv 2 failed"))
(when (not (string=? (mainv empty_string 3) "<<NULL>>"))
(error "calling mainv 3 failed"))
(exit 0)

View File

@ -17,6 +17,9 @@ endif
if (mainv(targs,1) != 'hola')
error("bad main typemap");
endif
if (mainv(targs,2) != '<<NULL>>')
error("bad main typemap");
endif
try
error_flag = 0;
@ -36,6 +39,9 @@ empty_args={};
if (mainc(empty_args) != 0)
error("bad main typemap");
endif
if (mainv(empty_args,0) != '<<NULL>>')
error("bad main typemap");
endif
# Check that empty strings are handled.
empty_string={"hello", blanks(0), "world"};
@ -52,3 +58,6 @@ endif
if (mainv(empty_string, 2) != "world")
error("bad main typemap");
endif
if (mainv(empty_string, 3) != "<<NULL>>")
error("bad main typemap");
endif

View File

@ -1,6 +1,6 @@
use strict;
use warnings;
use Test::More tests => 14;
use Test::More tests => 17;
BEGIN { use_ok('argcargvtest') }
require_ok('argcargvtest');
@ -10,6 +10,7 @@ is(argcargvtest::mainc($largs), 3, "test main typemap 1");
my $targs = ["hi", "hola"];
is(argcargvtest::mainv($targs, 0), "hi", "test main typemap 2a");
is(argcargvtest::mainv($targs, 1), "hola", "test main typemap 2b");
is(argcargvtest::mainv($targs, 2), "<<NULL>>", "test main typemap 2c");
my $errorVal = 0;
my $ret = eval qq(argcargvtest::mainv("hello", 1); \$errorVal = 1;);
@ -21,6 +22,7 @@ is(argcargvtest::initializeApp($largs), undef, "test main typemap 5");
# Check that an empty array works.
my @empty_args = ();
is(argcargvtest::mainc(\@empty_args), 0, "test main typemap 6");
is(argcargvtest::mainv(\@empty_args, 0), "<<NULL>>", "test main typemap 6a");
# Check that empty strings are handled.
my @empty_string = ("hello", "", "world");
@ -28,5 +30,6 @@ is(argcargvtest::mainc(\@empty_string), 3, "test main typemap 7");
is(argcargvtest::mainv(\@empty_string, 0), "hello", "test main typemap 8a");
is(argcargvtest::mainv(\@empty_string, 1), "", "test main typemap 8b");
is(argcargvtest::mainv(\@empty_string, 2), "world", "test main typemap 8c");
is(argcargvtest::mainv(\@empty_string, 3), "<<NULL>>", "test main typemap 8d");
ok(1, "done");

View File

@ -15,6 +15,7 @@ check::equal(mainc($largs), 3, 'Test main typemap 1');
$targs = array('hi', 'hola');
check::equal(mainv($targs, 0), 'hi', 'Test main typemap 2a');
check::equal(mainv($targs, 1), 'hola', 'Test main typemap 2b');
check::equal(mainv($targs, 2), '<<NULL>>', 'Test main typemap 2c');
$error = 0;
try {
@ -30,6 +31,7 @@ initializeApp($largs);
# Check that an empty array works.
$empty_args = [];
check::equal(mainc($empty_args), 0, "test main typemap 4");
check::equal(mainv($empty_args, 0), '<<NULL>>', 'Test main typemap 4a');
# Check that empty strings are handled.
$empty_string = ["hello", "", "world"];
@ -37,5 +39,6 @@ check::equal(mainc($empty_string), 3, "test main typemap 5");
check::equal(mainv($empty_string, 0), "hello", "test main typemap 6a");
check::equal(mainv($empty_string, 1), "", "test main typemap 6b");
check::equal(mainv($empty_string, 2), "world", "test main typemap 6c");
check::equal(mainv($empty_string, 3), "<<NULL>>", "test main typemap 6d");
check::done();

View File

@ -13,6 +13,8 @@ if mainv(targs, 0) != "hi":
raise RuntimeError("bad main typemap")
if mainv(targs, 1) != "hola":
raise RuntimeError("bad main typemap")
if mainv(targs, 2) != "<<NULL>>":
raise RuntimeError("bad main typemap")
try:
error = 0
@ -30,9 +32,13 @@ initializeApp(largs)
empty_args = []
if mainc(empty_args) != 0:
raise RuntimeError("bad main typemap")
if mainv(empty_args, 0) != "<<NULL>>":
raise RuntimeError("bad main typemap")
empty_tuple = ()
if mainc(empty_tuple) != 0:
raise RuntimeError("bad main typemap")
if mainv(empty_tuple, 0) != "<<NULL>>":
raise RuntimeError("bad main typemap")
# Check that empty strings are handled.
empty_string = ["hello", "", "world"]
@ -44,3 +50,5 @@ if mainv(empty_string, 1) != "":
raise RuntimeError("bad main typemap")
if mainv(empty_string, 2) != "world":
raise RuntimeError("bad main typemap")
if mainv(empty_string, 3) != "<<NULL>>":
raise RuntimeError("bad main typemap")

View File

@ -10,6 +10,7 @@ unittest(3, mainc(largs))
targs = c("hi", "hola")
unittest("hi", mainv(targs, 0))
unittest("hola", mainv(targs, 1))
unittest("<<NULL>>", mainv(targs, 2))
# R convert the string to a string vector with a single string.
# So instead of exception we simply get null
@ -33,6 +34,7 @@ initializeApp(largs, TRUE)
# Check that an empty array works.
empty_args = c()
unittest(0, mainc(empty_args))
unittest("<<NULL>>", mainv(empty_args, 0))
# check dispatcher with empty array.
initializeApp(empty_args)
@ -44,3 +46,4 @@ unittest(3, mainc(empty_string))
unittest("hello", mainv(empty_string, 0))
unittest("", mainv(empty_string, 1))
unittest("world", mainv(empty_string, 2))
unittest("<<NULL>>", mainv(empty_string, 3))

View File

@ -18,6 +18,9 @@ end
if mainv($targs, 1) != "hola"
raise RuntimeError, "bad main typemap"
end
if mainv($targs, 2) != "<<NULL>>"
raise RuntimeError, "bad main typemap"
end
$error = 0
$ret = 0
@ -39,6 +42,9 @@ $empty_args = []
if mainc($empty_args) != 0
raise RuntimeError, "bad main typemap"
end
if mainv($empty_args, 0) != "<<NULL>>"
raise RuntimeError, "bad main typemap"
end
# Check that empty strings are handled.
$empty_string = ["hello", "", "world"]
@ -54,3 +60,6 @@ end
if mainv($empty_string, 2) != "world"
raise RuntimeError, "bad main typemap"
end
if mainv($empty_string, 3) != "<<NULL>>"
raise RuntimeError, "bad main typemap"
end

View File

@ -7,6 +7,8 @@
(error "calling mainv failed"))
(when (not (string=? (mainv targs 1) "hola"))
(error "calling mainv failed"))
(when (not (string=? (mainv targs 2) "<<NULL>>"))
(error "calling mainv failed"))
(expect-throw 'swig-contract-assertion-failed
(mainv "hello" 1))
@ -17,6 +19,8 @@
(define empty_args #())
(when (not (= (mainc empty_args) 0))
(error "calling mainc failed"))
(when (not (string=? (mainv empty_args 0) "<<NULL>>"))
(error "calling mainv failed"))
; Check that empty strings are handled.
(define empty_string #("hello" "" "world"))
@ -28,5 +32,7 @@
(error "calling mainv 1 failed"))
(when (not (string=? (mainv empty_string 2) "world"))
(error "calling mainv 2 failed"))
(when (not (string=? (mainv empty_string 3) "<<NULL>>"))
(error "calling mainv 3 failed"))
(exit 0)

View File

@ -6,6 +6,7 @@ checkequal(mainc(largs), 3, "calling mainc");
targs = ["hi" "hola"]
checkequal(mainv(targs, 0), "hi", "calling mainv");
checkequal(mainv(targs, 1), "hola", "calling mainv");
checkequal(mainv(targs, 2), "<<NULL>>", "calling mainv");
checkequal(mainv("hi", 0), "hi", "calling mainv with a single string");
@ -20,6 +21,7 @@ initializeApp(largs);
// Check that an empty array works.
empty_args = [];
checkequal(mainc(empty_args), 0, "calling mainc");
checkequal(mainv(empty_args, 0), "<<NULL>>", "calling mainv");
// Check that empty strings are handled.
empty_string = ["hello", "", "world"];
@ -27,5 +29,6 @@ checkequal(mainc(empty_string), 3, "calling mainc");
checkequal(mainv(empty_string, 0), "hello", "calling mainv");
checkequal(mainv(empty_string, 1), "", "calling mainv");
checkequal(mainv(empty_string, 2), "world", "calling mainv");
checkequal(mainv(empty_string, 3), "<<NULL>>", "calling mainv");
exec("swigtest.quit", -1);

View File

@ -17,6 +17,10 @@ if {[mainv $targs 1] != "hola"} {
puts stderr "bad main typemap"
exit 1
}
if {[mainv $targs 2] != "<<NULL>>"} {
puts stderr "bad main typemap"
exit 1
}
set targs " hi hola "
if {[mainv $targs 0] != "hi"} {
@ -41,6 +45,10 @@ if {[mainc $empty_args] != 0} {
puts stderr "bad main typemap"
exit 1
}
if {[mainv $empty_args 0] != "<<NULL>>"} {
puts stderr "bad main typemap"
exit 1
}
# Check that empty strings are handled.
set empty_string {"hello" "" "world"}
@ -60,3 +68,7 @@ if {[mainv $empty_string 2] != "world"} {
puts stderr "bad main typemap"
exit 1
}
if {[mainv $empty_string 3] != "<<NULL>>"} {
puts stderr "bad main typemap"
exit 1
}

View File

@ -32,8 +32,10 @@ SWIGEXPORT void* SWIGSTDCALL SWIG_csharp_string_array_to_c(int len, void *array)
size_t alen, slen;
char *p, **ptr;
SWIG_csharp_string_array *ret;
/* Special care is needed here to handle an empty array. */
alen = sizeof(SWIG_csharp_string_array) + sizeof(char *) * (len - (len > 0));
/* We don't need to add one to len for the terminating NULL here because
* SWIG_csharp_string_array includes one element already.
*/
alen = sizeof(SWIG_csharp_string_array) + sizeof(char *) * len;
ret = (SWIG_csharp_string_array *)malloc(alen);
if (ret == SWIG_NULLPTR) {
SWIG_CSharpSetPendingException(SWIG_CSharpOutOfMemoryException, "fail to duplicate array.");
@ -52,6 +54,7 @@ SWIGEXPORT void* SWIGSTDCALL SWIG_csharp_string_array_to_c(int len, void *array)
memcpy(p, ptr[i], slen);
ret->array[i] = p;
}
ret->array[i] = SWIG_NULLPTR;
return ret;
}

View File

@ -17,6 +17,7 @@
/* Empty array */
$1 = 0;
$2 = ($2_ltype) malloc(sizeof($*2_ltype));
$2[0] = SWIG_NULLPTR;
} else if (!Rf_isVectorAtomic($input) || TYPEOF($input) != STRSXP) {
SWIG_exception_fail(SWIG_RuntimeError, "Wrong array type.");
} else {