Commit de95947ae5db07e4589bb16bab30b6c8ba2b3106

Roland Schatz 2022-05-24T03:04:43

Fix check for invalid varargs arguments. (#707)

diff --git a/src/prep_cif.c b/src/prep_cif.c
index c1832b1..2d0f252 100644
--- a/src/prep_cif.c
+++ b/src/prep_cif.c
@@ -1,6 +1,7 @@
 /* -----------------------------------------------------------------------
    prep_cif.c - Copyright (c) 2011, 2012, 2021  Anthony Green
                 Copyright (c) 1996, 1998, 2007  Red Hat, Inc.
+                Copyright (c) 2022 Oracle and/or its affiliates.
 
    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
@@ -240,7 +241,7 @@ ffi_status ffi_prep_cif_var(ffi_cif *cif,
   if (rc != FFI_OK)
     return rc;
 
-  for (i = 1; i < ntotalargs; i++)
+  for (i = nfixedargs; i < ntotalargs; i++)
     {
       ffi_type *arg_type = atypes[i];
       if (arg_type == &ffi_type_float
diff --git a/testsuite/libffi.call/va_3.c b/testsuite/libffi.call/va_3.c
new file mode 100644
index 0000000..b3e73b5
--- /dev/null
+++ b/testsuite/libffi.call/va_3.c
@@ -0,0 +1,154 @@
+/* Area:		ffi_call
+   Purpose:		Test function with multiple fixed args and variable argument list.
+   Limitations:	none.
+   PR:			none.
+   Originator:	        ARM Ltd., Oracle */
+
+/* { dg-do run } */
+/* { dg-output "" { xfail avr32*-*-* m68k-*-* } } */
+
+#include "ffitest.h"
+#include <stdarg.h>
+
+/*
+ * This is a modified version of va_2.c that has fixed arguments with "small" types that
+ * are not allowed as variable arguments, but they should be still allowed as fixed args.
+ */
+
+static int
+test_fn (char a1, float a2, int n, ...)
+{
+  va_list ap;
+  unsigned char uc;
+  signed char sc;
+  unsigned short us;
+  signed short ss;
+  unsigned int ui;
+  signed int si;
+  unsigned long ul;
+  signed long sl;
+  float f;
+  double d;
+
+  va_start (ap, n);
+
+  uc = va_arg (ap, unsigned);
+  sc = va_arg (ap, signed);
+
+  us = va_arg (ap, unsigned);
+  ss = va_arg (ap, signed);
+
+  ui = va_arg (ap, unsigned int);
+  si = va_arg (ap, signed int);
+
+  ul = va_arg (ap, unsigned long);
+  sl = va_arg (ap, signed long);
+
+  f = va_arg (ap, double);	/* C standard promotes float->double
+				   when anonymous */
+  d = va_arg (ap, double);
+
+  printf ("%d %f uc=%u sc=%d %u %d %u %d %lu %ld %f %f\n",
+	  a1, a2,
+	  uc, sc,
+	  us, ss,
+	  ui, si,
+	  ul, sl,
+	  f, d);
+
+  va_end (ap);
+
+  CHECK(a1 == 1);
+  CHECK((int)a2 == 2);
+  CHECK(uc == 9);
+  CHECK(sc == 10);
+  CHECK(us == 11);
+  CHECK(ss == 12);
+  CHECK(ui == 13);
+  CHECK(si == 14);
+  CHECK(ul == 15);
+  CHECK(sl == 16);
+  CHECK((int)f == 2);
+  CHECK((int)d == 3);
+
+  return n + 1;
+}
+
+int
+main (void)
+{
+  ffi_cif cif;
+  void* args[14];
+  ffi_type* arg_types[14];
+
+  char a1;
+  float a2;
+  int n;
+  ffi_arg res;
+
+  unsigned int uc;
+  signed int sc;
+  unsigned int us;
+  signed int ss;
+  unsigned int ui;
+  signed int si;
+  unsigned long ul;
+  signed long sl;
+  double d1;
+  double f1;
+
+  arg_types[0] = &ffi_type_schar;
+  arg_types[1] = &ffi_type_float;
+  arg_types[2] = &ffi_type_sint;
+  arg_types[3] = &ffi_type_uint;
+  arg_types[4] = &ffi_type_sint;
+  arg_types[5] = &ffi_type_uint;
+  arg_types[6] = &ffi_type_sint;
+  arg_types[7] = &ffi_type_uint;
+  arg_types[8] = &ffi_type_sint;
+  arg_types[9] = &ffi_type_ulong;
+  arg_types[10] = &ffi_type_slong;
+  arg_types[11] = &ffi_type_double;
+  arg_types[12] = &ffi_type_double;
+  arg_types[13] = NULL;
+
+  CHECK(ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 3, 13, &ffi_type_sint, arg_types) == FFI_OK);
+
+  a1 = 1;
+  a2 = 2.0f;
+  n = 41;
+
+  uc = 9;
+  sc = 10;
+  us = 11;
+  ss = 12;
+  ui = 13;
+  si = 14;
+  ul = 15;
+  sl = 16;
+  f1 = 2.12;
+  d1 = 3.13;
+
+  args[0] = &a1;
+  args[1] = &a2;
+  args[2] = &n;
+  args[3] = &uc;
+  args[4] = &sc;
+  args[5] = &us;
+  args[6] = &ss;
+  args[7] = &ui;
+  args[8] = &si;
+  args[9] = &ul;
+  args[10] = &sl;
+  args[11] = &f1;
+  args[12] = &d1;
+  args[13] = NULL;
+
+  ffi_call(&cif, FFI_FN(test_fn), &res, args);
+  /* { dg-output "1 2.000000 uc=9 sc=10 11 12 13 14 15 16 2.120000 3.130000" } */
+  printf("res: %d\n", (int) res);
+  /* { dg-output "\nres: 42" } */
+  CHECK(res == 42);
+
+  return 0;
+}