aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2015-03-01 12:33:20 -0500
committerSteve Vinoski <[email protected]>2015-03-15 19:11:40 -0400
commitf0cfce64b6a061ffeafeda254734f0b1f2f452fd (patch)
treeb6b3f0774ac8bb27d45819828c507bb2baf7521a /erts/emulator/test/nif_SUITE_data/nif_SUITE.c
parentfaeb9e9a67096af4257cd00409f06314f3223196 (diff)
downloadotp-f0cfce64b6a061ffeafeda254734f0b1f2f452fd.tar.gz
otp-f0cfce64b6a061ffeafeda254734f0b1f2f452fd.tar.bz2
otp-f0cfce64b6a061ffeafeda254734f0b1f2f452fd.zip
Ensure NIF term creation disallows illegal values
Add a check to enif_make_double to see if its double argument is infinity or NaN, returning a badarg exception if it is. Change the erl_nif documentation to specify that enif_make_double returns a badarg exception if its double argument is either infinity or NaN. Add tests to nif_SUITE for this change. Add checks to the enif_make* functions for atoms to prevent the creation of atoms whose name lengths are greater than the allowed maximum atom length. The enif_make_atom and enif_make_atom_len functions now return a badarg exception if the input string is too long. The enif_make_existing_atom and enif_make_existing_atom_len functions return false if the input string is too long. Change the erl_nif documentation to reflect the changes to these functions. Add tests to nif_SUITE for these changes. Add a field to ErlNifEnv to track that a NIF has raised an exception via enif_make_badarg. If a NIF calls enif_make_badarg but then ignores its return value and instead tries to return a non-exception term as its return value, the runtime still raises a badarg. This is needed to prevent enif_make_badarg values resulting from calls to enif_make_double, enif_make_atom, or enif_make_atom_len from being erroneously stored within other terms and returned from a NIF. Calling enif_make_badarg but not returning its return value has been documented as being illegal ever since enif_make_badarg was added, but the runtime has not enforced it until now. Add tests for regular and dirty NIFs to ensure that calls to enif_make_badarg result in badarg exceptions even if a NIF fails to return the result of enif_make_badarg as its return value. Add documentation to enif_make_badarg to specify that calling it raises a badarg even if a NIF ignores its return value.
Diffstat (limited to 'erts/emulator/test/nif_SUITE_data/nif_SUITE.c')
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c95
1 files changed, 89 insertions, 6 deletions
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 85544db2ab..d5109f1e58 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -380,7 +380,8 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ErlNifSInt64 sint64;
ErlNifUInt64 uint64;
double d;
- ERL_NIF_TERM atom, ref1, ref2;
+ ERL_NIF_TERM atom, ref1, ref2, term;
+ size_t len;
sint = INT_MIN;
do {
@@ -502,6 +503,7 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
goto error;
}
}
+
ref1 = enif_make_ref(env);
ref2 = enif_make_ref(env);
if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2)
@@ -1608,16 +1610,26 @@ static ERL_NIF_TERM send_from_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_
static ERL_NIF_TERM call_dirty_nif_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
switch (argc) {
- case 0: {
+ case 1: {
ERL_NIF_TERM args[255];
int i;
- for (i = 0; i < 255; i++)
+ args[0] = argv[0];
+ for (i = 1; i < 255; i++)
args[i] = enif_make_int(env, i);
return enif_schedule_nif(env, "call_dirty_nif_exception", ERL_NIF_DIRTY_JOB_CPU_BOUND,
call_dirty_nif_exception, 255, argv);
}
- case 1:
- return enif_make_badarg(env);
+ case 2: {
+ int return_badarg_directly;
+ enif_get_int(env, argv[0], &return_badarg_directly);
+ assert(return_badarg_directly == 1 || return_badarg_directly == 0);
+ if (return_badarg_directly)
+ return enif_make_badarg(env);
+ else {
+ /* ignore return value */ enif_make_badarg(env);
+ return enif_make_atom(env, "ok");
+ }
+ }
default:
return enif_schedule_nif(env, "call_dirty_nif_exception", ERL_NIF_DIRTY_JOB_CPU_BOUND,
call_dirty_nif_exception, argc-1, argv);
@@ -1637,6 +1649,74 @@ static ERL_NIF_TERM call_dirty_nif_zero_args(ErlNifEnv* env, int argc, const ERL
}
#endif
+/*
+ * Call enif_make_badarg, but don't return its return value. Instead,
+ * return ok. Result should still be a badarg exception for the erlang
+ * caller.
+ */
+static ERL_NIF_TERM call_nif_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ /* ignore return value */ enif_make_badarg(env);
+ return enif_make_atom(env, "ok");
+}
+
+static ERL_NIF_TERM call_nif_nan_or_inf(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ double val;
+ char arg[6];
+ ERL_NIF_TERM res;
+
+ assert(argc == 1);
+ enif_get_atom(env, argv[0], arg, sizeof arg, ERL_NIF_LATIN1);
+ if (strcmp(arg, "nan") == 0) {
+ /* Verify that enif_make_double raises a badarg for NaN */
+#ifdef NAN
+ val = NAN;
+#else
+ val = 0.0/0.0;
+#endif
+ } else {
+ /* Verify that enif_make_double raises a badarg for NaN and infinity */
+#ifdef INFINITY
+ val = INFINITY;
+#else
+ val = 1.0/0.0;
+#endif
+ }
+ res = enif_make_double(env, val);
+ assert(enif_is_exception(env, res));
+ if (strcmp(arg, "tuple") == 0) {
+ return enif_make_tuple2(env, argv[0], res);
+ } else {
+ return res;
+ }
+}
+
+static ERL_NIF_TERM call_nif_atom_too_long(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ char str[257];
+ char arg[4];
+ size_t len;
+ int i;
+ ERL_NIF_TERM res;
+
+ assert(argc == 1);
+ enif_get_atom(env, argv[0], arg, sizeof arg, ERL_NIF_LATIN1);
+ /* Verify that creating an atom from a string that's too long results in a badarg */
+ for (i = 0; i < sizeof str; ++i) {
+ str[i] = 'a';
+ }
+ str[256] = '\0';
+ if (strcmp(arg, "len") == 0) {
+ len = strlen(str);
+ res = enif_make_atom_len(env, str, len);
+ } else {
+ res = enif_make_atom(env, str);
+ }
+ assert(enif_is_exception(env, res));
+ return res;
+}
+
static ERL_NIF_TERM is_map_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_int(env, enif_is_map(env,argv[0]));
@@ -1818,9 +1898,12 @@ static ErlNifFunc nif_funcs[] =
#ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
{"call_dirty_nif", 3, call_dirty_nif},
{"send_from_dirty_nif", 1, send_from_dirty_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND},
- {"call_dirty_nif_exception", 0, call_dirty_nif_exception, ERL_NIF_DIRTY_JOB_IO_BOUND},
+ {"call_dirty_nif_exception", 1, call_dirty_nif_exception, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"call_dirty_nif_zero_args", 0, call_dirty_nif_zero_args, ERL_NIF_DIRTY_JOB_CPU_BOUND},
#endif
+ {"call_nif_exception", 0, call_nif_exception},
+ {"call_nif_nan_or_inf", 1, call_nif_nan_or_inf},
+ {"call_nif_atom_too_long", 1, call_nif_atom_too_long},
{"is_map_nif", 1, is_map_nif},
{"get_map_size_nif", 1, get_map_size_nif},
{"make_new_map_nif", 0, make_new_map_nif},