Adds syscall wrappers for __specialfd and __realpathat.
Also remove kernel dependency on COMPAT_FREEBSD10.
This change also reorganizes somewhat the scalar test
and adds configure time checks for the FreeBSD version,
allowing regression tests to be compiled depending on the
FreeBSD release.
From now on, scalar.c will contain syscalls for FreeBSD 11 and 12
and subsequent releases will get their own scalar, starting with
scalar_13_plus.c.
446138 DRD/Helgrind with std::timed_mutex::try_lock_until false positives
446281 Add a DRD suppression for fwrite
446103 Memcheck: `--track-origins=yes` causes extreme slowdowns for large mmap/munmap
+446823 FreeBSD - missing syscalls when using libzm4
To see details of a given bug, visit
https://bugs.kde.org/show_bug.cgi?id=XXXXXX
AC_MSG_RESULT([ok (${host_os})])
VGCONF_OS="freebsd"
AC_DEFINE([FREEBSD_10], 1000, [FREEBSD_VERS value for FreeBSD 10.x])
+ freebsd_10=1000
AC_DEFINE([FREEBSD_11], 1100, [FREEBSD_VERS value for FreeBSD 11.x])
+ freebsd_11=1100
AC_DEFINE([FREEBSD_12], 1200, [FREEBSD_VERS value for FreeBSD 12.0 to 12.1])
+ freebsd_12=1200
AC_DEFINE([FREEBSD_12_2], 1220, [FREEBSD_VERS value for FreeBSD 12.2])
+ freebsd_12_2=1220
AC_DEFINE([FREEBSD_13], 1300, [FREEBSD_VERS value for FreeBSD 13.x])
+ freebsd_13=1300
AC_DEFINE([FREEBSD_14], 1400, [FREEBSD_VERS value for FreeBSD 14.x])
+ freebsd_14=1400
AC_MSG_CHECKING([for the kernel version])
kernel=`uname -r`
10.*)
AC_MSG_RESULT([FreeBSD 10.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_10, [FreeBSD version])
+ freebsd_vers=$freebsd_10
;;
11.*)
AC_MSG_RESULT([FreeBSD 11.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_11, [FreeBSD version])
+ freebsd_vers=$freebsd_11
;;
12.*)
case "${kernel}" in
12.[[0-1]]-*)
AC_MSG_RESULT([FreeBSD 12.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_12, [FreeBSD version])
+ freebsd_vers=$freebsd_12
;;
*)
AC_MSG_RESULT([FreeBSD 12.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_12_2, [FreeBSD version])
+ freebsd_vers=$freebsd_12_2
;;
esac
;;
13.*)
AC_MSG_RESULT([FreeBSD 13.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_13, [FreeBSD version])
+ freebsd_vers=$freebsd_13
;;
14.*)
AC_MSG_RESULT([FreeBSD 14.x (${kernel})])
AC_DEFINE([FREEBSD_VERS], FREEBSD_14, [FreeBSD version])
+ freebsd_vers=$freebsd_14
;;
*)
AC_MSG_RESULT([unsupported (${kernel})])
AM_CONDITIONAL(SOLARIS_SYSTEM_STATS_SYSCALL, false)
fi # test "$VGCONF_OS" = "solaris"
+#----------------------------------------------------------------------------
+# FreeBSD-specific checks.
+#----------------------------------------------------------------------------
+
+# Rather than having a large number of feature test as above with Solaris
+# these tests are per-version. This may not be entirely relialable for
+# FreeBSD development branches (XX.Y-CURRENT) or pre-release branches
+# (XX.Y-STABLE) but it should work for XX-Y-RELEASE
+
+if test "$VGCONF_OS" = "freebsd" ; then
+
+AM_CONDITIONAL(FREEBSD_VERS_13_PLUS, test $freebsd_vers -ge $freebsd_13)
+
+else
+
+AM_CONDITIONAL(FREEBSD_VERS_13_PLUS, false)
+
+fi # test "$VGCONF_OS" = "freebsd"
+
#----------------------------------------------------------------------------
# Checks for C header files.
SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
return sr_isError(res) ? -1 : 0;
# elif defined(VGO_freebsd)
+#if defined(__NR_pipe2)
+ SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
+#else
SysRes res = VG_(do_syscall0)(__NR_freebsd10_pipe);
if (!sr_isError(res)) {
fd[0] = sr_Res(res);
fd[1] = sr_ResHI(res);
}
+#endif
return sr_isError(res) ? -1 : 0;
# elif defined(VGO_darwin)
/* __NR_pipe is UX64, so produces a double-word result */
// unimpl __NR_shm_open2 571
// unimpl __NR_shm_rename 572
// unimpl __NR_sigfastblock 573
-// unimpl __NR___realpathat 574
+DECL_TEMPLATE(freebsd, sys___realpathat) // 574
// unimpl __NR_close_range 575
#endif
#if (FREEBSD_VERS >= FREEBSD_13)
// unimpl __NR_rpctls_syscall 576
-
-#endif
-
-#if (FREEBSD_VERS >= FREEBSD_14)
-
-// unimpl __NR___specialfd 577
+DECL_TEMPLATE(freebsd, sys___specialfd) // 577
// unimpl __NR_aio_writev 578
// unimpl __NR_aio_readv 579
}
}
-#endif
+// SYS___realpathat
+// from syscalls.master
+// int __realpathat(int fd,
+// _In_z_ const char *path,
+// _Out_writes_z_(size) char *buf,
+// size_t size,
+// int flags)
+PRE(sys___realpathat)
+{
+ PRINT("sys___realpathat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %" FMT_REGWORD "u %" FMT_REGWORD "d )",
+ SARG1,ARG2,(const char*)ARG2,ARG3,ARG4,SARG5 );
+ PRE_REG_READ5(int, "__realpathat", int, fd, const char *, path,
+ char *, buf, vki_size_t, size, int, flags);
+ PRE_MEM_RASCIIZ("__realpathat(path)", (Addr)ARG2);
+ PRE_MEM_WRITE("__realpathat(buf)", (Addr)ARG3, ARG4);
+}
+
+POST(sys___realpathat)
+{
+ POST_MEM_WRITE((Addr)ARG3, ARG4);
+}
+
+#endif // (FREEBSD_VERS >= FREEBSD_12_2)
+
+#if (FREEBSD_VERS >= FREEBSD_13)
+
+// SYS___specialfd
+// syscalls.master
+// int __specialfd(int type,
+// _In_reads_bytes_(len) const void *req,
+// size_t len);
+PRE(sys___specialfd)
+{
+ PRINT("sys___specialfd ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",
+ SARG1,ARG2,(const char*)ARG2,ARG3 );
+ PRE_REG_READ3(int, "__specialfd", int, type, const void *, req, vki_size_t, len);
+ PRE_MEM_READ("__specialfd(req)", (Addr)ARG2, ARG3);
+}
+
+#endif // (FREEBSD_VERS >= FREEBSD_13)
#undef PRE
#undef POST
// unimpl __NR_shm_open2 571
// unimpl __NR_shm_rename 572
// unimpl __NR_sigfastblock 573
- // unimpl __NR___realpathat 574
+ BSDXY( __NR___realpathat, sys___realpathat), // 574
// unimpl __NR_close_range 575
#endif
#if (FREEBSD_VERS >= FREEBSD_13)
// unimpl __NR_rpctls_syscall 576
-#endif
-
-#if (FREEBSD_VERS >= FREEBSD_14)
- // unimpl __NR___specialfd 577
+ BSDX_(__NR___specialfd, sys___specialfd), // 577
// unimpl __NR_aio_writev 578
// unimpl __NR_aio_readv 579
#endif
#if (FREEBSD_VERS >= FREEBSD_13)
#define __NR_rpctls_syscall 576
-
-#endif
-
-#if (FREEBSD_VERS >= FREEBSD_14)
-
#define __NR___specialfd 577
#define __NR_aio_writev 578
#define __NR_aio_readv 579
static_allocs.vgtest \
static_allocs.stderr.exp \
fexecve.vgtest \
- fexecve.stderr.exp
+ fexecve.stderr.exp \
+ realpathat.vgtest \
+ realpathat.stderr.exp \
+ scalar_13_plus.vgtest \
+ scalar_13_plus.stderr.exp \
+ eventfd1.vgtest \
+ eventfd1.stderr.exp eventfd1.stdout.exp \
+ eventfd2.vgtest \
+ eventfd2.stderr.exp eventfd2.stdout.exp
check_PROGRAMS = \
statfs pdfork_pdkill getfsstat inlinfo inlinfo_nested.so extattr \
inlinfo_nested_so_CFLAGS = $(AM_CFLAGS) -fPIC @FLAG_W_NO_UNINITIALIZED@
inlinfo_nested_so_LDFLAGS = -Wl,-rpath,$(top_builddir)/memcheck/tests/freebsd -shared -fPIC
+if FREEBSD_VERS_13_PLUS
+check_PROGRAMS += realpathat scalar_13_plus eventfd1 eventfd2
+
+scalar_13_plus_CFLAGS = ${AM_CFLAGS} -g
+endif
+
scalar_CFLAGS = ${AM_CFLAGS} -g
--- /dev/null
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define handle_error(msg) \
+do { \
+perror(msg); \
+exit(EXIT_FAILURE); \
+} while (0)
+
+int
+main(int argc, char *argv[])
+{
+ eventfd_t u;
+ int efd, j;
+ int error;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <num>...\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ efd = eventfd(0, EFD_CLOEXEC);
+ if (efd == -1)
+ handle_error("eventfd");
+
+ switch (fork()) {
+ case 0:
+ for (j = 1; j < argc; j++) {
+ printf("Child writing %s to efd\n", argv[j]);
+ u = strtoull(argv[j], NULL, 0);
+
+ error = eventfd_write(efd, u);
+ if (error != 0)
+ handle_error("write");
+ }
+ printf("Child completed write loop\n");
+
+ exit(EXIT_SUCCESS);
+
+ default:
+ sleep(2);
+
+ printf("Parent about to read\n");
+ error = eventfd_read(efd, &u);
+ if (error != 0)
+ handle_error("read");
+ printf("Parent read %llu (0x%llx) from efd\n",
+ (unsigned long long) u, (unsigned long long) u);
+ exit(EXIT_SUCCESS);
+
+ case -1:
+
+ handle_error("fork");
+
+ }
+}
--- /dev/null
+Child writing 2 to efd
+Child completed write loop
+Parent about to read
+Parent read 2 (0x2) from efd
--- /dev/null
+prereq: test -e ./eventfd1
+prog: eventfd1
+args: 2
+vgopts: -q
+
--- /dev/null
+/* EFD_SEMAPHORE */
+
+#include <sys/eventfd.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void xsem_wait(int fd)
+{
+ eventfd_t cntr;
+
+ if (eventfd_read(fd, &cntr) != 0) {
+ perror("reading eventfd");
+ exit(1);
+ }
+
+ fprintf(stdout, "wait completed on %d: count=%" PRIu64 "\n",
+ fd, cntr);
+}
+
+static void xsem_post(int fd, int count)
+{
+ eventfd_t cntr = count;
+
+ if (eventfd_write(fd, cntr) != 0) {
+ perror("writing eventfd");
+ exit(1);
+ }
+}
+
+static void sem_player(int fd1, int fd2)
+{
+ /* these printfs did contain the pid
+ * so "[%u] ... ", getpid()
+ * not good for regresson tests
+ * (also xsem_wait above)
+ */
+ fprintf(stdout, "posting 1 on %d\n", fd1);
+ xsem_post(fd1, 1);
+
+ fprintf(stdout, "waiting on %d\n", fd2);
+ xsem_wait(fd2);
+
+ fprintf(stdout, "posting 1 on %d\n", fd1);
+ xsem_post(fd1, 1);
+
+ fprintf(stdout, "waiting on %d\n", fd2);
+ xsem_wait(fd2);
+
+ fprintf(stdout, "posting 5 on %d\n", fd1);
+ xsem_post(fd1, 5);
+
+ fprintf(stdout, "waiting 5 times on %d\n", fd2);
+ xsem_wait(fd2);
+ xsem_wait(fd2);
+ xsem_wait(fd2);
+ xsem_wait(fd2);
+ xsem_wait(fd2);
+}
+
+static void usage(char const *prg)
+{
+ fprintf(stderr, "use: %s [-h]\n", prg);
+}
+
+int main(int argc, char **argv)
+{
+ int c, fd1, fd2, status;
+ pid_t cpid_poster, cpid_waiter;
+
+ while ((c = getopt(argc, argv, "h")) != -1) {
+
+ switch (c) {
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if ((fd1 = eventfd(0, EFD_SEMAPHORE)) == -1 ||
+ (fd2 = eventfd(0, EFD_SEMAPHORE)) == -1) {
+ perror("eventfd");
+ return 1;
+ }
+ if ((cpid_poster = fork()) == 0) {
+ sem_player(fd1, fd2);
+ exit(0);
+ }
+ if ((cpid_waiter = fork()) == 0) {
+ sem_player(fd2, fd1);
+ exit(0);
+ }
+ waitpid(cpid_poster, &status, 0);
+ waitpid(cpid_waiter, &status, 0);
+
+ exit(0);
+}
--- /dev/null
+posting 1 on 3
+waiting on 4
+wait completed on 4: count=1
+posting 1 on 3
+waiting on 4
+wait completed on 4: count=1
+posting 5 on 3
+waiting 5 times on 4
+wait completed on 4: count=1
+wait completed on 4: count=1
+wait completed on 4: count=1
+wait completed on 4: count=1
+wait completed on 4: count=1
+posting 1 on 4
+waiting on 3
+wait completed on 3: count=1
+posting 1 on 4
+waiting on 3
+wait completed on 3: count=1
+posting 5 on 4
+waiting 5 times on 3
+wait completed on 3: count=1
+wait completed on 3: count=1
+wait completed on 3: count=1
+wait completed on 3: count=1
+wait completed on 3: count=1
--- /dev/null
+prog: eventfd2
+prereq: test -e ./eventfd2
+vgopts: -q
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+
+int main(void)
+{
+ // good
+ char buf[PATH_MAX];
+ char* self_path = "../../tests/freebsd/realpath.c";
+ realpath(self_path, buf);
+
+ // bad
+ int * bad_int1 = malloc(sizeof(char));
+ int * bad_int2 = malloc(sizeof(char));
+ *bad_int1 = AT_FDCWD;
+ *bad_int2 = 0;
+ syscall(SYS___realpathat, *bad_int1, self_path, buf, *bad_int2);
+ free(bad_int1);
+ free(bad_int2);
+
+ // ugly
+ char * bad_buf = malloc(100);
+ char* bad_buf2 = strdup(self_path);
+ free(bad_buf);
+ free(bad_buf2);
+ // fingers crossed
+ realpath(bad_buf2, bad_buf);
+
+
+}
--- /dev/null
+Invalid write of size 4
+ at 0x........: main (realpathat.c:18)
+ Address 0x........ is 0 bytes inside a block of size 1 alloc'd
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:16)
+
+Invalid write of size 4
+ at 0x........: main (realpathat.c:19)
+ Address 0x........ is 0 bytes inside a block of size 1 alloc'd
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:17)
+
+Syscall param __realpathat(fd) contains uninitialised byte(s)
+ ...
+ by 0x........: main (realpathat.c:20)
+
+Syscall param __realpathat(size) contains uninitialised byte(s)
+ ...
+ by 0x........: main (realpathat.c:20)
+
+Invalid read of size 1
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Syscall param __realpathat(path) points to unaddressable byte(s)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Syscall param __realpathat(buf) points to unaddressable byte(s)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Invalid read of size 1
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Syscall param __getcwd(buf) points to unaddressable byte(s)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Invalid read of size 1
+ at 0x........: strlcpy (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 0 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Invalid read of size 1
+ at 0x........: strlcpy (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 1 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Invalid read of size 1
+ at 0x........: strlcpy (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 30 bytes inside a block of size 31 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:28)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ ...
+ by 0x........: main (realpathat.c:26)
+
+Invalid write of size 2
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 55 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Invalid read of size 1
+ at 0x........: strlcat (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 56 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Invalid write of size 1
+ at 0x........: strlcat (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 56 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Invalid write of size 1
+ at 0x........: strlcat (vg_replace_strmem.c:...)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 66 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
+Syscall param fstatat(path) points to unaddressable byte(s)
+ ...
+ by 0x........: main (realpathat.c:30)
+ Address 0x........ is 56 bytes inside a block of size 100 free'd
+ at 0x........: free (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:27)
+ Block was alloc'd at
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (realpathat.c:25)
+
--- /dev/null
+prog: realpathat
+prereq: test -e ./realpathat
+vgopts: -q
GO(SYS___sysctlbyname, "(putnew) 4s 2m");
SY(SYS___sysctlbyname, x0, x0+1, NULL, NULL, x0+1, x0+2); FAIL;
+
+ GO(SYS___realpathat, " 5s 2m");
+ SY(SYS___realpathat, x0+0xffff, x0, x0, x0+100, x0+2); FAIL;
#endif
...
Address 0x........ is not stack'd, malloc'd or (recently) free'd
+---------------------------------------------------------
+574: SYS___realpathat 5s 2m
+---------------------------------------------------------
+Syscall param __realpathat(fd) contains uninitialised byte(s)
+ ...
+
+Syscall param __realpathat(path) contains uninitialised byte(s)
+ ...
+
+Syscall param __realpathat(buf) contains uninitialised byte(s)
+ ...
+
+Syscall param __realpathat(size) contains uninitialised byte(s)
+ ...
+
+Syscall param __realpathat(flags) contains uninitialised byte(s)
+ ...
+
+Syscall param __realpathat(path) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param __realpathat(buf) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
---------------------------------------------------------
1: SYS_exit 1s 0m
---------------------------------------------------------
--- /dev/null
+#include "scalar.h"
+
+int main(void)
+{
+ long *px = malloc(2*sizeof(long));
+ x0 = px[0];
+
+
+ /* SYS___specialfd 574 */
+ GO(SYS___specialfd, "3s 1m");
+ SY(SYS___specialfd, x0+0xf000, x0+1, x0+10); FAIL;
+
+ return(0);
+}
+
--- /dev/null
+---------------------------------------------------------
+577: SYS___specialfd 3s 1m
+---------------------------------------------------------
+Syscall param __specialfd(type) contains uninitialised byte(s)
+ ...
+
+Syscall param __specialfd(req) contains uninitialised byte(s)
+ ...
+
+Syscall param __specialfd(len) contains uninitialised byte(s)
+ ...
+
+Syscall param __specialfd(req) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
--- /dev/null
+prereq: test -e ./scalar_13_plus
+prog: scalar_13_plus
+vgopts: -q --error-limit=no
+stderr_filter: filter_scalar
+# Remove all frames from the stack trace except the first one.
+# This is important because syscall() function on x86 isn't ABI conformant
+# which confuses the Valgrind stack unwinder.
+# Therefore x86 and amd64 stack traces are unified so that they contain only
+# 'syscall (in libc)' stack frame and this is then filtered out completely.
+stderr_filter_args: libc
+args: < scalar_13_plus.c
+