/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
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
// 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
// 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)
#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
// 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)
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");
+ }
}
}
{
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);
}
}
{
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
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
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
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)
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
#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)
#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)
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 \
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 \
--- /dev/null
+#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;
+}
--- /dev/null
+
+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)
--- /dev/null
+prog: aio
+vgopts: --leak-check=no
+stderr_filter: ../filter_allocs
--- /dev/null
+// 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;
+}
--- /dev/null
+Hello, World!
--- /dev/null
+content: Hello, World!
+
--- /dev/null
+prog: aio_read
+args: < aio_read.in
+vgopts: -q
--- /dev/null
+#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;
+}
--- /dev/null
+
+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)
--- /dev/null
+prog: aiov
+vgopts: --leak-check=no
+stderr_filter: ../filter_allocs
/* 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 */
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
---------------------------------------------------------
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)
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
---------------------------------------------------------
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)
/* 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);
}
...
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
+