]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Bug 476887 - WARNING: unhandled amd64-freebsd syscall: 578
authorPaul Floyd <pjfloyd@wanadoo.fr>
Thu, 16 Nov 2023 20:33:33 +0000 (21:33 +0100)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Thu, 16 Nov 2023 20:47:29 +0000 (21:47 +0100)
Adds syscall wrappers for aio_readv and aio_writev
Also rewrote the wrappers for aio_read, aio_write and aio_return
as they weren't correctly checking the async memory.

The code is similar th that of Darwin with one exception.
Darwin uses a global variable to communicate between the
pre- and post- aio_return wrappers. I don't think that is
safe when there are multiple aio reads in flight. Instead
I put everything in the pre- aio_return wrapper.

23 files changed:
.gitignore
NEWS
coregrind/m_syswrap/priv_syswrap-freebsd.h
coregrind/m_syswrap/syswrap-darwin.c
coregrind/m_syswrap/syswrap-freebsd.c
coregrind/vg_preloaded.c
memcheck/tests/freebsd/Makefile.am
memcheck/tests/freebsd/aio.c [new file with mode: 0644]
memcheck/tests/freebsd/aio.stderr.exp [new file with mode: 0644]
memcheck/tests/freebsd/aio.vgtest [new file with mode: 0644]
memcheck/tests/freebsd/aio_read.c [new file with mode: 0644]
memcheck/tests/freebsd/aio_read.in [new file with mode: 0644]
memcheck/tests/freebsd/aio_read.stderr.exp [new file with mode: 0644]
memcheck/tests/freebsd/aio_read.stdout.exp [new file with mode: 0644]
memcheck/tests/freebsd/aio_read.vgtest [new file with mode: 0644]
memcheck/tests/freebsd/aiov.c [new file with mode: 0644]
memcheck/tests/freebsd/aiov.stderr.exp [new file with mode: 0644]
memcheck/tests/freebsd/aiov.vgtest [new file with mode: 0644]
memcheck/tests/freebsd/scalar.c
memcheck/tests/freebsd/scalar.stderr.exp
memcheck/tests/freebsd/scalar.stderr.exp-x86
memcheck/tests/freebsd/scalar_13_plus.c
memcheck/tests/freebsd/scalar_13_plus.stderr.exp

index 369d49404c3e1c3a455926194e8dbedc7284124b..7ccf1c2dec78c5bc49aaf3f1f8291a0e83192761 100644 (file)
 /memcheck/tests/freebsd/Makefile.in
 /memcheck/tests/freebsd/452275
 /memcheck/tests/freebsd/access
+/memcheck/tests/freebsd/aio
+/memcheck/tests/freebsd/aiov
+/memcheck/tests/freebsd/aio_read
 /memcheck/tests/freebsd/aligned_alloc
 /memcheck/tests/freebsd/bug464476
 /memcheck/tests/freebsd/bug470713
diff --git a/NEWS b/NEWS
index 6736f58b2a53755cd3825f72f5aa941e73704dd7..98c2ecf1370d8ab02cd26720fb9b26ab37c4ac5f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 476780  Extend strlcat and strlcpy wrappers to GNU libc
 476787  Build of Valgrind 3.21.0 fails when SOLARIS_PT_SUNDWTRACE_THRP is
         defined
+476887  WARNING: unhandled amd64-freebsd syscall: 578
 
 To see details of a given bug, visit
   https://bugs.kde.org/show_bug.cgi?id=XXXXXX
index 5dcdc376a3a5670e2b3aa5f609527796c0a9a3db..30b90ca37fe733d3d9fb9ef94ea644c5102c232a 100644 (file)
@@ -549,8 +549,8 @@ DECL_TEMPLATE(freebsd, sys_close_range)  // 575
 
 // unimpl __NR_rpctls_syscall      576
 DECL_TEMPLATE(freebsd, sys___specialfd) // 577
-// unimpl __NR_aio_writev          578
-// unimpl __NR_aio_readv           579
+DECL_TEMPLATE(freebsd, sys_aio_writev)  // 578
+DECL_TEMPLATE(freebsd, sys_aio_readv)   // 579
 
 #endif
 
index c5c9b603b6f56732c55fdcd517b0adc417303da4..3b8ceda3e25270b544b1805f6743be8dede1d28d 100644 (file)
@@ -4613,12 +4613,14 @@ PRE(aio_suspend)
    // but not the contents of the structs.
    PRINT( "aio_suspend ( %#lx )", ARG1 );
    PRE_REG_READ3(long, "aio_suspend",
-                 const struct vki_aiocb *, aiocbp, int, nent,
+                 const struct vki_aiocb * const *, aiocbp, int, nent,
                  const struct vki_timespec *, timeout);
-   if (ARG2 > 0)
+   if (ARG2 > 0) {
       PRE_MEM_READ("aio_suspend(list)", ARG1, ARG2 * sizeof(struct vki_aiocb *));
-   if (ARG3)
+   }
+   if (ARG3) {
       PRE_MEM_READ ("aio_suspend(timeout)", ARG3, sizeof(struct vki_timespec));
+   }
 }
 
 PRE(aio_error)
index ce50566698cbe6f33c58d1427f2d9939ae197f2f..dab12a6eaceaa7fcbcffd33048cc6ab3f1a6cd9e 100644 (file)
@@ -56,6 +56,7 @@
 #include "pub_core_syswrap.h"
 #include "pub_core_inner.h"
 #include "pub_core_pathscan.h"
+#include "pub_core_oset.h"
 #if defined(ENABLE_INNER_CLIENT_REQUEST)
 #include "pub_core_clreq.h"
 #endif
@@ -2613,6 +2614,30 @@ PRE(sys_issetugid)
 // SYS_lchown  254
 // generic
 
+// We must record the iocb for each aio_read() in a table so that when
+// aio_return() is called we can mark the memory written asynchronously by
+// aio_read() as having been written.  We don't have to do this for
+// aio_write().  See bug 197227 for more details.
+static OSet* iocb_table = NULL;
+static Bool aio_init_done = False;
+
+static void aio_init(void)
+{
+   iocb_table = VG_(OSetWord_Create)(VG_(malloc), "syswrap.aio", VG_(free));
+   aio_init_done = True;
+}
+
+// and the same thing for vector reads
+static OSet* iocbv_table = NULL;
+static Bool aiov_init_done = False;
+
+static void aiov_init(void)
+{
+   iocbv_table = VG_(OSetWord_Create)(VG_(malloc), "syswrap.aiov", VG_(free));
+   aiov_init_done = True;
+}
+
+
 // SYS_aio_read   255
 // int aio_read(struct aiocb *iocb);
 PRE(sys_aio_read)
@@ -2622,15 +2647,36 @@ PRE(sys_aio_read)
    PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb));
    if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
       struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
-      PRE_MEM_WRITE( "aio_read(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
+      if (!ML_(fd_allowed)(iocb->aio_fildes, "aio_read", tid, False)) {
+         SET_STATUS_Failure(VKI_EBADF);
+      } else {
+         PRE_MEM_WRITE("aio_read(aiocbp->aio_buf)",
+                       (Addr)iocb->aio_buf, iocb->aio_nbytes);
+         // @todo PJF there is a difference between FreeBSD and
+         // Darwin here. On Darwin, if aio_buf is NULL the syscall
+         // will fail, on FreeBSD it doesn't fail.
+      }
+   } else {
+      SET_STATUS_Failure(VKI_EINVAL);
    }
 }
 
 POST(sys_aio_read)
 {
-   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
-      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
-      POST_MEM_WRITE((Addr)iocb, sizeof(struct vki_aiocb));
+   struct vki_aiocb* iocb = (struct vki_aiocb*)ARG1;
+
+   if (iocb->aio_buf) {
+      if (!aio_init_done) {
+         aio_init();
+      }
+      // see also POST(sys_aio_readv)
+      if (!VG_(OSetWord_Contains)(iocb_table, (UWord)iocb)) {
+         VG_(OSetWord_Insert)(iocb_table, (UWord)iocb);
+      } else {
+         VG_(dmsg)("Warning: Duplicate control block %p in aio_read\n",
+                   (void *)(Addr)ARG1);
+         VG_(dmsg)("Warning: Ensure 'aio_return' is called when 'aio_read' has completed\n");
+      }
    }
 }
 
@@ -2640,18 +2686,20 @@ PRE(sys_aio_write)
 {
    PRINT("sys_aio_write ( %#" FMT_REGWORD "x )", ARG1);
    PRE_REG_READ1(int, "aio_write", struct vki_aiocb *, iocb);
-   PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb));
+   PRE_MEM_READ("aio_write(iocb)", ARG1, sizeof(struct vki_aiocb));
    if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
       struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
-      PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
-   }
-}
-
-POST(sys_aio_write)
-{
-   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
-      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
-      PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
+      if (!ML_(fd_allowed)(iocb->aio_fildes, "aio_write", tid, False)) {
+         SET_STATUS_Failure( VKI_EBADF );
+      } else {
+         PRE_MEM_READ("aio_write(iocb->aio_buf)",
+                      (Addr)iocb->aio_buf, iocb->aio_nbytes);
+         // @todo PJF there is a difference between FreeBSD and
+         // Darwin here. On Darwin, if aio_buf is NULL the syscall
+         // will fail, on FreeBSD it doesn't fail.
+      }
+   } else {
+      SET_STATUS_Failure(VKI_EINVAL);
    }
 }
 
@@ -2905,9 +2953,34 @@ PRE(sys_aio_return)
 {
    PRINT("sys_aio_return ( %#" FMT_REGWORD "x )", ARG1);
    PRE_REG_READ1(ssize_t, "aio_return", struct aiocb *, iocb);
-   // not too clear if this is read-only, sounds like it from the man page
-   // but it isn't const
    PRE_MEM_READ("aio_return(iocb)", ARG1, sizeof(struct vki_aiocb));
+   // read or write?
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      SET_STATUS_from_SysRes(VG_(do_syscall1)(SYSNO, ARG1));
+      if (SUCCESS && RES >= 0) {
+         struct vki_aiocb* iocb = (struct vki_aiocb*)ARG1;
+         if (!aio_init_done) {
+            aio_init();
+         }
+         if (!aiov_init_done) {
+            aiov_init();
+         }
+         // check if it was a plain read
+         if (VG_(OSetWord_Remove)(iocb_table, (UWord)iocb)) {
+            POST_MEM_WRITE((Addr)iocb->aio_buf, iocb->aio_nbytes);
+         }
+         if (VG_(OSetWord_Remove)(iocbv_table, (UWord)iocb)) {
+            SizeT vec_count = (SizeT)iocb->aio_nbytes;
+            // assume that id the read succeded p_iovec is accessible
+            volatile struct vki_iovec* p_iovec  = (volatile struct vki_iovec*)iocb->aio_buf;
+            for (SizeT i = 0U; i < vec_count; ++i) {
+               POST_MEM_WRITE((Addr)p_iovec[i].iov_base, p_iovec[i].iov_len);
+            }
+         }
+      }
+   } else {
+      SET_STATUS_Failure(VKI_EINVAL);
+   }
 }
 
 // SYS_aio_suspend   315
@@ -2916,9 +2989,13 @@ PRE(sys_aio_return)
 PRE(sys_aio_suspend)
 {
    PRINT("sys_aio_suspend ( %#" FMT_REGWORD "x )", ARG1);
-   PRE_REG_READ3(int, "aio_suspend", struct aiocb **, iocbs, int, nbiocb, const struct timespec*, timeout);
-   PRE_MEM_READ("aio_suspend(iocbs)", ARG1, ARG2*sizeof(struct vki_aiocb));
-   PRE_MEM_READ("aio_suspend(timeout)", ARG3, sizeof(struct vki_timespec));
+   PRE_REG_READ3(int, "aio_suspend", const struct aiocb * const *, iocbs, int, nbiocb, const struct timespec*, timeout);
+   if (ARG2 > 0) {
+      PRE_MEM_READ("aio_suspend(iocbs)", ARG1, ARG2*sizeof(struct vki_aiocb*));
+   }
+   if (ARG3) {
+      PRE_MEM_READ("aio_suspend(timeout)", ARG3, sizeof(struct vki_timespec));
+   }
 }
 
 // SYS_aio_cancel 316
@@ -2926,10 +3003,25 @@ PRE(sys_aio_suspend)
 PRE(sys_aio_cancel)
 {
    PRINT("sys_aio_cancel ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
-   PRE_REG_READ2(int, "aio_cancel", int, fildex, struct aiocb *, iocb);
+   PRE_REG_READ2(int, "aio_cancel", int, fildes, struct iocb *, iocb);
    if (ARG2) {
       PRE_MEM_READ("aio_cancel(iocb)", ARG2, sizeof(struct vki_aiocb));
    }
+   if (!ML_(fd_allowed)(ARG1, "aio_cancel", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   } else {
+      if (ARG2) {
+         if (ML_(safe_to_deref)((struct vki_aiocb *)ARG2, sizeof(struct vki_aiocb))) {
+            struct vki_aiocb *iocb = (struct vki_aiocb *)ARG2;
+            // @todo PJF cancel only requests associated with
+            // fildes and iocb
+         } else {
+            SET_STATUS_Failure(VKI_EINVAL);
+         }
+      } else {
+         // @todo PJF cancel all requests associated with fildes
+      }
+   }
 }
 
 // SYS_aio_error  317
@@ -6775,6 +6867,84 @@ PRE(sys___specialfd)
    PRE_MEM_READ("__specialfd(req)", (Addr)ARG2, ARG3);
 }
 
+// SYS_aio_writev 578
+// int aio_writev(struct aiocb *iocb);
+PRE(sys_aio_writev)
+{
+   PRINT("sys_aio_writev ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "aio_writev", struct vki_aiocb *, iocb);
+   PRE_MEM_READ("aio_writev(iocb)", ARG1, sizeof(struct vki_aiocb));
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      if (!ML_(fd_allowed)(iocb->aio_fildes, "aio_writev", tid, False)) {
+         SET_STATUS_Failure( VKI_EBADF );
+      } else {
+         // aio_writev() gathers the data from the iocb->aio_iovcnt buffers specified
+         // by the members of the iocb->aio_iov array
+         // FreeBSD headers #define define this to aio_iovcnt
+         SizeT vec_count = (SizeT)iocb->aio_nbytes;
+         struct vki_iovec* p_iovec  = (struct vki_iovec*)iocb->aio_buf;
+         PRE_MEM_READ("aio_writev(iocb->aio_iov)", (Addr)p_iovec, vec_count*sizeof(struct vki_iovec));
+         // and this to aio_iov
+
+         if (ML_(safe_to_deref)(p_iovec, vec_count*sizeof(struct vki_iovec))) {
+            for (SizeT i = 0U; i < vec_count; ++i) {
+               PRE_MEM_READ("aio_writev(iocb->iov[...])",
+                            (Addr)p_iovec[i].iov_base, p_iovec[i].iov_len);
+            }
+         }
+      }
+   } else {
+      SET_STATUS_Failure(VKI_EINVAL);
+   }
+}
+
+// SYS_aio_readv 579
+// int aio_readv(struct aiocb *iocb);
+PRE(sys_aio_readv)
+{
+   PRINT("sys_aio_readv ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "aio_readv", struct vki_aiocb *, iocb);
+   PRE_MEM_READ("aio_readv(iocb)", ARG1, sizeof(struct vki_aiocb));
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      if (!ML_(fd_allowed)(iocb->aio_fildes, "aio_readv", tid, False)) {
+         SET_STATUS_Failure( VKI_EBADF );
+      } else {
+         SizeT vec_count = (SizeT)iocb->aio_nbytes;
+         struct vki_iovec* p_iovec  = (struct vki_iovec*)iocb->aio_buf;
+         PRE_MEM_READ("aio_readv(iocb->aio_iov)", (Addr)p_iovec,  vec_count*sizeof(struct vki_iovec));
+         // @todo PJF check that p_iovec is accessible
+         if (ML_(safe_to_deref)(p_iovec, vec_count*sizeof(struct vki_iovec*))) {
+            for (SizeT i = 0U; i < vec_count; ++i) {
+               PRE_MEM_WRITE("aio_writev(iocb->aio_iov[...])",
+                            (Addr)p_iovec[i].iov_base, p_iovec[i].iov_len);
+            }
+         }
+      }
+   } else {
+      SET_STATUS_Failure(VKI_EINVAL);
+   }
+}
+
+POST(sys_aio_readv)
+{
+   struct vki_aiocb* iocbv = (struct vki_aiocb*)ARG1;
+   if (iocbv->aio_buf) {
+      if (!aiov_init_done) {
+         aiov_init();
+      }
+
+      if (!VG_(OSetWord_Contains)(iocbv_table, (UWord)iocbv)) {
+         VG_(OSetWord_Insert)(iocbv_table, (UWord)iocbv);
+      } else {
+         VG_(dmsg)("Warning: Duplicate control block %p in aio_readv\n",
+                   (void *)(Addr)ARG1);
+         VG_(dmsg)("Warning: Ensure 'aio_return' is called when 'aio_readv' has completed\n");
+      }
+   }
+}
+
 #endif // (FREEBSD_VERS >= FREEBSD_13_0)
 
 #if (FREEBSD_VERS >= FREEBSD_13_1)
@@ -7223,7 +7393,7 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    BSDX_(__NR_issetugid,        sys_issetugid),         // 253
    GENX_(__NR_lchown,           sys_lchown),            // 254
    BSDXY(__NR_aio_read,         sys_aio_read),          // 255
-   BSDXY(__NR_aio_write,        sys_aio_write),         // 256
+   BSDX_(__NR_aio_write,        sys_aio_write),         // 256
    BSDX_(__NR_lio_listio,       sys_lio_listio),        // 257
 
    GENXY(__NR_freebsd11_getdents, sys_getdents),        // 272
@@ -7606,8 +7776,8 @@ const SyscallTableEntry ML_(syscall_table)[] = {
 #if (FREEBSD_VERS >= FREEBSD_13_0)
    // unimpl __NR_rpctls_syscall      576
    BSDX_(__NR___specialfd,      sys___specialfd),       // 577
-   // unimpl __NR_aio_writev          578
-   // unimpl __NR_aio_readv           579
+   BSDX_(__NR_aio_writev,       sys_aio_writev),        // 578
+   BSDXY(__NR_aio_readv,        sys_aio_readv),         // 579
 #endif
 
 #if (FREEBSD_VERS >= FREEBSD_13_1)
index 1c727966f3a2c8085e61f9475086dc16b4b1a9dd..7986eeec5275cb2e0aa2407f0f2bc6d42cda475c 100644 (file)
@@ -238,7 +238,7 @@ void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned
 
 #elif defined(VGO_freebsd)
 
-#if (FREEBSD_VERS >= FREEBSD_14)
+#if (FREEBSD_VERS >= FREEBSD_13)
 
 void * VG_NOTIFY_ON_LOAD(ifunc_wrapper) (void);
 void * VG_NOTIFY_ON_LOAD(ifunc_wrapper) (void)
index fb1149f98b44302d9c816bc56b1274e51352c47b..466799cefdcce45395acd247ca83b22edf84bb4f 100644 (file)
@@ -8,6 +8,10 @@ dist_noinst_SCRIPTS = filter_stderr filter_pts dump_stdout filter_sigwait \
 EXTRA_DIST = \
        access.vgtest \
        access.stderr.exp \
+       aio.vgtest aio.stderr.exp \
+       aiov.vgtest aiov.stderr.exp \
+       aio_read.vgtest aio_read.stderr.exp aio_read.stdout.exp \
+       aio_read.in \
        aligned_alloc.vgtest aligned_alloc.stderr.exp \
        aligned_alloc_xml.vgtest aligned_alloc_xml.stderr.exp \
        aligned_allocs_supp.vgtest \
@@ -132,8 +136,8 @@ EXTRA_DIST = \
        utimes.stderr.exp
 
 check_PROGRAMS = \
-       access aligned_alloc bug464476 bug470713 capsicum \
-       chflags \
+       access aio aiov aio_read aligned_alloc bug464476 bug470713 \
+       capsicum chflags \
        chmod_chown delete_sized_mismatch errno_aligned_allocs \
        extattr \
        fexecve \
diff --git a/memcheck/tests/freebsd/aio.c b/memcheck/tests/freebsd/aio.c
new file mode 100644 (file)
index 0000000..999eecb
--- /dev/null
@@ -0,0 +1,98 @@
+#include <assert.h>
+#include <aio.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+int x;
+
+int main(void)
+{
+   #define LEN 10
+   char buf[LEN];
+
+   struct aiocb a;
+   struct sigevent s;
+
+   memset(&a, 0, sizeof(struct aiocb));
+   // Not sure if the sigevent is even looked at by aio_*... just zero it.
+   memset(&s, 0, sizeof(struct sigevent));
+
+   a.aio_fildes     = -1;
+   a.aio_offset     = 0;
+   a.aio_buf        = NULL;
+   a.aio_nbytes     = LEN;
+   a.aio_reqprio    = 0;
+   //a.aio_sigevent   = s;
+   a.aio_lio_opcode = 0;   // ignored
+
+   //------------------------------------------------------------------------
+   // The cases where aiocbp itself points to bogus memory is handled in
+   // memcheck/tests/darwin/scalar.c, so we don't check that here.
+
+   //------------------------------------------------------------------------
+   // XXX: This causes an unexpected undef value error later, at the XXX mark.
+   //      Not sure why, it shouldn't.
+   // assert( aio_return(&a) < 0);  // (iocb hasn't been inited)
+
+   //------------------------------------------------------------------------
+   assert( aio_read(&a) < 0);       // invalid fd
+
+   //------------------------------------------------------------------------
+   a.aio_fildes = open("aio.c", O_RDONLY);
+   assert(a.aio_fildes >= 0);
+
+   // unaddressable aio_buf
+   assert(aio_read(&a) == 0);
+   assert(aio_return(&a) == -1);
+
+   //------------------------------------------------------------------------
+   a.aio_buf = buf;
+
+   assert( aio_read(&a) == 0 );
+   
+   // undefined -- aio_return() not called yet
+   if (buf[0] == buf[9]) x++;       
+
+   // also failed on macOS
+   // (don't crash on the repeated &a)
+   assert( aio_read(&a) == 0 );
+
+   while (0 != aio_error(&a)) { }
+
+   assert( aio_return(&a) > 0 );    // XXX: (undefined value error here)
+
+   if (buf[0] == buf[9]) x++;
+
+   assert( aio_return(&a) > 0 );    // (repeated aio_return();  fails because 
+                                    // Valgrind can't find &a in the table)
+
+   //------------------------------------------------------------------------
+   a.aio_buf    = 0;
+   a.aio_fildes = creat("mytmpfile", S_IRUSR|S_IWUSR);
+   assert(a.aio_fildes >= 0);
+
+   // unaddressable aio_buf
+   assert( aio_write(&a) == 0);
+   assert(aio_return(&a) == -1);
+
+   //------------------------------------------------------------------------
+   a.aio_buf = buf;
+
+   assert( aio_write(&a) == 0 );
+
+   // (don't crash on the repeated &a)
+   assert( aio_write(&a)  == 0 );
+
+   while (0 != aio_error(&a)) { }
+
+   assert( aio_return(&a) > 0 );
+
+   assert( aio_return(&a) > 0 );    // (repeated aio_return();  fails because 
+                                    // Valgrind can't find &a in the table)
+
+   unlink("mytmpfile");
+
+   return x;
+}
diff --git a/memcheck/tests/freebsd/aio.stderr.exp b/memcheck/tests/freebsd/aio.stderr.exp
new file mode 100644 (file)
index 0000000..b40b054
--- /dev/null
@@ -0,0 +1,31 @@
+
+Warning: invalid file descriptor -1 in syscall aio_read()
+Syscall param aio_read(aiocbp->aio_buf) points to unaddressable byte(s)
+   at 0x........: aio_read (in /...libc...)
+   by 0x........: main (aio.c:47)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (aio.c:56)
+
+Warning: Duplicate control block 0x........ in aio_read
+Warning: Ensure 'aio_return' is called when 'aio_read' has completed
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: aio_read (in /...libc...)
+   by 0x........: main (aio.c:60)
+
+Syscall param aio_write(iocb->aio_buf) points to unaddressable byte(s)
+   at 0x........: aio_write (in /...libc...)
+   by 0x........: main (aio.c:77)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+
+HEAP SUMMARY:
+    in use at exit: ... bytes in ... blocks
+  total heap usage: ... allocs, ... frees, ... bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+Use --track-origins=yes to see where uninitialised values come from
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/freebsd/aio.vgtest b/memcheck/tests/freebsd/aio.vgtest
new file mode 100644 (file)
index 0000000..020a3ad
--- /dev/null
@@ -0,0 +1,3 @@
+prog: aio
+vgopts: --leak-check=no
+stderr_filter: ../filter_allocs
diff --git a/memcheck/tests/freebsd/aio_read.c b/memcheck/tests/freebsd/aio_read.c
new file mode 100644 (file)
index 0000000..b7e2915
--- /dev/null
@@ -0,0 +1,47 @@
+// my_aio_read.c
+// from https://github.com/imyjf/apue/blob/master/my_aio_read.c
+// and I guess originally from APUE but it isn't in my second
+// edition (and I didn't keep the first edition)
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <aio.h>
+#include <strings.h>
+#include <errno.h>
+
+#define ERR_EXIT(msg) do { perror(msg); exit(1); } while(0)
+
+int main() {
+  int fd, ret;
+  char buf[64];
+  struct aiocb my_aiocb;
+
+  bzero((char*)&my_aiocb, sizeof(struct aiocb));
+
+  my_aiocb.aio_buf = buf;
+  my_aiocb.aio_fildes = STDIN_FILENO;
+  my_aiocb.aio_nbytes = 64;
+  my_aiocb.aio_offset = 0;
+
+  ret = aio_read(&my_aiocb);
+  if (ret < 0) {
+     ERR_EXIT("aio_read");
+  }
+
+  while (aio_error(&my_aiocb) == EINPROGRESS) {
+    //write(STDOUT_FILENO, ".", 1); 
+    sleep(1);
+  }
+
+  ret = aio_return(&my_aiocb); 
+  if (ret < 0) {
+     ERR_EXIT("aio_return");
+  }
+
+  printf("content: %s\n", buf);
+
+  return 0;
+}
diff --git a/memcheck/tests/freebsd/aio_read.in b/memcheck/tests/freebsd/aio_read.in
new file mode 100644 (file)
index 0000000..8ab686e
--- /dev/null
@@ -0,0 +1 @@
+Hello, World!
diff --git a/memcheck/tests/freebsd/aio_read.stderr.exp b/memcheck/tests/freebsd/aio_read.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/memcheck/tests/freebsd/aio_read.stdout.exp b/memcheck/tests/freebsd/aio_read.stdout.exp
new file mode 100644 (file)
index 0000000..5fe0fa5
--- /dev/null
@@ -0,0 +1,2 @@
+content: Hello, World!
+
diff --git a/memcheck/tests/freebsd/aio_read.vgtest b/memcheck/tests/freebsd/aio_read.vgtest
new file mode 100644 (file)
index 0000000..3cbae38
--- /dev/null
@@ -0,0 +1,3 @@
+prog: aio_read
+args: < aio_read.in
+vgopts: -q
diff --git a/memcheck/tests/freebsd/aiov.c b/memcheck/tests/freebsd/aiov.c
new file mode 100644 (file)
index 0000000..12d434c
--- /dev/null
@@ -0,0 +1,102 @@
+#include <assert.h>
+#include <aio.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+int x;
+
+int main(void)
+{
+   #define LEN 10
+   char buf1[LEN];
+   char buf2[LEN];
+   char buf3[LEN];
+   struct iovec vec_array[] = {{buf1, LEN}, {buf2, LEN}, {buf3, LEN}};
+   struct iovec bad_array[] = {{NULL, LEN}, {buf2, LEN}, {buf3, LEN}};
+
+   struct aiocb a;
+
+   memset(&a, 0, sizeof(struct aiocb));
+
+   a.aio_fildes     = -1;
+   a.aio_offset     = 0;
+   a.aio_iov        = NULL;
+   a.aio_iovcnt     = 3;
+   a.aio_reqprio    = 0;
+   a.aio_lio_opcode = 0;   // ignored
+
+   //------------------------------------------------------------------------
+   // The cases where aiocbp itself points to bogus memory is handled in
+   // memcheck/tests/darwin/scalar.c, so we don't check that here.
+
+   //------------------------------------------------------------------------
+   // XXX: This causes an unexpected undef value error later, at the XXX mark.
+   //      Not sure why, it shouldn't.
+   // assert( aio_return(&a) < 0);  // (iocb hasn't been inited)
+
+   //------------------------------------------------------------------------
+   assert( aio_readv(&a) < 0);       // invalid fd
+
+   //------------------------------------------------------------------------
+   a.aio_fildes = open("aio.c", O_RDONLY);
+   assert(a.aio_fildes >= 0);
+
+   // unaddressable aio_iov
+   assert( aio_readv(&a) < 0);
+
+   //------------------------------------------------------------------------
+   //a.aio_iov = bad_array;
+   // unaddressable first element in aio_iov
+   // but it doesn't fail!
+   //assert( aio_readv(&a) < 0 );
+   
+   a.aio_iov = vec_array;
+   assert( aio_readv(&a) == 0 );
+
+   // undefined -- aio_return() not called yet
+   if (((char*)(vec_array[0].iov_base))[0] == ((char*)(vec_array[0].iov_base))[9]) x++;
+
+   // also failed on macOS
+   // (don't crash on the repeated &a)
+   //assert( aio_readv(&a) == 0 );
+
+   while (0 != aio_error(&a)) { }
+
+   assert( aio_return(&a) > 0 );    // XXX: (undefined value error here)
+
+   if (((char*)(vec_array[0].iov_base))[0] == ((char*)(vec_array[0].iov_base))[9]) x++;
+
+   assert( aio_return(&a) < 0 );    // (repeated aio_return();  fails because 
+                                    // Valgrind can't find &a in the table)
+
+   //------------------------------------------------------------------------
+   a.aio_iov    = 0;
+   a.aio_fildes = creat("mytmpfile", S_IRUSR|S_IWUSR);
+   assert(a.aio_fildes >= 0);
+
+   // unaddressable aio_buf
+   assert( aio_writev(&a) < 0);
+
+   //------------------------------------------------------------------------
+   a.aio_iov = vec_array;
+
+   assert( aio_writev(&a) == 0 );
+
+   // (don't crash on the repeated &a)
+   // this failed on macOS
+   //assert( aio_writev(&a)  < 0 );
+
+   while (0 != aio_error(&a)) { };
+
+   assert( aio_return(&a) > 0 );
+
+   assert( aio_return(&a) < 0 );    // (repeated aio_return();  fails because 
+                                    // Valgrind can't find &a in the table)
+
+   unlink("mytmpfile");
+
+   return x;
+}
diff --git a/memcheck/tests/freebsd/aiov.stderr.exp b/memcheck/tests/freebsd/aiov.stderr.exp
new file mode 100644 (file)
index 0000000..9fd6f9f
--- /dev/null
@@ -0,0 +1,25 @@
+
+Warning: invalid file descriptor -1 in syscall aio_readv()
+Syscall param aio_readv(iocb->aio_iov) points to unaddressable byte(s)
+   ...
+   by 0x........: main (aiov.c:48)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (aiov.c:62)
+
+Syscall param aio_writev(iocb->aio_iov) points to unaddressable byte(s)
+   ...
+   by 0x........: main (aiov.c:83)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+
+HEAP SUMMARY:
+    in use at exit: ... bytes in ... blocks
+  total heap usage: ... allocs, ... frees, ... bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+Use --track-origins=yes to see where uninitialised values come from
+For lists of detected and suppressed errors, rerun with: -s
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/freebsd/aiov.vgtest b/memcheck/tests/freebsd/aiov.vgtest
new file mode 100644 (file)
index 0000000..5f2dabd
--- /dev/null
@@ -0,0 +1,3 @@
+prog: aiov
+vgopts: --leak-check=no
+stderr_filter: ../filter_allocs
index 6c8d81aa6e14a2095ed4cab622c5ce2daf7d419c..5afd0f2946e48613df060870be1c842bcaecae63 100644 (file)
@@ -1056,7 +1056,7 @@ int main(void)
 
    /* SYS_aio_error               317 */
    GO(SYS_aio_error, "1s 1m");
-   SY(SYS_aio_error, x0+1); FAIL;
+   SY(SYS_aio_error, x0+1); SUCC;
 
    /* freebsd 6 aio_read          318 */
 
index 5a4f3230f13b0c19d5a82fa13f72d6dcd06cbebf..38d2380f7861efe41f3ada81e6709c6a89ab0411 100644 (file)
@@ -1958,7 +1958,7 @@ Syscall param aio_read(iocb) points to unaddressable byte(s)
 Syscall param aio_write(iocb) contains uninitialised byte(s)
    ...
 
-Syscall param aio_read(iocb) points to unaddressable byte(s)
+Syscall param aio_write(iocb) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
@@ -2240,7 +2240,7 @@ Syscall param aio_suspend(timeout) points to unaddressable byte(s)
 ---------------------------------------------------------
 316:          SYS_aio_cancel 2s 1m
 ---------------------------------------------------------
-Syscall param aio_cancel(fildex) contains uninitialised byte(s)
+Syscall param aio_cancel(fildes) contains uninitialised byte(s)
    ...
 
 Syscall param aio_cancel(iocb) contains uninitialised byte(s)
index a45d0601c38e90313dc911d252b2944f2e8f8013..cdb0825ca76d56ee7eb64952bfd04a290b48b125 100644 (file)
@@ -1958,7 +1958,7 @@ Syscall param aio_read(iocb) points to unaddressable byte(s)
 Syscall param aio_write(iocb) contains uninitialised byte(s)
    ...
 
-Syscall param aio_read(iocb) points to unaddressable byte(s)
+Syscall param aio_write(iocb) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
@@ -2246,7 +2246,7 @@ Syscall param aio_suspend(timeout) points to unaddressable byte(s)
 ---------------------------------------------------------
 316:          SYS_aio_cancel 2s 1m
 ---------------------------------------------------------
-Syscall param aio_cancel(fildex) contains uninitialised byte(s)
+Syscall param aio_cancel(fildes) contains uninitialised byte(s)
    ...
 
 Syscall param aio_cancel(iocb) contains uninitialised byte(s)
index 6e58e418fb3a1cc6cf6128d27d769fdc26abbff3..799dcfc8b7e43bb3d90674ca483c8dead84aa2da 100644 (file)
@@ -24,6 +24,14 @@ int main(void)
    /* SYS___specialfd                    577 */
    GO(SYS___specialfd, "3s 1m");
    SY(SYS___specialfd, x0+0xf000, x0+1, x0+10); FAIL;
+   /* SYS_aio_writev                     578 */
+   GO(SYS_aio_writev, "1s 1m");
+   SY(SYS_aio_writev, x0+1); FAIL;
+   
+   /* SYS_aio_readv                      579 */
+   GO(SYS_aio_readv, "1s 1m");
+   SY(SYS_aio_readv, x0+1); FAIL;
 
    return(0);
 }
index 43b904e6f4ebbeafaebe13d498da67f9ac5915ca..c7c2e4027bd8279b0f6cd7b6f6182bf3ce7168c5 100644 (file)
@@ -100,3 +100,23 @@ Syscall param __specialfd(req) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
+---------------------------------------------------------
+578:          SYS_aio_writev 1s 1m
+---------------------------------------------------------
+Syscall param aio_writev(iocb) contains uninitialised byte(s)
+   ...
+
+Syscall param aio_writev(iocb) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+579:           SYS_aio_readv 1s 1m
+---------------------------------------------------------
+Syscall param aio_readv(iocb) contains uninitialised byte(s)
+   ...
+
+Syscall param aio_readv(iocb) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+