Make the checking of poll() more accurate.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2938 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 4279f39..b694fad 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -4339,24 +4339,32 @@
 	short events;     -- requested events
 	short revents;    -- returned events
       };
-      int poll(struct pollfd *ufds, unsigned int nfds, 
-      int timeout) 
+      int poll(struct pollfd *ufds, unsigned int nfds, int timeout) 
    */
+   UInt i;
+   struct vki_pollfd* ufds = (struct vki_pollfd *)arg1;
    MAYBE_PRINTF("poll ( %p, %d, %d )\n",arg1,arg2,arg3);
-   /* In fact some parts of this struct should be readable too.
-      This should be fixed properly. */
-   SYSCALL_TRACK( pre_mem_write, tid, "poll(ufds)", 
-		  arg1, arg2 * sizeof(struct vki_pollfd) );
+
+   for (i = 0; i < arg2; i++) {
+      // 'fd' and 'events' field are inputs;  'revents' is output.
+      // XXX: this is x86 specific -- the pollfd struct varies across
+      // different architectures.
+      SYSCALL_TRACK( pre_mem_read, tid, "poll(ufds)",
+                     (Addr)(&ufds[i]), sizeof(int) + sizeof(short) );
+      SYSCALL_TRACK( pre_mem_write, tid, "poll(ufds)", 
+                     (Addr)(&ufds[i].revents), sizeof(short) );
+   }
 }
 
 POST(poll)
 {
    if (res > 0) {
       UInt i;
-      struct vki_pollfd * arr = (struct vki_pollfd *)arg1;
+      struct vki_pollfd* ufds = (struct vki_pollfd *)arg1;
+      // XXX: again, this is x86-specific
       for (i = 0; i < arg2; i++)
-	 VG_TRACK( post_mem_write, (Addr)(&arr[i].revents), 
-		   sizeof(Short) );
+	 VG_TRACK( post_mem_write, (Addr)(&ufds[i].revents), 
+		   sizeof(short) );
    }
 }
 
diff --git a/memcheck/tests/.cvsignore b/memcheck/tests/.cvsignore
index 8cc030c..7ef3ece 100644
--- a/memcheck/tests/.cvsignore
+++ b/memcheck/tests/.cvsignore
@@ -5,6 +5,7 @@
 badjump
 badjump2
 badloop
+badpoll
 badrw
 brk
 brk2
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 14aa31b..c5041cc 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -11,6 +11,7 @@
 	badjump.stderr.exp badjump.vgtest \
 	badjump2.stderr.exp badjump2.vgtest \
 	badloop.stderr.exp badloop.vgtest \
+	badpoll.stderr.exp badpoll.vgtest \
 	badrw.stderr.exp badrw.vgtest \
 	brk.stderr.exp brk.vgtest \
 	brk2.stderr.exp brk2.vgtest \
@@ -69,7 +70,7 @@
 
 check_PROGRAMS = \
 	badaddrvalue badfree badjump badjump2 \
-	badloop badrw brk brk2 buflen_check \
+	badloop badpoll badrw brk brk2 buflen_check \
 	clientperm custom_alloc \
 	doublefree error_counts errs1 exitprog execve execve2 \
 	fprw fwrite hello inits inline \
@@ -94,6 +95,7 @@
 badjump_SOURCES 	= badjump.c
 badjump2_SOURCES 	= badjump2.c
 badloop_SOURCES 	= badloop.c
+badpoll_SOURCES		= badpoll.c
 badrw_SOURCES		= badrw.c
 brk_SOURCES 		= brk.c
 brk2_SOURCES 		= brk2.c
diff --git a/memcheck/tests/badpoll.c b/memcheck/tests/badpoll.c
new file mode 100644
index 0000000..61b8d31
--- /dev/null
+++ b/memcheck/tests/badpoll.c
@@ -0,0 +1,25 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+
+// At one point, poll()'s checking was not done accurately.  This test
+// exposes this -- previously Memcheck only found one error, now if finds
+// two.
+
+int main(void)
+{
+   // Under-allocate by one byte so we get an addressability error.
+   struct pollfd* ufds = malloc(2 * sizeof(struct pollfd) - 1);
+   assert(ufds);
+
+   ufds[0].fd = 0;
+   ufds[0].events = 0;
+   //ufds[1].fd = 0;    // leave undefined so we get another error.
+   ufds[1].events = 0;
+
+   // Previously, the bounds-error due to the under-allocation was detected,
+   // but not the undefined value error due to ufds[1].fd not being defined.
+   poll(ufds, 2, 200);
+
+   return 0;
+}
diff --git a/memcheck/tests/badpoll.stderr.exp b/memcheck/tests/badpoll.stderr.exp
new file mode 100644
index 0000000..5193a31
--- /dev/null
+++ b/memcheck/tests/badpoll.stderr.exp
@@ -0,0 +1,13 @@
+Syscall param poll(ufds) contains uninitialised or unaddressable byte(s)
+   at 0x........: poll (in /...libc...)
+   by 0x........: main (badpoll.c:22)
+ Address 0x........ is 8 bytes inside a block of size 15 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (badpoll.c:12)
+
+Syscall param poll(ufds) contains unaddressable byte(s)
+   at 0x........: poll (in /...libc...)
+   by 0x........: main (badpoll.c:22)
+ Address 0x........ is 0 bytes after a block of size 15 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (badpoll.c:12)
diff --git a/memcheck/tests/badpoll.vgtest b/memcheck/tests/badpoll.vgtest
new file mode 100644
index 0000000..ac49e7f
--- /dev/null
+++ b/memcheck/tests/badpoll.vgtest
@@ -0,0 +1,2 @@
+prog: badpoll
+vgopts: -q