1 /* 2 * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 #include <openssl/ssl.h> 10 #include <openssl/quic.h> 11 #include <openssl/bio.h> 12 #include <openssl/lhash.h> 13 #include <openssl/rand.h> 14 #include "../testutil.h" 15 #include "internal/numbers.h" /* UINT64_C */ 16 #include "internal/time.h" /* OSSL_TIME */ 17 18 static const char *cert_file, *key_file; 19 20 /* 21 * TERP - Test Executive Script Interpreter 22 * ======================================== 23 */ 24 typedef struct gen_ctx_st GEN_CTX; 25 26 typedef void (*script_gen_t)(GEN_CTX *ctx); 27 28 typedef struct script_info_st { 29 /* name: A symbolic name, like simple_conn. */ 30 const char *name; 31 /* desc: A short, one-line description. */ 32 const char *desc; 33 const char *file; 34 int line; 35 /* gen_func: The script generation function. */ 36 script_gen_t gen_func; 37 } SCRIPT_INFO; 38 39 struct gen_ctx_st { 40 SCRIPT_INFO *script_info; 41 const char *cur_file; 42 int error, cur_line; 43 const char *first_error_msg, *first_error_file; 44 int first_error_line; 45 46 uint8_t *build_buf_beg, *build_buf_cur, *build_buf_end; 47 }; 48 49 static int GEN_CTX_init(GEN_CTX *ctx, SCRIPT_INFO *script_info) 50 { 51 ctx->script_info = script_info; 52 ctx->error = 0; 53 ctx->cur_file = NULL; 54 ctx->cur_line = 0; 55 ctx->first_error_msg = NULL; 56 ctx->first_error_line = 0; 57 ctx->build_buf_beg = NULL; 58 ctx->build_buf_cur = NULL; 59 ctx->build_buf_end = NULL; 60 return 1; 61 } 62 63 static void GEN_CTX_cleanup(GEN_CTX *ctx) 64 { 65 OPENSSL_free(ctx->build_buf_beg); 66 ctx->build_buf_beg = ctx->build_buf_cur = ctx->build_buf_end = NULL; 67 } 68 69 typedef struct terp_st TERP; 70 71 #define F_RET_SPIN_AGAIN 2 72 #define F_RET_SKIP_REST 3 73 74 #define F_SPIN_AGAIN() \ 75 do { \ 76 ok = F_RET_SPIN_AGAIN; \ 77 fctx->spin_again = 1; \ 78 goto err; \ 79 } while (0) 80 81 #define F_SKIP_REST() \ 82 do { \ 83 ok = F_RET_SKIP_REST; \ 84 fctx->skip_rest = 1; \ 85 goto err; \ 86 } while (0) 87 88 typedef struct func_ctx_st { 89 TERP *terp; 90 91 /* 92 * Set to 1 inside a user function if the function should spin again. 93 * Cleared automatically after the user function returns. 94 */ 95 int spin_again; 96 97 /* 98 * Immediately exit script successfully. Useful for skipping. 99 */ 100 int skip_rest; 101 } FUNC_CTX; 102 103 static ossl_inline int TERP_stk_pop(TERP *terp, 104 void *buf, size_t buf_len); 105 106 #define TERP_STK_PUSH(terp, v) \ 107 do { \ 108 if (!TEST_true(TERP_stk_push((terp), &(v), sizeof(v)))) \ 109 goto err; \ 110 } while (0) 111 112 #define TERP_STK_POP(terp, v) \ 113 do { \ 114 memset(&(v), 0, sizeof(v)); /* quiet warnings */ \ 115 if (!TEST_true(TERP_stk_pop((terp), &(v), sizeof(v)))) \ 116 goto err; \ 117 } while (0) 118 119 #define TERP_STK_POP2(terp, a, b) \ 120 do { \ 121 TERP_STK_POP((terp), (b)); \ 122 TERP_STK_POP((terp), (a)); \ 123 } while (0) 124 125 #define F_PUSH(v) TERP_STK_PUSH(fctx->terp, (v)) 126 #define F_POP(v) TERP_STK_POP (fctx->terp, (v)) 127 #define F_POP2(a, b) TERP_STK_POP2(fctx->terp, (a), (b)) 128 129 typedef int (*helper_func_t)(FUNC_CTX *fctx); 130 131 #define DEF_FUNC(name) ossl_unused static int name(FUNC_CTX *fctx) 132 133 #define DEF_SCRIPT(name, desc) \ 134 static void script_gen_##name(GEN_CTX *ctx); \ 135 static SCRIPT_INFO script_info_##name = { \ 136 #name, desc, __FILE__, __LINE__, \ 137 script_gen_##name \ 138 }; \ 139 static void script_gen_##name(GEN_CTX *ctx) 140 141 enum { 142 OPK_INVALID, 143 OPK_END, 144 OPK_PUSH_P, 145 /* 146 * This is exactly like PUSH_P, but the script dumper knows the pointer 147 * points to a static NUL-terminated string and can therefore print it. 148 */ 149 OPK_PUSH_PZ, 150 OPK_PUSH_U64, 151 /* 152 * Could use OPK_PUSH_U64 for this but it's annoying to have to avoid using 153 * size_t in case it is a different size. 154 */ 155 OPK_PUSH_SIZE, 156 OPK_FUNC, 157 OPK_LABEL 158 }; 159 160 static void *openc_alloc_space(GEN_CTX *ctx, size_t num_bytes); 161 162 #define DEF_ENCODER(name, type) \ 163 static void name(GEN_CTX *ctx, type v) \ 164 { \ 165 void *dst = openc_alloc_space(ctx, sizeof(v)); \ 166 if (dst == NULL) \ 167 return; \ 168 \ 169 memcpy(dst, &v, sizeof(v)); \ 170 } 171 172 DEF_ENCODER(openc_u64, uint64_t) 173 DEF_ENCODER(openc_size, size_t) 174 DEF_ENCODER(openc_p, void *) 175 DEF_ENCODER(openc_fp, helper_func_t) 176 #define openc_opcode openc_u64 177 178 static void opgen_END(GEN_CTX *ctx) 179 { 180 openc_opcode(ctx, OPK_END); 181 } 182 183 static ossl_unused void opgen_PUSH_P(GEN_CTX *ctx, void *p) 184 { 185 openc_opcode(ctx, OPK_PUSH_P); 186 openc_p(ctx, p); 187 } 188 189 static void opgen_PUSH_PZ(GEN_CTX *ctx, void *p) 190 { 191 openc_opcode(ctx, OPK_PUSH_PZ); 192 openc_p(ctx, p); 193 } 194 195 static void opgen_PUSH_U64(GEN_CTX *ctx, uint64_t v) 196 { 197 openc_opcode(ctx, OPK_PUSH_U64); 198 openc_u64(ctx, v); 199 } 200 201 ossl_unused static void opgen_PUSH_SIZE(GEN_CTX *ctx, size_t v) 202 { 203 openc_opcode(ctx, OPK_PUSH_SIZE); 204 openc_size(ctx, v); 205 } 206 207 ossl_unused static void opgen_FUNC(GEN_CTX *ctx, helper_func_t f, 208 const char *f_name) 209 { 210 openc_opcode(ctx, OPK_FUNC); 211 openc_fp(ctx, f); 212 openc_p(ctx, (void *)f_name); 213 } 214 215 ossl_unused static void opgen_LABEL(GEN_CTX *ctx, const char *name) 216 { 217 openc_opcode(ctx, OPK_LABEL); 218 openc_p(ctx, (void *)name); 219 } 220 221 static void opgen_set_line(GEN_CTX *ctx, const char *file, int line) 222 { 223 ctx->cur_file = file; 224 ctx->cur_line = line; 225 } 226 227 static ossl_unused void opgen_fail(GEN_CTX *ctx, const char *msg) 228 { 229 if (!ctx->error) { 230 ctx->first_error_file = ctx->cur_file; 231 ctx->first_error_line = ctx->cur_line; 232 ctx->first_error_msg = msg; 233 } 234 235 ctx->error = 1; 236 } 237 238 #define OPGEN(n) (opgen_set_line(ctx, __FILE__, __LINE__), \ 239 opgen_##n) 240 #define OP_END() OPGEN(END) (ctx) 241 #define OP_PUSH_P(v) OPGEN(PUSH_P) (ctx, (v)) 242 #define OP_PUSH_PZ(v) OPGEN(PUSH_PZ) (ctx, (v)) 243 #define OP_PUSH_U64(v) OPGEN(PUSH_U64) (ctx, (v)) 244 #define OP_PUSH_SIZE(v) OPGEN(PUSH_SIZE) (ctx, (v)) 245 #define OP_PUSH_BUFP(p, l) (OP_PUSH_P(p), OP_PUSH_SIZE(l)) 246 #define OP_PUSH_BUF(v) OP_PUSH_BUFP(&(v), sizeof(v)) 247 #define OP_PUSH_LREF(v) OPGEN(PUSH_LREF)(ctx, (lref)) 248 #define OP_FUNC(f) OPGEN(FUNC) (ctx, (f), #f) 249 #define OP_LABEL(name) OPGEN(LABEL) (ctx, (name)) 250 #define GEN_FAIL(msg) OPGEN(fail) (ctx, (msg)) 251 252 static void *openc_alloc_space(GEN_CTX *ctx, size_t num_bytes) 253 { 254 void *p; 255 size_t cur_spare, old_size, new_size, off; 256 257 cur_spare = ctx->build_buf_end - ctx->build_buf_cur; 258 if (cur_spare < num_bytes) { 259 off = ctx->build_buf_cur - ctx->build_buf_beg; 260 old_size = ctx->build_buf_end - ctx->build_buf_beg; 261 new_size = (old_size == 0) ? 1024 : old_size * 2; 262 p = OPENSSL_realloc(ctx->build_buf_beg, new_size); 263 if (!TEST_ptr(p)) 264 return NULL; 265 266 ctx->build_buf_beg = p; 267 ctx->build_buf_cur = ctx->build_buf_beg + off; 268 ctx->build_buf_end = ctx->build_buf_beg + new_size; 269 } 270 271 p = ctx->build_buf_cur; 272 ctx->build_buf_cur += num_bytes; 273 return p; 274 } 275 276 /* 277 * Script Interpreter 278 * ============================================================================ 279 */ 280 typedef struct gen_script_st { 281 const uint8_t *buf; 282 size_t buf_len; 283 } GEN_SCRIPT; 284 285 static int GEN_CTX_finish(GEN_CTX *ctx, GEN_SCRIPT *script) 286 { 287 script->buf = ctx->build_buf_beg; 288 script->buf_len = ctx->build_buf_cur - ctx->build_buf_beg; 289 ctx->build_buf_beg = ctx->build_buf_cur = ctx->build_buf_end = NULL; 290 return 1; 291 } 292 293 static void GEN_SCRIPT_cleanup(GEN_SCRIPT *script) 294 { 295 OPENSSL_free((char *)script->buf); 296 297 script->buf = NULL; 298 script->buf_len = 0; 299 } 300 301 static int GEN_SCRIPT_init(GEN_SCRIPT *gen_script, SCRIPT_INFO *script_info) 302 { 303 int ok = 0; 304 GEN_CTX gctx; 305 306 if (!TEST_true(GEN_CTX_init(&gctx, script_info))) 307 return 0; 308 309 script_info->gen_func(&gctx); 310 opgen_END(&gctx); 311 312 if (!TEST_false(gctx.error)) 313 goto err; 314 315 if (!TEST_true(GEN_CTX_finish(&gctx, gen_script))) 316 goto err; 317 318 ok = 1; 319 err: 320 if (!ok) { 321 if (gctx.error) 322 TEST_error("script generation failed: %s (at %s:%d)", 323 gctx.first_error_msg, 324 gctx.first_error_file, 325 gctx.first_error_line); 326 327 GEN_CTX_cleanup(&gctx); 328 } 329 return ok; 330 } 331 332 typedef struct srdr_st { 333 const uint8_t *beg, *cur, *end, *save_cur; 334 } SRDR; 335 336 static void SRDR_init(SRDR *rdr, const uint8_t *buf, size_t buf_len) 337 { 338 rdr->beg = rdr->cur = buf; 339 rdr->end = rdr->beg + buf_len; 340 rdr->save_cur = NULL; 341 } 342 343 static ossl_inline int SRDR_get_operand(SRDR *srdr, void *buf, size_t buf_len) 344 { 345 if (!TEST_size_t_ge(srdr->end - srdr->cur, buf_len)) 346 return 0; /* malformed script */ 347 348 memcpy(buf, srdr->cur, buf_len); 349 srdr->cur += buf_len; 350 return 1; 351 } 352 353 static ossl_inline void SRDR_save(SRDR *srdr) 354 { 355 srdr->save_cur = srdr->cur; 356 } 357 358 static ossl_inline void SRDR_restore(SRDR *srdr) 359 { 360 srdr->cur = srdr->save_cur; 361 } 362 363 #define GET_OPERAND(srdr, v) \ 364 do { \ 365 memset(&(v), 0, sizeof(v)); /* quiet uninitialized warn */ \ 366 if (!TEST_true(SRDR_get_operand(srdr, &(v), sizeof(v)))) \ 367 goto err; \ 368 } while (0) 369 370 371 static void print_opc(BIO *bio, size_t op_num, size_t offset, const char *name) 372 { 373 if (op_num != SIZE_MAX) 374 BIO_printf(bio, "%3zu- %4zx>\t%-8s \t", op_num, 375 offset, name); 376 else 377 BIO_printf(bio, " %4zx>\t%-8s \t", 378 offset, name); 379 } 380 381 static int SRDR_print_one(SRDR *srdr, BIO *bio, size_t i, int *was_end) 382 { 383 int ok = 0; 384 const uint8_t *opc_start; 385 uint64_t opc; 386 387 if (was_end != NULL) 388 *was_end = 0; 389 390 opc_start = srdr->cur; 391 GET_OPERAND(srdr, opc); 392 393 #define PRINT_OPC(name) print_opc(bio, i, (size_t)(opc_start - srdr->beg), #name) 394 395 switch (opc) { 396 case OPK_END: 397 PRINT_OPC(END); 398 opc_start = srdr->cur; 399 if (was_end != NULL) 400 *was_end = 1; 401 break; 402 case OPK_PUSH_P: 403 { 404 void *v; 405 406 GET_OPERAND(srdr, v); 407 PRINT_OPC(PUSH_P); 408 BIO_printf(bio, "%20p", v); 409 } 410 break; 411 case OPK_PUSH_PZ: 412 { 413 void *v; 414 415 GET_OPERAND(srdr, v); 416 PRINT_OPC(PUSH_PZ); 417 if (v != NULL && strlen((const char *)v) == 1) 418 BIO_printf(bio, "%20p (%s)", v, (const char *)v); 419 else 420 BIO_printf(bio, "%20p (\"%s\")", v, (const char *)v); 421 } 422 break; 423 case OPK_PUSH_U64: 424 { 425 uint64_t v; 426 427 GET_OPERAND(srdr, v); 428 PRINT_OPC(PUSH_U64); 429 BIO_printf(bio, "%#20llx (%llu)", 430 (unsigned long long)v, (unsigned long long)v); 431 } 432 break; 433 case OPK_PUSH_SIZE: 434 { 435 size_t v; 436 437 GET_OPERAND(srdr, v); 438 PRINT_OPC(PUSH_SIZE); 439 BIO_printf(bio, "%#20llx (%llu)", 440 (unsigned long long)v, (unsigned long long)v); 441 } 442 break; 443 case OPK_FUNC: 444 { 445 helper_func_t v; 446 void *f_name = NULL, *x = NULL; 447 448 GET_OPERAND(srdr, v); 449 GET_OPERAND(srdr, f_name); 450 451 PRINT_OPC(FUNC); 452 memcpy(&x, &v, sizeof(x) < sizeof(v) ? sizeof(x) : sizeof(v)); 453 BIO_printf(bio, "%s", (const char *)f_name); 454 } 455 break; 456 case OPK_LABEL: 457 { 458 void *l_name; 459 460 GET_OPERAND(srdr, l_name); 461 462 BIO_printf(bio, "\n%s:\n", (const char *)l_name); 463 PRINT_OPC(LABEL); 464 } 465 break; 466 default: 467 TEST_error("unsupported opcode while printing: %llu", 468 (unsigned long long)opc); 469 goto err; 470 } 471 472 ok = 1; 473 err: 474 return ok; 475 } 476 477 static int GEN_SCRIPT_print(GEN_SCRIPT *gen_script, BIO *bio, 478 const SCRIPT_INFO *script_info) 479 { 480 int ok = 0; 481 size_t i; 482 SRDR srdr_v, *srdr = &srdr_v; 483 int was_end = 0; 484 485 SRDR_init(srdr, gen_script->buf, gen_script->buf_len); 486 487 if (script_info != NULL) { 488 BIO_printf(bio, "\nGenerated script for '%s':\n", 489 script_info->name); 490 BIO_printf(bio, "\n--GENERATED-------------------------------------" 491 "----------------------\n"); 492 BIO_printf(bio, " # NAME:\n # %s\n", 493 script_info->name); 494 BIO_printf(bio, " # SOURCE:\n # %s:%d\n", 495 script_info->file, script_info->line); 496 BIO_printf(bio, " # DESCRIPTION:\n # %s\n", script_info->desc); 497 } 498 499 for (i = 0; !was_end; ++i) { 500 BIO_printf(bio, "\n"); 501 502 if (!TEST_true(SRDR_print_one(srdr, bio, i, &was_end))) 503 goto err; 504 } 505 506 if (script_info != NULL) { 507 const unsigned char *opc_start = srdr->cur; 508 509 BIO_printf(bio, "\n"); 510 PRINT_OPC(+++); 511 BIO_printf(bio, "\n------------------------------------------------" 512 "----------------------\n\n"); 513 } 514 515 ok = 1; 516 err: 517 return ok; 518 } 519 520 static void SCRIPT_INFO_print(SCRIPT_INFO *script_info, BIO *bio, int error, 521 const char *msg) 522 { 523 if (error) 524 TEST_error("%s: script '%s' (%s)", 525 msg, script_info->name, script_info->desc); 526 else 527 TEST_info("%s: script '%s' (%s)", 528 msg, script_info->name, script_info->desc); 529 } 530 531 typedef struct terp_config_st { 532 BIO *debug_bio; 533 534 OSSL_TIME (*now_cb)(void *arg); 535 void *now_cb_arg; 536 537 int (*per_op_cb)(TERP *terp, void *arg); 538 void *per_op_cb_arg; 539 540 OSSL_TIME max_execution_time; /* duration */ 541 } TERP_CONFIG; 542 543 #define TERP_DEFAULT_MAX_EXECUTION_TIME (ossl_ms2time(3000)) 544 545 struct terp_st { 546 TERP_CONFIG cfg; 547 const SCRIPT_INFO *script_info; 548 const GEN_SCRIPT *gen_script; 549 SRDR srdr; 550 uint8_t *stk_beg, *stk_cur, *stk_end, *stk_save_cur; 551 FUNC_CTX fctx; 552 uint64_t ops_executed; 553 int log_execute; 554 OSSL_TIME start_time, deadline_time; 555 }; 556 557 static int TERP_init(TERP *terp, 558 const TERP_CONFIG *cfg, 559 const SCRIPT_INFO *script_info, 560 const GEN_SCRIPT *gen_script) 561 { 562 if (!TEST_true(cfg->now_cb != NULL)) 563 return 0; 564 565 terp->cfg = *cfg; 566 terp->script_info = script_info; 567 terp->gen_script = gen_script; 568 terp->fctx.terp = terp; 569 terp->fctx.spin_again = 0; 570 terp->fctx.skip_rest = 0; 571 terp->stk_beg = NULL; 572 terp->stk_cur = NULL; 573 terp->stk_end = NULL; 574 terp->stk_save_cur = NULL; 575 terp->ops_executed = 0; 576 terp->log_execute = 1; 577 578 if (ossl_time_is_zero(terp->cfg.max_execution_time)) 579 terp->cfg.max_execution_time = TERP_DEFAULT_MAX_EXECUTION_TIME; 580 581 return 1; 582 } 583 584 static void TERP_cleanup(TERP *terp) 585 { 586 if (terp->script_info == NULL) 587 return; 588 589 OPENSSL_free(terp->stk_beg); 590 terp->stk_beg = terp->stk_cur = terp->stk_end = NULL; 591 terp->script_info = NULL; 592 } 593 594 static int TERP_stk_ensure_capacity(TERP *terp, size_t spare) 595 { 596 uint8_t *p; 597 size_t old_size, new_size, off; 598 599 old_size = terp->stk_end - terp->stk_beg; 600 if (old_size >= spare) 601 return 1; 602 603 off = terp->stk_end - terp->stk_cur; 604 new_size = old_size != 0 ? old_size * 2 : 256; 605 p = OPENSSL_realloc(terp->stk_beg, new_size); 606 if (!TEST_ptr(p)) 607 return 0; 608 609 terp->stk_beg = p; 610 terp->stk_end = terp->stk_beg + new_size; 611 terp->stk_cur = terp->stk_end - off; 612 return 1; 613 } 614 615 static ossl_inline int TERP_stk_push(TERP *terp, 616 const void *buf, size_t buf_len) 617 { 618 if (!TEST_true(TERP_stk_ensure_capacity(terp, buf_len))) 619 return 0; 620 621 terp->stk_cur -= buf_len; 622 memcpy(terp->stk_cur, buf, buf_len); 623 return 1; 624 } 625 626 static ossl_inline int TERP_stk_pop(TERP *terp, 627 void *buf, size_t buf_len) 628 { 629 if (!TEST_size_t_ge(terp->stk_end - terp->stk_cur, buf_len)) 630 return 0; 631 632 memcpy(buf, terp->stk_cur, buf_len); 633 terp->stk_cur += buf_len; 634 return 1; 635 } 636 637 static void TERP_print_stack(TERP *terp, BIO *bio, const char *header) 638 { 639 test_output_memory(header, terp->stk_cur, terp->stk_end - terp->stk_cur); 640 BIO_printf(bio, " (%zu bytes)\n", (size_t)(terp->stk_end - terp->stk_cur)); 641 BIO_printf(bio, "\n"); 642 } 643 644 #define TERP_GET_OPERAND(v) GET_OPERAND(&terp->srdr, (v)) 645 646 #define TERP_SPIN_AGAIN() \ 647 do { \ 648 SRDR_restore(&terp->srdr); \ 649 terp->stk_cur = terp->stk_save_cur; \ 650 ++spin_count; \ 651 goto spin_again; \ 652 } while (0) 653 654 static OSSL_TIME TERP_now(TERP *terp) 655 { 656 return terp->cfg.now_cb(terp->cfg.now_cb_arg); 657 } 658 659 static void TERP_log_spin(TERP *terp, size_t spin_count) 660 { 661 if (spin_count > 0) 662 BIO_printf(terp->cfg.debug_bio, " \t\t(span %zu times)\n", 663 spin_count); 664 } 665 666 static int TERP_execute(TERP *terp) 667 { 668 int ok = 0; 669 uint64_t opc; 670 size_t op_num = 0; 671 int in_debug_output = 0; 672 size_t spin_count = 0; 673 BIO *debug_bio = terp->cfg.debug_bio; 674 675 SRDR_init(&terp->srdr, terp->gen_script->buf, terp->gen_script->buf_len); 676 677 terp->start_time = TERP_now(terp); 678 terp->deadline_time = ossl_time_add(terp->start_time, 679 terp->cfg.max_execution_time); 680 681 for (;;) { 682 if (terp->log_execute) { 683 SRDR srdr_copy = terp->srdr; 684 685 if (!in_debug_output) { 686 BIO_printf(debug_bio, "\n--EXECUTION-----------------------------" 687 "------------------------------\n"); 688 in_debug_output = 1; 689 } 690 691 TERP_log_spin(terp, spin_count); 692 if (!TEST_true(SRDR_print_one(&srdr_copy, debug_bio, SIZE_MAX, NULL))) 693 goto err; 694 695 BIO_printf(debug_bio, "\n"); 696 } 697 698 TERP_GET_OPERAND(opc); 699 ++op_num; 700 SRDR_save(&terp->srdr); 701 terp->stk_save_cur = terp->stk_cur; 702 spin_count = 0; 703 704 ++terp->ops_executed; 705 706 spin_again: 707 if (ossl_time_compare(TERP_now(terp), terp->deadline_time) >= 0) { 708 TEST_error("timed out while executing op %zu", op_num); 709 if (terp->log_execute) 710 TERP_log_spin(terp, spin_count); 711 goto err; 712 } 713 714 if (terp->cfg.per_op_cb != NULL) 715 if (!TEST_true(terp->cfg.per_op_cb(terp, terp->cfg.per_op_cb_arg))) { 716 TEST_error("pre-operation processing failed at op %zu", op_num); 717 if (terp->log_execute) 718 TERP_log_spin(terp, spin_count); 719 goto err; 720 } 721 722 switch (opc) { 723 case OPK_END: 724 goto stop; 725 case OPK_PUSH_P: 726 case OPK_PUSH_PZ: 727 { 728 void *v; 729 730 TERP_GET_OPERAND(v); 731 TERP_STK_PUSH(terp, v); 732 } 733 break; 734 case OPK_PUSH_U64: 735 { 736 uint64_t v; 737 738 TERP_GET_OPERAND(v); 739 TERP_STK_PUSH(terp, v); 740 } 741 break; 742 case OPK_PUSH_SIZE: 743 { 744 size_t v; 745 746 TERP_GET_OPERAND(v); 747 TERP_STK_PUSH(terp, v); 748 } 749 break; 750 case OPK_LABEL: 751 { 752 const char *l_name; 753 754 TERP_GET_OPERAND(l_name); 755 /* no-op */ 756 } 757 break; 758 case OPK_FUNC: 759 { 760 helper_func_t v; 761 const void *f_name; 762 int ret; 763 764 TERP_GET_OPERAND(v); 765 TERP_GET_OPERAND(f_name); 766 767 if (!TEST_true(v != NULL)) 768 goto err; 769 770 ret = v(&terp->fctx); 771 772 if (terp->fctx.skip_rest) { 773 if (!TEST_int_eq(ret, F_RET_SKIP_REST)) 774 goto err; 775 776 if (terp->log_execute) 777 BIO_printf(terp->cfg.debug_bio, " \t\t(skipping)\n"); 778 779 terp->fctx.skip_rest = 0; 780 goto stop; 781 } else if (terp->fctx.spin_again) { 782 if (!TEST_int_eq(ret, F_RET_SPIN_AGAIN)) 783 goto err; 784 785 terp->fctx.spin_again = 0; 786 TERP_SPIN_AGAIN(); 787 } else { 788 if (!TEST_false(terp->fctx.spin_again)) 789 goto err; 790 791 if (ret != 1) { 792 TEST_error("op %zu (FUNC %s) failed with return value %d", 793 op_num, (const char *)f_name, ret); 794 goto err; 795 } 796 } 797 } 798 break; 799 default: 800 TEST_error("unknown opcode: %llu", (unsigned long long)opc); 801 goto err; 802 } 803 } 804 805 stop: 806 ok = 1; 807 err: 808 if (in_debug_output) 809 BIO_printf(debug_bio, "----------------------------------------" 810 "------------------------------\n"); 811 812 if (!ok) { 813 TEST_error("FAILED while executing script: %s at op %zu, error stack:", 814 terp->script_info->name, op_num); 815 ERR_print_errors(terp->cfg.debug_bio); 816 BIO_printf(debug_bio, "\n"); 817 } else if (ERR_peek_last_error() != 0) { 818 TEST_info("WARNING: errors on error stack despite success:"); 819 ERR_print_errors(terp->cfg.debug_bio); 820 BIO_printf(debug_bio, "\n"); 821 } 822 823 return ok; 824 } 825 826 static int TERP_run(SCRIPT_INFO *script_info, TERP_CONFIG *cfg) 827 { 828 int ok = 0, have_terp = 0; 829 TERP terp; 830 GEN_SCRIPT gen_script = {0}; 831 BIO *debug_bio = cfg->debug_bio; 832 833 SCRIPT_INFO_print(script_info, debug_bio, /*error=*/0, "generating script"); 834 835 /* Generate the script by calling the generator function. */ 836 if (!TEST_true(GEN_SCRIPT_init(&gen_script, script_info))) { 837 SCRIPT_INFO_print(script_info, debug_bio, /*error=*/1, 838 "error while generating script"); 839 goto err; 840 } 841 842 /* Output the script for debugging purposes. */ 843 if (!TEST_true(GEN_SCRIPT_print(&gen_script, debug_bio, script_info))) { 844 SCRIPT_INFO_print(script_info, debug_bio, /*error=*/1, 845 "error while printing script"); 846 goto err; 847 } 848 849 /* Execute the script. */ 850 if (!TEST_true(TERP_init(&terp, cfg, script_info, &gen_script))) 851 goto err; 852 853 have_terp = 1; 854 855 SCRIPT_INFO_print(script_info, debug_bio, /*error=*/0, "executing script"); 856 857 if (!TERP_execute(&terp)) 858 goto err; 859 860 if (terp.stk_end - terp.stk_cur != 0) { 861 TEST_error("stack not empty: %zu bytes left", 862 (size_t)(terp.stk_end - terp.stk_cur)); 863 goto err; 864 } 865 866 ok = 1; 867 err: 868 if (have_terp) { 869 TERP_print_stack(&terp, debug_bio, "Final state of stack"); 870 TERP_cleanup(&terp); 871 } 872 873 GEN_SCRIPT_cleanup(&gen_script); 874 BIO_printf(debug_bio, "Stats:\n Ops executed: %16llu\n\n", 875 (unsigned long long)terp.ops_executed); 876 SCRIPT_INFO_print(script_info, debug_bio, /*error=*/!ok, 877 ok ? "completed" : "failed, exiting"); 878 return ok; 879 } 880 881 #define SCRIPT(name) (&script_info_##name) 882 #define USE(name) SCRIPT(name), 883