diff options
Diffstat (limited to 'erts/emulator/test/send_term_SUITE_data/send_term_drv.c')
-rw-r--r-- | erts/emulator/test/send_term_SUITE_data/send_term_drv.c | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c new file mode 100644 index 0000000000..6638de0560 --- /dev/null +++ b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c @@ -0,0 +1,718 @@ +/* ``The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved via the world wide web at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson Utvecklings AB. + * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + * AB. All Rights Reserved.'' + * + * $Id$ + */ + +#include "erl_driver.h" +#include <errno.h> +#include <string.h> + +static ErlDrvPort erlang_port; +static ErlDrvData send_term_drv_start(ErlDrvPort port, char *command); +static void send_term_drv_stop(ErlDrvData drv_data); +static void send_term_drv_run(ErlDrvData drv_data, char *buf, int len); + + +static int make_ext_term_list(ErlDrvTermData *td, int bad); + +#define FAIL_TERM(M, L) fail_term((M), (L), __LINE__) + +static ErlDrvEntry send_term_drv_entry = { + NULL, + send_term_drv_start, + send_term_drv_stop, + send_term_drv_run, + NULL, + NULL, + "send_term_drv", +}; + +DRIVER_INIT(send_term_drv) +{ + erlang_port = (ErlDrvPort)-1; + return &send_term_drv_entry; +} + +static ErlDrvData send_term_drv_start(ErlDrvPort port, char *buf) +{ + if (erlang_port != (ErlDrvPort)-1) { + return ERL_DRV_ERROR_GENERAL; + } + + erlang_port = port; + return (ErlDrvData)port; +} + +static void send_term_drv_stop(ErlDrvData drv_data) +{ +} + +static void output_term(ErlDrvTermData* msg, int len); +static void fail_term(ErlDrvTermData* msg, int len, int line); + +static void send_term_drv_run(ErlDrvData port, char *buf, int count) +{ + ErlDrvTermData msg[1024]; + + switch (*buf) { + case 0: + msg[0] = ERL_DRV_NIL; + output_term(msg, 1); + break; + + case 1: /* Most term types inside a tuple. */ + { + double f = 3.1416; + + msg[0] = ERL_DRV_ATOM; + msg[1] = driver_mk_atom("blurf"), + msg[2] = ERL_DRV_INT; + msg[3] = (ErlDrvTermData) 42; + msg[4] = ERL_DRV_NIL; + msg[5] = ERL_DRV_INT; + msg[6] = (ErlDrvTermData) -42; + msg[7] = ERL_DRV_TUPLE; + msg[8] = (ErlDrvTermData) 0; + msg[9] = ERL_DRV_PORT; + msg[10] = driver_mk_port(erlang_port); + msg[11] = ERL_DRV_STRING_CONS; + msg[12] = (ErlDrvTermData) "abc"; + msg[13] = (ErlDrvTermData) 3; + msg[14] = ERL_DRV_LIST; + msg[15] = (ErlDrvTermData) 3; + msg[16] = ERL_DRV_STRING; + msg[17] = (ErlDrvTermData) "kalle"; + msg[18] = (ErlDrvTermData) 5; + msg[19] = ERL_DRV_FLOAT; + msg[20] = (ErlDrvTermData) &f; + msg[21] = ERL_DRV_PID; + msg[22] = driver_connected(erlang_port); + msg[23] = ERL_DRV_TUPLE; + msg[24] = (ErlDrvTermData) 7; + output_term(msg, 25); + } + break; + + case 2: /* Deep stack */ + { + int i; + + for (i = 0; i < 400; i += 2) { + msg[i] = ERL_DRV_INT; + msg[i+1] = (ErlDrvTermData) (i / 2); + } + msg[i] = ERL_DRV_NIL; + msg[i+1] = ERL_DRV_LIST; + msg[i+2] = (ErlDrvTermData) 201; + output_term(msg, i+3); + } + break; + + case 3: /* Binaries */ + { + ErlDrvBinary* bin; + int i; + + bin = driver_alloc_binary(256); + for (i = 0; i < 256; i++) { + bin->orig_bytes[i] = i; + } + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) bin; + msg[2] = (ErlDrvTermData) 256; + msg[3] = (ErlDrvTermData) 0; + msg[4] = ERL_DRV_BINARY; + msg[5] = (ErlDrvTermData) bin; + msg[6] = (ErlDrvTermData) 256-23-17; + msg[7] = (ErlDrvTermData) 23; + msg[8] = ERL_DRV_TUPLE; + msg[9] = (ErlDrvTermData) 2; + output_term(msg, 10); + driver_free_binary(bin); + } + break; + + case 4: /* Pids */ + msg[0] = ERL_DRV_PID; + msg[1] = driver_connected(erlang_port); + msg[2] = ERL_DRV_PID; + msg[3] = driver_caller(erlang_port); + msg[4] = ERL_DRV_TUPLE; + msg[5] = (ErlDrvTermData) 2; + output_term(msg, 6); + break; + + case 5: + output_term(msg, make_ext_term_list(msg, 0)); + break; + + case 6: + msg[0] = ERL_DRV_INT; + msg[1] = ~((ErlDrvTermData) 0); + msg[2] = ERL_DRV_UINT; + msg[3] = ~((ErlDrvTermData) 0); + msg[4] = ERL_DRV_TUPLE; + msg[5] = (ErlDrvTermData) 2; + output_term(msg, 6); + break; + + case 7: { + int len = 0; + char buf[1024]; + memset(buf, 17, sizeof(buf)); + /* empty heap binary */ + msg[len++] = ERL_DRV_BUF2BINARY; + msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */ + msg[len++] = (ErlDrvTermData) 0; + /* empty heap binary again */ + msg[len++] = ERL_DRV_BUF2BINARY; + msg[len++] = (ErlDrvTermData) &buf[0]; /* ptr is ok if size == 0 */ + msg[len++] = (ErlDrvTermData) 0; + /* heap binary */ + msg[len++] = ERL_DRV_BUF2BINARY; + msg[len++] = (ErlDrvTermData) &buf[0]; + msg[len++] = (ErlDrvTermData) 17; + /* off heap binary */ + msg[len++] = ERL_DRV_BUF2BINARY; + msg[len++] = (ErlDrvTermData) &buf[0]; + msg[len++] = (ErlDrvTermData) sizeof(buf); + + msg[len++] = ERL_DRV_TUPLE; + msg[len++] = (ErlDrvTermData) 4; + + output_term(msg, len); + break; + } + + case 8: + msg[0] = ERL_DRV_NIL; + output_term(msg, 1); + break; + + case 9: + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_mk_atom(""); + output_term(msg, 2); + break; + + case 10: + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); + output_term(msg, 2); + break; + + case 11: + msg[0] = ERL_DRV_INT; + msg[1] = (ErlDrvTermData) -4711; + output_term(msg, 2); + break; + + case 12: + msg[0] = ERL_DRV_UINT; + msg[1] = (ErlDrvTermData) 4711; + output_term(msg, 2); + + break; + case 13: + msg[0] = ERL_DRV_PORT; + msg[1] = driver_mk_port(erlang_port); + output_term(msg, 2); + break; + + case 14: { + ErlDrvBinary *dbin = driver_alloc_binary(0); + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) dbin; + msg[2] = (ErlDrvTermData) 0; + msg[3] = (ErlDrvTermData) 0; + output_term(msg, 4); + driver_free_binary(dbin); + break; + } + + case 15: { + char buf[] = "hejsan"; + ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1); + if (dbin) + memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) dbin; + msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0); + msg[3] = (ErlDrvTermData) 0; + output_term(msg, 4); + driver_free_binary(dbin); + break; + } + + case 16: + msg[0] = ERL_DRV_BUF2BINARY; + msg[1] = (ErlDrvTermData) NULL; + msg[2] = (ErlDrvTermData) 0; + output_term(msg, 3); + break; + + case 17: { + char buf[] = ""; + msg[0] = ERL_DRV_BUF2BINARY; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + output_term(msg, 3); + break; + } + + case 18: { + char buf[] = "hoppsan"; + msg[0] = ERL_DRV_BUF2BINARY; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + output_term(msg, 3); + break; + } + + case 19: + msg[0] = ERL_DRV_STRING; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) 0; + output_term(msg, 3); + break; + + case 20: { + char buf[] = ""; + msg[0] = ERL_DRV_STRING; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + output_term(msg, 3); + break; + } + + case 21: { + char buf[] = "hippsan"; + msg[0] = ERL_DRV_STRING; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + output_term(msg, 3); + break; + } + + case 22: + msg[0] = ERL_DRV_TUPLE; + msg[1] = (ErlDrvTermData) 0; + output_term(msg, 2); + break; + + case 23: + msg[0] = ERL_DRV_NIL; + msg[1] = ERL_DRV_LIST; + msg[2] = (ErlDrvTermData) 1; + output_term(msg, 3); + break; + + case 24: + msg[0] = ERL_DRV_PID; + msg[1] = driver_connected(erlang_port); + output_term(msg, 2); + break; + + case 25: + msg[0] = ERL_DRV_NIL; + msg[1] = ERL_DRV_STRING_CONS; + msg[2] = (ErlDrvTermData) ""; + msg[3] = (ErlDrvTermData) 0; + output_term(msg, 4); + break; + + case 26: { + double my_float = 0.0; + msg[0] = ERL_DRV_FLOAT; + msg[1] = (ErlDrvTermData) &my_float; + output_term(msg, 2); + break; + } + + case 27: { + char buf[] = {131, 106}; /* [] */ + msg[0] = ERL_DRV_EXT2TERM; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf); + output_term(msg, 3); + break; + } + + case 28: { + ErlDrvUInt64 x = ~((ErlDrvUInt64) 0); + msg[0] = ERL_DRV_UINT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 29: { + ErlDrvUInt64 x = ((ErlDrvUInt64) 4711) << 32; + msg[0] = ERL_DRV_UINT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 30: { + ErlDrvUInt64 x = 4711; + msg[0] = ERL_DRV_UINT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 31: { + ErlDrvUInt64 x = 0; + msg[0] = ERL_DRV_UINT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 32: { + ErlDrvSInt64 x = ((((ErlDrvUInt64) 0x7fffffff) << 32) + | ((ErlDrvUInt64) 0xffffffff)); + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 33: { + ErlDrvSInt64 x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32); + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 34: { + ErlDrvSInt64 x = 4711; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 35: { + ErlDrvSInt64 x = 0; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 36: { + ErlDrvSInt64 x = -1; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 37: { + ErlDrvSInt64 x = -4711; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 38: { + ErlDrvSInt64 x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + case 39: { + ErlDrvSInt64 x = ((ErlDrvSInt64) 1) << 63; + msg[0] = ERL_DRV_INT64; + msg[1] = (ErlDrvTermData) &x; + output_term(msg, 2); + + break; + } + + + case 127: /* Error cases */ + { + long refc; + ErlDrvBinary* bin = driver_alloc_binary(256); + + FAIL_TERM(msg, 0); + + msg[0] = ERL_DRV_LIST; + msg[1] = (ErlDrvTermData) 0; + FAIL_TERM(msg, 2); + + /* Not an atom */ + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_connected(erlang_port); + FAIL_TERM(msg, 2); + msg[0] = ERL_DRV_ATOM; + msg[1] = driver_term_nil; + FAIL_TERM(msg, 2); + + /* Not a pid */ + msg[0] = ERL_DRV_PID; + msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); + FAIL_TERM(msg, 2); + msg[0] = ERL_DRV_PID; + msg[1] = driver_term_nil; + FAIL_TERM(msg, 2); + + /* Not a port */ + msg[0] = ERL_DRV_PORT; + msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); + FAIL_TERM(msg, 2); + msg[0] = ERL_DRV_PORT; + msg[1] = driver_term_nil; + FAIL_TERM(msg, 2); + + /* Missing parameter on stack */ + msg[0] = ERL_DRV_STRING_CONS; + msg[1] = (ErlDrvTermData) "abc"; + msg[2] = (ErlDrvTermData) 3; + FAIL_TERM(msg, 3); + + /* + * The first binary reference is correct, the second is incorrect. + * There should not be any "binary leak". + */ + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) bin; + msg[2] = (ErlDrvTermData) 256; + msg[3] = (ErlDrvTermData) 0; + msg[4] = ERL_DRV_BINARY; + msg[5] = (ErlDrvTermData) bin; + msg[6] = (ErlDrvTermData) 257; + msg[7] = (ErlDrvTermData) 0; + msg[8] = ERL_DRV_TUPLE; + msg[9] = (ErlDrvTermData) 2; + FAIL_TERM(msg, 10); + + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) bin; + msg[2] = (ErlDrvTermData) 256; + msg[3] = (ErlDrvTermData) 0; + msg[4] = ERL_DRV_BINARY; + msg[5] = (ErlDrvTermData) bin; + msg[6] = (ErlDrvTermData) 256; + msg[7] = (ErlDrvTermData) 50; + msg[8] = ERL_DRV_TUPLE; + msg[9] = (ErlDrvTermData) 2; + FAIL_TERM(msg, 10); + + /* + * We have succefully built two binaries. We expect the ref count + * to be 1 (SMP) or 3 (non-SMP). + */ + refc = driver_binary_get_refc(bin); + if (refc > 3) { + char sbuf[128]; + sprintf(sbuf, "bad_refc:%d", refc); + driver_failure_atom(erlang_port, sbuf); + } + driver_free_binary(bin); + + + FAIL_TERM(msg, make_ext_term_list(msg, 1)); + + + /* + * Check that we fail for missing args. + * + * We setup valid terms but pass a too small size. We + * want valid terms since we want to verify that the + * failure really is due to the small size. + */ + msg[0] = ERL_DRV_ATOM; + msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); + FAIL_TERM(msg, 1); + + msg[0] = ERL_DRV_INT; + msg[1] = (ErlDrvTermData) -4711; + FAIL_TERM(msg, 1); + + msg[0] = ERL_DRV_UINT; + msg[1] = (ErlDrvTermData) 4711; + FAIL_TERM(msg, 1); + + msg[0] = ERL_DRV_PORT; + msg[1] = driver_mk_port(erlang_port); + FAIL_TERM(msg, 1); + + { + char buf[] = "hejsan"; + ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1); + if (!dbin) + driver_failure_posix(erlang_port, ENOMEM); + else { + memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); + msg[0] = ERL_DRV_BINARY; + msg[1] = (ErlDrvTermData) dbin; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + msg[3] = (ErlDrvTermData) 0; + FAIL_TERM(msg, 1); + FAIL_TERM(msg, 2); + FAIL_TERM(msg, 3); + driver_free_binary(dbin); + } + } + + { + char buf[] = "hoppsan"; + msg[0] = ERL_DRV_BUF2BINARY; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + FAIL_TERM(msg, 1); + FAIL_TERM(msg, 2); + } + + { + char buf[] = "hippsan"; + msg[0] = ERL_DRV_STRING; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf)-1; + FAIL_TERM(msg, 1); + FAIL_TERM(msg, 2); + } + + msg[0] = ERL_DRV_TUPLE; + msg[1] = (ErlDrvTermData) 0; + FAIL_TERM(msg, 1); + + msg[0] = ERL_DRV_NIL; + msg[1] = ERL_DRV_LIST; + msg[2] = (ErlDrvTermData) 1; + FAIL_TERM(msg, 2); + + msg[0] = ERL_DRV_PID; + msg[1] = driver_connected(erlang_port); + FAIL_TERM(msg, 1); + + msg[0] = ERL_DRV_NIL; + msg[1] = ERL_DRV_STRING_CONS; + msg[2] = (ErlDrvTermData) ""; + msg[3] = (ErlDrvTermData) 0; + FAIL_TERM(msg, 2); + FAIL_TERM(msg, 3); + + { + double my_float = 0.0; + msg[0] = ERL_DRV_FLOAT; + msg[1] = (ErlDrvTermData) &my_float; + FAIL_TERM(msg, 1); + } + + { + char buf[] = {131, 106}; /* [] */ + msg[0] = ERL_DRV_EXT2TERM; + msg[1] = (ErlDrvTermData) buf; + msg[2] = (ErlDrvTermData) sizeof(buf); + FAIL_TERM(msg, 1); + FAIL_TERM(msg, 2); + } + + /* Signal end of test case */ + msg[0] = ERL_DRV_NIL; + driver_output_term(erlang_port, msg, 1); + } + break; + + default: + driver_failure_atom(erlang_port, "bad_request"); + break; + } +} + +static void output_term(ErlDrvTermData* msg, int len) +{ + if (driver_output_term(erlang_port, msg, len) <= 0) { + driver_failure_atom(erlang_port, "driver_output_term_failed"); + } +} + +static void fail_term(ErlDrvTermData* msg, int len, int line) +{ + int status = driver_output_term(erlang_port, msg, len); + + if (status == 1) { + char buf[1024]; + sprintf(buf, "%s:%d: unexpected success", __FILE__, line); + driver_failure_atom(erlang_port, buf); + } else if (status == 0) { + char buf[1024]; + sprintf(buf, "%s:%d: unexpected port error", __FILE__, line); + driver_failure_atom(erlang_port, buf); + } +} + +#include "ext_terms.h" + +/* + * <<131,103,100,0,12,97,110,111,100,101,64,103,111,114,98,97,103,0,0,0,36,0,0,0,0,1>> + * is a valid pid: <0.36.0> + * + * We replace the nodename tag (atom tag: 100) with a pid tag (103) to get an + * invalid pid. + */ +static unsigned char bad_ext_term[] = { + 131,103,103,0,12,97,110,111,100,101,64,103,111,114,98,97,103,0,0,0,36,0,0,0,0,1 + /* ^ + * | + * The bad tag. + */ +}; + +static int make_ext_term_list(ErlDrvTermData *td, int bad) +{ + int tdix = 0; + int i; + for (i = 0; i < NO_OF_EXT_TERMS; i++) { + td[tdix++] = ERL_DRV_EXT2TERM; + td[tdix++] = (ErlDrvTermData) &ext_terms[i].ext[0]; + td[tdix++] = (ErlDrvTermData) ext_terms[i].ext_size; + td[tdix++] = ERL_DRV_EXT2TERM; + td[tdix++] = (ErlDrvTermData) &ext_terms[i].cext[0]; + td[tdix++] = (ErlDrvTermData) ext_terms[i].cext_size; + td[tdix++] = ERL_DRV_TUPLE; + td[tdix++] = (ErlDrvTermData) 2; + } + if (bad) { /* Include a bad ext term */ + td[tdix++] = ERL_DRV_EXT2TERM; + td[tdix++] = (ErlDrvTermData) &bad_ext_term[0]; + td[tdix++] = (ErlDrvTermData) sizeof(bad_ext_term); + } + td[tdix++] = ERL_DRV_NIL; + td[tdix++] = ERL_DRV_LIST; + td[tdix++] = (ErlDrvTermData) (NO_OF_EXT_TERMS + (bad ? 2 : 1)); + return tdix; +} |