If there were more than 6 integer arguments before the ellipsis, or there were used more than 8 slots used until the ellipsis (e.g. by a large intermediate struct) we generated wrong code. See testcase.
Unified · Split
| @@ -558,6 +558,36 @@ static int stdarg_test(void) { · 557 unmodified lines | |||
| 558 | return run_callback(src, stdarg_test_callback); | 558 | return run_callback(src, stdarg_test_callback); |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | typedef struct {long long a, b;} stdarg_many_test_struct_type; | ||
| 562 | typedef void (*stdarg_many_test_function_type) (int, int, int, int, int, | ||
| 563 | stdarg_many_test_struct_type, | ||
| 564 | int, int, ...); | ||
| 565 | |||
| 566 | static int stdarg_many_test_callback(void *ptr) | ||
| 567 | { | ||
| 568 | stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr; | ||
| 569 | int x; | ||
| 570 | stdarg_many_test_struct_type l = {10, 11}; | ||
| 571 | f(1, 2, 3, 4, 5, l, 6, 7, &x, 44); | ||
| 572 | return x == 44 ? 0 : -1; | ||
| 573 | } | ||
| 574 | |||
| 575 | static int stdarg_many_test(void) | ||
| 576 | { | ||
| 577 | const char *src = | ||
| 578 | "#include <stdarg.h>\n" | ||
| 579 | "typedef struct {long long a, b;} stdarg_many_test_struct_type;\n" | ||
| 580 | "void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n" | ||
| 581 | " va_list ap;\n" | ||
| 582 | " int *p;\n" | ||
| 583 | " va_start (ap, g);\n" | ||
| 584 | " p = va_arg(ap, int*);\n" | ||
| 585 | " *p = va_arg(ap, int);\n" | ||
| 586 | " va_end (ap);\n" | ||
| 587 | "}\n"; | ||
| 588 | return run_callback(src, stdarg_many_test_callback); | ||
| 589 | } | ||
| 590 | |||
| 561 | /* | 591 | /* |
| 562 | * Test Win32 stdarg handling, since the calling convention will pass a pointer | 592 | * Test Win32 stdarg handling, since the calling convention will pass a pointer |
| 563 | * to the struct and the stdarg pointer must point to that pointer initially. | 593 | * to the struct and the stdarg pointer must point to that pointer initially. |
| @@ -654,6 +684,7 @@ int main(int argc, char **argv) { · 90 unmodified lines | |||
| 654 | RUN_TEST(many_struct_test_2); | 684 | RUN_TEST(many_struct_test_2); |
| 655 | RUN_TEST(many_struct_test_3); | 685 | RUN_TEST(many_struct_test_3); |
| 656 | RUN_TEST(stdarg_test); | 686 | RUN_TEST(stdarg_test); |
| 687 | RUN_TEST(stdarg_many_test); | ||
| 657 | RUN_TEST(stdarg_struct_test); | 688 | RUN_TEST(stdarg_struct_test); |
| 658 | RUN_TEST(arg_align_test); | 689 | RUN_TEST(arg_align_test); |
| 659 | return retval; | 690 | return retval; |
| @@ -1423,21 +1423,15 @@ void gfunc_prolog(CType *func_type) · 1422 unmodified lines | |||
| 1423 | break; | 1423 | break; |
| 1424 | 1424 | ||
| 1425 | case x86_64_mode_integer: | 1425 | case x86_64_mode_integer: |
| 1426 | if (seen_reg_num + reg_count <= 8) { | 1426 | if (seen_reg_num + reg_count > REGN) |
| 1427 | seen_reg_num += reg_count; | 1427 | goto stack_arg; |
| 1428 | } else { | 1428 | seen_reg_num += reg_count; |
| 1429 | seen_reg_num = 8; | ||
| 1430 | goto stack_arg; | ||
| 1431 | } | ||
| 1432 | break; | 1429 | break; |
| 1433 | 1430 | ||
| 1434 | case x86_64_mode_sse: | 1431 | case x86_64_mode_sse: |
| 1435 | if (seen_sse_num + reg_count <= 8) { | 1432 | if (seen_sse_num + reg_count > 8) |
| 1436 | seen_sse_num += reg_count; | 1433 | goto stack_arg; |
| 1437 | } else { | 1434 | seen_sse_num += reg_count; |
| 1438 | seen_sse_num = 8; | ||
| 1439 | goto stack_arg; | ||
| 1440 | } | ||
| 1441 | break; | 1435 | break; |
| 1442 | } | 1436 | } |
| 1443 | } | 1437 | } |