1 /* ``Licensed under the Apache License, Version 2.0 (the "License");
2  * you may not use this file except in compliance with the License.
3  * You may obtain a copy of the License at
4  *
5  *     http://www.apache.org/licenses/LICENSE-2.0
6  *
7  * Unless required by applicable law or agreed to in writing, software
8  * distributed under the License is distributed on an "AS IS" BASIS,
9  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  * See the License for the specific language governing permissions and
11  * limitations under the License.
12  *
13  * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
14  * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
15  * AB. All Rights Reserved.''
16  *
17  *     $Id$
18  */
19 
20 #include "erl_driver.h"
21 #include <stdio.h>
22 #include <errno.h>
23 #include <string.h>
24 
25 static ErlDrvPort erlang_port;
26 static ErlDrvData send_term_drv_start(ErlDrvPort port, char *command);
27 static void send_term_drv_stop(ErlDrvData drv_data);
28 static void send_term_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len);
29 
30 
31 static int make_ext_term_list(ErlDrvTermData *td, int bad);
32 
33 #define FAIL_TERM(M, L) fail_term((M), (L), __LINE__)
34 
35 static ErlDrvEntry send_term_drv_entry = {
36     NULL,
37     send_term_drv_start,
38     send_term_drv_stop,
39     send_term_drv_run,
40     NULL,
41     NULL,
42     "send_term_drv",
43     NULL,
44     NULL, /* handle */
45     NULL, /* control */
46     NULL, /* timeout */
47     NULL, /* outputv */
48     NULL, /* ready_async */
49     NULL,
50     NULL,
51     NULL,
52     ERL_DRV_EXTENDED_MARKER,
53     ERL_DRV_EXTENDED_MAJOR_VERSION,
54     ERL_DRV_EXTENDED_MINOR_VERSION,
55     0,
56     NULL,
57     NULL,
58     NULL,
59 };
60 
DRIVER_INIT(send_term_drv)61 DRIVER_INIT(send_term_drv)
62 {
63     erlang_port = (ErlDrvPort)-1;
64     return &send_term_drv_entry;
65 }
66 
send_term_drv_start(ErlDrvPort port,char * buf)67 static ErlDrvData send_term_drv_start(ErlDrvPort port, char *buf)
68 {
69     if (erlang_port != (ErlDrvPort)-1) {
70 	return ERL_DRV_ERROR_GENERAL;
71     }
72 
73     erlang_port = port;
74     return (ErlDrvData)port;
75 }
76 
send_term_drv_stop(ErlDrvData drv_data)77 static void send_term_drv_stop(ErlDrvData drv_data)
78 {
79 }
80 
81 static void output_term(ErlDrvTermData* msg, int len);
82 static void fail_term(ErlDrvTermData* msg, int len, int line);
83 
send_term_drv_run(ErlDrvData port,char * buf,ErlDrvSizeT count)84 static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count)
85 {
86     char buf7[1024];
87     ErlDrvTermData spec[1024];
88     ErlDrvTermData* msg = spec;
89     ErlDrvBinary* bins[15];
90     int bin_ix = 0;
91     ErlDrvSInt64 s64[15];
92     int s64_ix = 0;
93     ErlDrvUInt64 u64[15];
94     int u64_ix = 0;
95     int i = 0;
96 
97     for (i=0; i<count; i++) switch (buf[i]) {
98     case 0:
99 	msg[0] = ERL_DRV_NIL;
100 	msg += 1;
101 	break;
102 
103     case 1: 			/* Most term types inside a tuple. */
104 	{
105 	    double f = 3.1416;
106 
107 	    msg[0] = ERL_DRV_ATOM;
108 	    msg[1] = driver_mk_atom("blurf");
109 	    msg[2] = ERL_DRV_INT;
110 	    msg[3] = (ErlDrvTermData) 42;
111 	    msg[4] = ERL_DRV_NIL;
112 	    msg[5] = ERL_DRV_INT;
113 	    msg[6] = (ErlDrvTermData) -42;
114 	    msg[7] = ERL_DRV_TUPLE;
115 	    msg[8] = (ErlDrvTermData) 0;
116 	    msg[9] = ERL_DRV_PORT;
117 	    msg[10] = driver_mk_port(erlang_port);
118 	    msg[11] = ERL_DRV_STRING_CONS;
119 	    msg[12] = (ErlDrvTermData) "abc";
120 	    msg[13] = (ErlDrvTermData) 3;
121 	    msg[14] = ERL_DRV_LIST;
122 	    msg[15] = (ErlDrvTermData) 3;
123 	    msg[16] = ERL_DRV_STRING;
124 	    msg[17] = (ErlDrvTermData) "kalle";
125 	    msg[18] = (ErlDrvTermData) 5;
126 	    msg[19] = ERL_DRV_FLOAT;
127 	    msg[20] = (ErlDrvTermData) &f;
128 	    msg[21] = ERL_DRV_PID;
129 	    msg[22] = driver_connected(erlang_port);
130 	    msg[23] = ERL_DRV_MAP;
131 	    msg[24] = (ErlDrvTermData) 0;
132 	    msg[25] = ERL_DRV_TUPLE;
133 	    msg[26] = (ErlDrvTermData) 8;
134 	    msg += 27;
135 	}
136 	break;
137 
138     case 2:			/* Deep stack */
139 	{
140 	    int i;
141 
142 	    for (i = 0; i < 400; i += 2) {
143 		msg[i] = ERL_DRV_INT;
144 		msg[i+1] = (ErlDrvTermData) (i / 2);
145 	    }
146 	    msg[i] = ERL_DRV_NIL;
147 	    msg[i+1] = ERL_DRV_LIST;
148 	    msg[i+2] = (ErlDrvTermData) 201;
149 	    msg += i+3;
150 	}
151 	break;
152 
153     case 3:			/* Binaries */
154 	{
155 	    ErlDrvBinary* bin;
156 	    int i;
157 
158 	    bin = bins[bin_ix++] = driver_alloc_binary(256);
159 	    for (i = 0; i < 256; i++) {
160 		bin->orig_bytes[i] = i;
161 	    }
162 	    msg[0] = ERL_DRV_BINARY;
163 	    msg[1] = (ErlDrvTermData) bin;
164 	    msg[2] = (ErlDrvTermData) 256;
165 	    msg[3] = (ErlDrvTermData) 0;
166 	    msg[4] = ERL_DRV_BINARY;
167 	    msg[5] = (ErlDrvTermData) bin;
168 	    msg[6] = (ErlDrvTermData) 256-23-17;
169 	    msg[7] = (ErlDrvTermData) 23;
170 	    msg[8] = ERL_DRV_TUPLE;
171 	    msg[9] = (ErlDrvTermData) 2;
172 	    msg += 10;
173 	}
174 	break;
175 
176     case 4:			/* Pids */
177 	msg[0] = ERL_DRV_PID;
178 	msg[1] = driver_connected(erlang_port);
179 	msg[2] = ERL_DRV_PID;
180 	msg[3] = driver_caller(erlang_port);
181 	msg[4] = ERL_DRV_TUPLE;
182 	msg[5] = (ErlDrvTermData) 2;
183 	msg += 6;
184 	break;
185 
186     case 5:
187 	msg += make_ext_term_list(msg, 0);
188 	break;
189 
190     case 6:
191 	msg[0] = ERL_DRV_INT;
192 	msg[1] = ~((ErlDrvTermData) 0);
193 	msg[2] = ERL_DRV_UINT;
194 	msg[3] = ~((ErlDrvTermData) 0);
195 	msg[4] = ERL_DRV_TUPLE;
196 	msg[5] = (ErlDrvTermData) 2;
197 	msg += 6;
198 	break;
199 
200     case 7: {
201 	int len = 0;
202 	memset(buf7, 17, sizeof(buf7));
203 	/* empty heap binary */
204 	msg[len++] = ERL_DRV_BUF2BINARY;
205 	msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */
206 	msg[len++] = (ErlDrvTermData) 0;
207 	/* empty heap binary again */
208 	msg[len++] = ERL_DRV_BUF2BINARY;
209 	msg[len++] = (ErlDrvTermData) buf7; /* ptr is ok if size == 0 */
210 	msg[len++] = (ErlDrvTermData) 0;
211 	/* heap binary */
212 	msg[len++] = ERL_DRV_BUF2BINARY;
213 	msg[len++] = (ErlDrvTermData) buf7;
214 	msg[len++] = (ErlDrvTermData) 17;
215 	/* off heap binary */
216 	msg[len++] = ERL_DRV_BUF2BINARY;
217 	msg[len++] = (ErlDrvTermData) buf7;
218 	msg[len++] = (ErlDrvTermData) sizeof(buf7);
219 
220 	msg[len++] = ERL_DRV_TUPLE;
221 	msg[len++] = (ErlDrvTermData) 4;
222 
223 	msg += len;
224 	break;
225     }
226 
227     case 8:
228 	msg[0] = ERL_DRV_NIL;
229 	msg += 1;
230 	break;
231 
232     case 9:
233 	msg[0] = ERL_DRV_ATOM;
234 	msg[1] = (ErlDrvTermData) driver_mk_atom("");
235 	msg += 2;
236 	break;
237 
238     case 10:
239 	msg[0] = ERL_DRV_ATOM;
240 	msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom");
241 	msg += 2;
242 	break;
243 
244     case 11:
245 	msg[0] = ERL_DRV_INT;
246 	msg[1] = (ErlDrvTermData) -4711;
247 	msg += 2;
248 	break;
249 
250     case 12:
251 	msg[0] = ERL_DRV_UINT;
252 	msg[1] = (ErlDrvTermData) 4711;
253 	msg += 2;
254 
255 	break;
256     case 13:
257 	msg[0] = ERL_DRV_PORT;
258 	msg[1] = driver_mk_port(erlang_port);
259 	msg += 2;
260 	break;
261 
262     case 14: {
263 	ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(0);
264 	msg[0] = ERL_DRV_BINARY;
265 	msg[1] = (ErlDrvTermData) dbin;
266 	msg[2] = (ErlDrvTermData) 0;
267 	msg[3] = (ErlDrvTermData) 0;
268 	msg += 4;
269 	break;
270 	}
271 
272     case 15: {
273 	static const char buf[] = "hejsan";
274 	ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(sizeof(buf)-1);
275 	if (dbin)
276 	    memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1);
277 	msg[0] = ERL_DRV_BINARY;
278 	msg[1] = (ErlDrvTermData) dbin;
279 	msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0);
280 	msg[3] = (ErlDrvTermData) 0;
281 	msg += 4;
282 	break;
283 	}
284 
285     case 16:
286 	msg[0] = ERL_DRV_BUF2BINARY;
287 	msg[1] = (ErlDrvTermData) NULL;
288 	msg[2] = (ErlDrvTermData) 0;
289 	msg += 3;
290 	break;
291 
292     case 17: {
293 	static const char buf[] = "";
294 	msg[0] = ERL_DRV_BUF2BINARY;
295 	msg[1] = (ErlDrvTermData) buf;
296 	msg[2] = (ErlDrvTermData) sizeof(buf)-1;
297 	msg += 3;
298 	break;
299 	}
300 
301     case 18: {
302 	static const char buf[] = "hoppsan";
303 	msg[0] = ERL_DRV_BUF2BINARY;
304 	msg[1] = (ErlDrvTermData) buf;
305 	msg[2] = (ErlDrvTermData) sizeof(buf)-1;
306 	msg += 3;
307 	break;
308     }
309 
310     case 19:
311 	msg[0] = ERL_DRV_STRING;
312 	msg[1] = (ErlDrvTermData) buf;
313 	msg[2] = (ErlDrvTermData) 0;
314 	msg += 3;
315 	break;
316 
317     case 20: {
318 	static const char buf[] = "";
319 	msg[0] = ERL_DRV_STRING;
320 	msg[1] = (ErlDrvTermData) buf;
321 	msg[2] = (ErlDrvTermData) sizeof(buf)-1;
322 	msg += 3;
323 	break;
324     }
325 
326     case 21: {
327 	static const char buf[] = "hippsan";
328 	msg[0] = ERL_DRV_STRING;
329 	msg[1] = (ErlDrvTermData) buf;
330 	msg[2] = (ErlDrvTermData) sizeof(buf)-1;
331 	msg += 3;
332 	break;
333 	}
334 
335     case 22:
336 	msg[0] = ERL_DRV_TUPLE;
337 	msg[1] = (ErlDrvTermData) 0;
338 	msg += 2;
339 	break;
340 
341     case 23:
342 	msg[0] = ERL_DRV_NIL;
343 	msg[1] = ERL_DRV_LIST;
344 	msg[2] = (ErlDrvTermData) 1;
345 	msg += 3;
346 	break;
347 
348     case 24:
349 	msg[0] = ERL_DRV_PID;
350 	msg[1] = driver_connected(erlang_port);
351 	msg += 2;
352 	break;
353 
354     case 25:
355 	msg[0] = ERL_DRV_NIL;
356 	msg[1] = ERL_DRV_STRING_CONS;
357 	msg[2] = (ErlDrvTermData) "";
358 	msg[3] = (ErlDrvTermData) 0;
359 	msg += 4;
360 	break;
361 
362     case 26: {
363 	static double my_float = 0.0;
364 	msg[0] = ERL_DRV_FLOAT;
365 	msg[1] = (ErlDrvTermData) &my_float;
366 	msg += 2;
367 	break;
368     }
369 
370     case 27: {
371 	static char buf[] = {131, 106}; /* [] */
372 	msg[0] = ERL_DRV_EXT2TERM;
373 	msg[1] = (ErlDrvTermData) buf;
374 	msg[2] = (ErlDrvTermData) sizeof(buf);
375 	msg += 3;
376 	break;
377     }
378 
379     case 28: {
380 	ErlDrvUInt64* x = &u64[u64_ix++];
381 	*x = ~((ErlDrvUInt64) 0);
382 	msg[0] = ERL_DRV_UINT64;
383 	msg[1] = (ErlDrvTermData) x;
384 	msg += 2;
385 	break;
386     }
387 
388     case 29: {
389 	ErlDrvUInt64* x = &u64[u64_ix++];
390 	*x = ((ErlDrvUInt64) 4711) << 32;
391 	msg[0] = ERL_DRV_UINT64;
392 	msg[1] = (ErlDrvTermData) x;
393 	msg += 2;
394 	break;
395     }
396 
397     case 30: {
398 	ErlDrvUInt64* x = &u64[u64_ix++];
399 	*x = 4711;
400 	msg[0] = ERL_DRV_UINT64;
401 	msg[1] = (ErlDrvTermData) x;
402 	msg += 2;
403 	break;
404     }
405 
406     case 31: {
407 	ErlDrvUInt64* x = &u64[u64_ix++];
408 	*x = 0;
409 	msg[0] = ERL_DRV_UINT64;
410 	msg[1] = (ErlDrvTermData) x;
411 	msg += 2;
412 	break;
413     }
414 
415     case 32: {
416 	ErlDrvSInt64* x = &s64[s64_ix++];
417 	*x = ((((ErlDrvUInt64) 0x7fffffff) << 32) | ((ErlDrvUInt64) 0xffffffff));
418 	msg[0] = ERL_DRV_INT64;
419 	msg[1] = (ErlDrvTermData) x;
420 	msg += 2;
421 	break;
422     }
423 
424     case 33: {
425 	ErlDrvSInt64* x = &s64[s64_ix++];
426 	*x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32);
427 	msg[0] = ERL_DRV_INT64;
428 	msg[1] = (ErlDrvTermData) x;
429 	msg += 2;
430 	break;
431     }
432 
433     case 34: {
434 	ErlDrvSInt64* x = &s64[s64_ix++];
435 	*x = 4711;
436 	msg[0] = ERL_DRV_INT64;
437 	msg[1] = (ErlDrvTermData) x;
438 	msg += 2;
439 	break;
440     }
441 
442     case 35: {
443 	ErlDrvSInt64* x = &s64[s64_ix++];
444 	*x = 0;
445 	msg[0] = ERL_DRV_INT64;
446 	msg[1] = (ErlDrvTermData) x;
447 	msg += 2;
448 	break;
449     }
450 
451     case 36: {
452 	ErlDrvSInt64* x = &s64[s64_ix++];
453 	*x = -1;
454 	msg[0] = ERL_DRV_INT64;
455 	msg[1] = (ErlDrvTermData) x;
456 	msg += 2;
457 	break;
458     }
459 
460     case 37: {
461 	ErlDrvSInt64* x = &s64[s64_ix++];
462 	*x = -4711;
463 	msg[0] = ERL_DRV_INT64;
464 	msg[1] = (ErlDrvTermData) x;
465 	msg += 2;
466 	break;
467     }
468 
469     case 38: {
470 	ErlDrvSInt64* x = &s64[s64_ix++];
471 	*x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1;
472 	msg[0] = ERL_DRV_INT64;
473 	msg[1] = (ErlDrvTermData) x;
474 	msg += 2;
475 	break;
476     }
477 
478     case 39: {
479 	ErlDrvSInt64* x = &s64[s64_ix++];
480 	*x = ((ErlDrvSInt64) 1) << 63;
481 	msg[0] = ERL_DRV_INT64;
482 	msg[1] = (ErlDrvTermData) x;
483 	msg += 2;
484 	break;
485     }
486 
487     case 40: {
488 	msg[0] = ERL_DRV_MAP;
489 	msg[1] = (ErlDrvTermData) 0;
490 	msg += 2;
491 	break;
492     }
493 
494     case 41:    /* Most term types inside a map */
495     case 42: {
496 	double f = 3.1416;
497 
498 	if (buf[i] == 41) {
499 	    *msg++ = ERL_DRV_ATOM;
500 	    *msg++ = driver_mk_atom("blurf");
501 	}
502 	*msg++ = ERL_DRV_INT;
503 	*msg++ = (ErlDrvTermData)42;
504 	*msg++ = ERL_DRV_NIL;
505 	*msg++ = ERL_DRV_INT;
506 	*msg++ = (ErlDrvTermData)-42;
507 	*msg++ = ERL_DRV_TUPLE;
508 	*msg++ = (ErlDrvTermData)0;
509 	*msg++ = ERL_DRV_PORT;
510 	*msg++ = driver_mk_port(erlang_port);
511 	*msg++ = ERL_DRV_STRING_CONS;
512 	*msg++ = (ErlDrvTermData)"abc";
513 	*msg++ = (ErlDrvTermData)3;
514 	*msg++ = ERL_DRV_LIST;
515 	*msg++ = (ErlDrvTermData)3;
516 	*msg++ = ERL_DRV_STRING;
517 	*msg++ = (ErlDrvTermData)"kalle";
518 	*msg++ = (ErlDrvTermData)5;
519 	*msg++ = ERL_DRV_FLOAT;
520 	*msg++ = (ErlDrvTermData)&f;
521 	*msg++ = ERL_DRV_PID;
522 	*msg++ = driver_connected(erlang_port);
523 	*msg++ = ERL_DRV_MAP;
524 	*msg++ = (ErlDrvTermData)0;
525 	if (buf[i] == 42) {
526 	    *msg++ = ERL_DRV_ATOM;
527 	    *msg++ = driver_mk_atom("blurf");
528 	}
529 	*msg++ = ERL_DRV_MAP;
530 	*msg++ = (ErlDrvTermData)4;
531 	break;
532     }
533 
534     case 127:			/* Error cases */
535 	{
536 	    long refc;
537 	    ErlDrvBinary* bin = bins[bin_ix++] = driver_alloc_binary(256);
538 
539 	    FAIL_TERM(msg, 0);
540 
541 	    msg[0] = ERL_DRV_LIST;
542 	    msg[1] = (ErlDrvTermData) 0;
543 	    FAIL_TERM(msg, 2);
544 
545 	    /* Not an atom */
546 	    msg[0] = ERL_DRV_ATOM;
547 	    msg[1] = (ErlDrvTermData) driver_connected(erlang_port);
548 	    FAIL_TERM(msg, 2);
549 	    msg[0] = ERL_DRV_ATOM;
550 	    msg[1] = driver_term_nil;
551 	    FAIL_TERM(msg, 2);
552 
553 	    /* Not a pid */
554 	    msg[0] = ERL_DRV_PID;
555 	    msg[1] = (ErlDrvTermData) driver_mk_atom("blurf");
556 	    FAIL_TERM(msg, 2);
557 	    msg[0] = ERL_DRV_PID;
558 	    msg[1] = driver_term_nil;
559 	    FAIL_TERM(msg, 2);
560 
561 	    /* Not a port */
562 	    msg[0] = ERL_DRV_PORT;
563 	    msg[1] = (ErlDrvTermData) driver_mk_atom("blurf");
564 	    FAIL_TERM(msg, 2);
565 	    msg[0] = ERL_DRV_PORT;
566 	    msg[1] = driver_term_nil;
567 	    FAIL_TERM(msg, 2);
568 
569 	    /* Missing parameter on stack */
570 	    msg[0] = ERL_DRV_STRING_CONS;
571 	    msg[1] = (ErlDrvTermData) "abc";
572 	    msg[2] = (ErlDrvTermData) 3;
573 	    FAIL_TERM(msg, 3);
574 
575 	    /*
576 	     * The first binary reference is correct, the second is incorrect.
577 	     * There should not be any "binary leak".
578 	     */
579 	    msg[0] = ERL_DRV_BINARY;
580 	    msg[1] = (ErlDrvTermData) bin;
581 	    msg[2] = (ErlDrvTermData) 256;
582 	    msg[3] = (ErlDrvTermData) 0;
583 	    msg[4] = ERL_DRV_BINARY;
584 	    msg[5] = (ErlDrvTermData) bin;
585 	    msg[6] = (ErlDrvTermData) 257;
586 	    msg[7] = (ErlDrvTermData) 0;
587 	    msg[8] = ERL_DRV_TUPLE;
588 	    msg[9] = (ErlDrvTermData) 2;
589 	    FAIL_TERM(msg, 10);
590 
591 	    msg[0] = ERL_DRV_BINARY;
592 	    msg[1] = (ErlDrvTermData) bin;
593 	    msg[2] = (ErlDrvTermData) 256;
594 	    msg[3] = (ErlDrvTermData) 0;
595 	    msg[4] = ERL_DRV_BINARY;
596 	    msg[5] = (ErlDrvTermData) bin;
597 	    msg[6] = (ErlDrvTermData) 256;
598 	    msg[7] = (ErlDrvTermData) 50;
599 	    msg[8] = ERL_DRV_TUPLE;
600 	    msg[9] = (ErlDrvTermData) 2;
601 	    FAIL_TERM(msg, 10);
602 
603 	    /*
604 	     * We have succefully built two binaries. We expect the ref count
605 	     * to be 1 (SMP) or 3 (non-SMP).
606 	     */
607 	    refc = driver_binary_get_refc(bin);
608 	    if (refc > 3) {
609 		char sbuf[128];
610 		sprintf(sbuf, "bad_refc:%ld", refc);
611 		driver_failure_atom(erlang_port, sbuf);
612 	    }
613 	    driver_free_binary(bin);
614 
615 
616 	    FAIL_TERM(msg, make_ext_term_list(msg, 1));
617 
618 
619 	    /*
620 	     * Check that we fail for missing args.
621 	     *
622 	     * We setup valid terms but pass a too small size. We
623 	     * want valid terms since we want to verify that the
624 	     * failure really is due to the small size.
625 	     */
626 	    msg[0] = ERL_DRV_ATOM;
627 	    msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom");
628 	    FAIL_TERM(msg, 1);
629 
630 	    msg[0] = ERL_DRV_INT;
631 	    msg[1] = (ErlDrvTermData) -4711;
632 	    FAIL_TERM(msg, 1);
633 
634 	    msg[0] = ERL_DRV_UINT;
635 	    msg[1] = (ErlDrvTermData) 4711;
636 	    FAIL_TERM(msg, 1);
637 
638 	    msg[0] = ERL_DRV_PORT;
639 	    msg[1] = driver_mk_port(erlang_port);
640 	    FAIL_TERM(msg, 1);
641 
642 	    {
643 		char buf[] = "hejsan";
644 		ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1);
645 		if (!dbin)
646 		    driver_failure_posix(erlang_port, ENOMEM);
647 		else {
648 		    memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1);
649 		    msg[0] = ERL_DRV_BINARY;
650 		    msg[1] = (ErlDrvTermData) dbin;
651 		    msg[2] = (ErlDrvTermData) sizeof(buf)-1;
652 		    msg[3] = (ErlDrvTermData) 0;
653 		    FAIL_TERM(msg, 1);
654 		    FAIL_TERM(msg, 2);
655 		    FAIL_TERM(msg, 3);
656 		    driver_free_binary(dbin);
657 		}
658 	    }
659 
660 	    {
661 		char buf[] = "hoppsan";
662 		msg[0] = ERL_DRV_BUF2BINARY;
663 		msg[1] = (ErlDrvTermData) buf;
664 		msg[2] = (ErlDrvTermData) sizeof(buf)-1;
665 		FAIL_TERM(msg, 1);
666 		FAIL_TERM(msg, 2);
667 	    }
668 
669 	    {
670 		char buf[] = "hippsan";
671 		msg[0] = ERL_DRV_STRING;
672 		msg[1] = (ErlDrvTermData) buf;
673 		msg[2] = (ErlDrvTermData) sizeof(buf)-1;
674 		FAIL_TERM(msg, 1);
675 		FAIL_TERM(msg, 2);
676 	    }
677 
678 	    msg[0] = ERL_DRV_TUPLE;
679 	    msg[1] = (ErlDrvTermData) 0;
680 	    FAIL_TERM(msg, 1);
681 
682 	    msg[0] = ERL_DRV_NIL;
683 	    msg[1] = ERL_DRV_LIST;
684 	    msg[2] = (ErlDrvTermData) 1;
685 	    FAIL_TERM(msg, 2);
686 
687 	    msg[0] = ERL_DRV_PID;
688 	    msg[1] = driver_connected(erlang_port);
689 	    FAIL_TERM(msg, 1);
690 
691 	    msg[0] = ERL_DRV_NIL;
692 	    msg[1] = ERL_DRV_STRING_CONS;
693 	    msg[2] = (ErlDrvTermData) "";
694 	    msg[3] = (ErlDrvTermData) 0;
695 	    FAIL_TERM(msg, 2);
696 	    FAIL_TERM(msg, 3);
697 
698 	    {
699 		double my_float = 0.0;
700 		msg[0] = ERL_DRV_FLOAT;
701 		msg[1] = (ErlDrvTermData) &my_float;
702 		FAIL_TERM(msg, 1);
703 	    }
704 
705 	    {
706 		char buf[] = {131, 106}; /* [] */
707 		msg[0] = ERL_DRV_EXT2TERM;
708 		msg[1] = (ErlDrvTermData) buf;
709 		msg[2] = (ErlDrvTermData) sizeof(buf);
710 		FAIL_TERM(msg, 1);
711 		FAIL_TERM(msg, 2);
712 	    }
713 
714 	    msg[0] = ERL_DRV_MAP;
715 	    msg[1] = (ErlDrvTermData) 0;
716 	    FAIL_TERM(msg, 1);
717 
718 	    /* map with duplicate key */
719 	    msg[0] = ERL_DRV_ATOM;
720 	    msg[1] = driver_mk_atom("key");
721 	    msg[2] = ERL_DRV_NIL;
722 	    msg[3] = ERL_DRV_ATOM;
723 	    msg[4] = driver_mk_atom("key");
724 	    msg[5] = ERL_DRV_INT;
725 	    msg[6] = (ErlDrvTermData) -4711;
726 	    msg[7] = ERL_DRV_MAP;
727 	    msg[8] = 2;
728 	    FAIL_TERM(msg, 9);
729 
730 	    /* Signal end of test case */
731 	    msg[0] = ERL_DRV_NIL;
732 	    erl_drv_output_term(driver_mk_port(erlang_port), msg, 1);
733 	    return;
734 	}
735 	break;
736 
737     default:
738 	driver_failure_atom(erlang_port, "bad_request");
739 	break;
740     }
741     if (count > 1) {
742 	*msg++ = ERL_DRV_NIL;
743 	*msg++ = ERL_DRV_LIST;
744 	*msg++ = count + 1;
745     }
746     output_term(spec, msg-spec);
747     if ((bin_ix|s64_ix|u64_ix) > 15) abort();
748     while (bin_ix) {
749 	driver_free_binary(bins[--bin_ix]);
750     }
751 }
752 
output_term(ErlDrvTermData * msg,int len)753 static void output_term(ErlDrvTermData* msg, int len)
754 {
755     if (erl_drv_output_term(driver_mk_port(erlang_port), msg, len) <= 0) {
756 	driver_failure_atom(erlang_port, "erl_drv_output_term_failed");
757     }
758 }
759 
fail_term(ErlDrvTermData * msg,int len,int line)760 static void fail_term(ErlDrvTermData* msg, int len, int line)
761 {
762     int status = erl_drv_output_term(driver_mk_port(erlang_port), msg, len);
763 
764     if (status == 1) {
765 	char buf[1024];
766 	sprintf(buf, "%s:%d: unexpected success", __FILE__, line);
767 	driver_failure_atom(erlang_port, buf);
768     } else if (status == 0) {
769 	char buf[1024];
770 	sprintf(buf, "%s:%d: unexpected port error", __FILE__, line);
771 	driver_failure_atom(erlang_port, buf);
772     }
773 }
774 
775 #include "ext_terms.h"
776 
777 /*
778  * <<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>>
779  * is a valid pid: <0.36.0>
780  *
781  * We replace the nodename tag (atom tag: 100) with a pid tag (103) to get an
782  * invalid pid.
783  */
784 static unsigned char bad_ext_term[] = {
785     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
786     /*       ^
787      *       |
788      * The bad tag.
789      */
790 };
791 
make_ext_term_list(ErlDrvTermData * td,int bad)792 static int make_ext_term_list(ErlDrvTermData *td, int bad)
793 {
794     int tdix = 0;
795     int i;
796     for (i = 0; i < NO_OF_EXT_TERMS; i++) {
797 	td[tdix++] = ERL_DRV_EXT2TERM;
798 	td[tdix++] = (ErlDrvTermData) &ext_terms[i].ext[0];
799 	td[tdix++] = (ErlDrvTermData) ext_terms[i].ext_size;
800 	td[tdix++] = ERL_DRV_EXT2TERM;
801 	td[tdix++] = (ErlDrvTermData) &ext_terms[i].cext[0];
802 	td[tdix++] = (ErlDrvTermData) ext_terms[i].cext_size;
803 	td[tdix++] = ERL_DRV_TUPLE;
804 	td[tdix++] = (ErlDrvTermData) 2;
805     }
806     if (bad) { /* Include a bad ext term */
807 	td[tdix++] = ERL_DRV_EXT2TERM;
808 	td[tdix++] = (ErlDrvTermData) &bad_ext_term[0];
809 	td[tdix++] = (ErlDrvTermData) sizeof(bad_ext_term);
810     }
811     td[tdix++] = ERL_DRV_NIL;
812     td[tdix++] = ERL_DRV_LIST;
813     td[tdix++] = (ErlDrvTermData) (NO_OF_EXT_TERMS + (bad ? 2 : 1));
814     return tdix;
815 }
816