From: Paul Floyd Date: Thu, 16 Nov 2023 20:33:33 +0000 (+0100) Subject: Bug 476887 - WARNING: unhandled amd64-freebsd syscall: 578 X-Git-Tag: VALGRIND_3_23_0~272 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a15b387e630226b13944126fd3d75e79e551fcb2;p=thirdparty%2Fvalgrind.git Bug 476887 - WARNING: unhandled amd64-freebsd syscall: 578 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. --- diff --git a/.gitignore b/.gitignore index 369d49404c..7ccf1c2dec 100644 --- a/.gitignore +++ b/.gitignore @@ -1365,6 +1365,9 @@ /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 6736f58b2a..98c2ecf137 100644 --- 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 diff --git a/coregrind/m_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h index 5dcdc376a3..30b90ca37f 100644 --- a/coregrind/m_syswrap/priv_syswrap-freebsd.h +++ b/coregrind/m_syswrap/priv_syswrap-freebsd.h @@ -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 diff --git a/coregrind/m_syswrap/syswrap-darwin.c b/coregrind/m_syswrap/syswrap-darwin.c index c5c9b603b6..3b8ceda3e2 100644 --- a/coregrind/m_syswrap/syswrap-darwin.c +++ b/coregrind/m_syswrap/syswrap-darwin.c @@ -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) diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c index ce50566698..dab12a6eac 100644 --- a/coregrind/m_syswrap/syswrap-freebsd.c +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -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) diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c index 1c727966f3..7986eeec52 100644 --- a/coregrind/vg_preloaded.c +++ b/coregrind/vg_preloaded.c @@ -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) diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index fb1149f98b..466799cefd 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -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 index 0000000000..999eecb6f6 --- /dev/null +++ b/memcheck/tests/freebsd/aio.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include +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 index 0000000000..b40b054d15 --- /dev/null +++ b/memcheck/tests/freebsd/aio.stderr.exp @@ -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 index 0000000000..020a3ad26f --- /dev/null +++ b/memcheck/tests/freebsd/aio.vgtest @@ -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 index 0000000000..b7e2915d19 --- /dev/null +++ b/memcheck/tests/freebsd/aio_read.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..8ab686eafe --- /dev/null +++ b/memcheck/tests/freebsd/aio_read.in @@ -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 index 0000000000..e69de29bb2 diff --git a/memcheck/tests/freebsd/aio_read.stdout.exp b/memcheck/tests/freebsd/aio_read.stdout.exp new file mode 100644 index 0000000000..5fe0fa569d --- /dev/null +++ b/memcheck/tests/freebsd/aio_read.stdout.exp @@ -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 index 0000000000..3cbae387d3 --- /dev/null +++ b/memcheck/tests/freebsd/aio_read.vgtest @@ -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 index 0000000000..12d434c7e7 --- /dev/null +++ b/memcheck/tests/freebsd/aiov.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +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 index 0000000000..9fd6f9f210 --- /dev/null +++ b/memcheck/tests/freebsd/aiov.stderr.exp @@ -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 index 0000000000..5f2dabdcca --- /dev/null +++ b/memcheck/tests/freebsd/aiov.vgtest @@ -0,0 +1,3 @@ +prog: aiov +vgopts: --leak-check=no +stderr_filter: ../filter_allocs diff --git a/memcheck/tests/freebsd/scalar.c b/memcheck/tests/freebsd/scalar.c index 6c8d81aa6e..5afd0f2946 100644 --- a/memcheck/tests/freebsd/scalar.c +++ b/memcheck/tests/freebsd/scalar.c @@ -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 */ diff --git a/memcheck/tests/freebsd/scalar.stderr.exp b/memcheck/tests/freebsd/scalar.stderr.exp index 5a4f3230f1..38d2380f78 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp +++ b/memcheck/tests/freebsd/scalar.stderr.exp @@ -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) diff --git a/memcheck/tests/freebsd/scalar.stderr.exp-x86 b/memcheck/tests/freebsd/scalar.stderr.exp-x86 index a45d0601c3..cdb0825ca7 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp-x86 +++ b/memcheck/tests/freebsd/scalar.stderr.exp-x86 @@ -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) diff --git a/memcheck/tests/freebsd/scalar_13_plus.c b/memcheck/tests/freebsd/scalar_13_plus.c index 6e58e418fb..799dcfc8b7 100644 --- a/memcheck/tests/freebsd/scalar_13_plus.c +++ b/memcheck/tests/freebsd/scalar_13_plus.c @@ -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); } diff --git a/memcheck/tests/freebsd/scalar_13_plus.stderr.exp b/memcheck/tests/freebsd/scalar_13_plus.stderr.exp index 43b904e6f4..c7c2e4027b 100644 --- a/memcheck/tests/freebsd/scalar_13_plus.stderr.exp +++ b/memcheck/tests/freebsd/scalar_13_plus.stderr.exp @@ -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 +