This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Committed: fix two simulator lseek syscall bugs (sim/cris and generic)


These were noticed while investigating
<http://gcc.gnu.org/PR45841>, a libstdc++ testsuite regression,
in which my autotester using the simulator flagged a regression,
a proper libstdc++ bug, but somewhat serendipitously for the
wrong reason; these bugs.

The lseek syscall is a gotcha.  That bug might be there for
other ports (and I wouldn't be surprised if in other
simulators).  The src/sim API to the host (struct cb_syscall)
uses "long" for syscall parameters.  The cris-*-* target is
ILP32, and target syscall parameters, generally being unsigned
32-bit numbers and addresses are handled in the port as "USI"
(uint32_t).  But, the lseek position parameter needs to be
sign-extended rather than zero-extended when on a LP64 host, or
you'll end up with 4G files (thankfully sparse) for writable
files, and wrong positions or errors for other files.  I
couldn't think of any other syscall parameter requiring
sign-extension for this target.

Speaking of lseek errors, the callback for lseek didn't handle
them.  Just a matter of wrapping it using the correct idiom,
like for other nearby I/O calls.

Regression-tested for cris-elf, committed.

sim/testsuite:
	* sim/cris/c/seek3.c, sim/cris/c/seek4.c: New tests.

sim/cris:
	* traps.c (cris_break_13_handler): Pass lseek
	offset parameter as sign-extended.

sim/common:
	* callback.c (os_lseek): Call wrap on lseek result.

Index: sim/cris/traps.c
===================================================================
RCS file: /cvs/src/src/sim/cris/traps.c,v
retrieving revision 1.22
diff -u -p -r1.22 traps.c
--- sim/cris/traps.c	14 Jan 2009 10:53:06 -0000	1.22
+++ sim/cris/traps.c	6 Oct 2010 05:06:01 -0000
@@ -1477,6 +1477,14 @@ cris_break_13_handler (SIM_CPU *current_
   s.arg2 = arg2;
   s.arg3 = arg3;
 
+  /* The type of s.arg2 is long, so for hosts with 64-bit longs, we need
+     to sign-extend the lseek offset to be passed as a signed number,
+     else we'll truncate it to something > 2GB on hosts where sizeof
+     long > sizeof USI.  We avoid doing it for all syscalls, as arg2 is
+     e.g. an address for some syscalls.  */
+  if (callnum == TARGET_SYS_lseek)
+    s.arg2 = (SI) arg2;
+
   if (callnum == TARGET_SYS_exit_group
       || (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0))
     {

Index: sim/common/callback.c
===================================================================
RCS file: /cvs/src/src/sim/common/callback.c,v
retrieving revision 1.25
diff -u -p -r1.25 callback.c
--- sim/common/callback.c	14 Jan 2009 10:53:05 -0000	1.25
+++ sim/common/callback.c	6 Oct 2010 05:06:01 -0000
@@ -278,7 +278,7 @@ os_lseek (p, fd, off, way)
   result = fdbad (p, fd);
   if (result)
     return result;
-  result = lseek (fdmap (p, fd), off, way);
+  result = wrap (p, lseek (fdmap (p, fd), off, way));
   return result;
 }
 
--- /dev/null	Tue Oct 29 15:57:07 2002
+++ sim/testsuite/sim/cris/c/seek3.c	Wed Oct  6 00:53:22 2010
@@ -0,0 +1,49 @@
+/* Check for a sim bug, whereby the position was always unsigned
+   (truncation instead of sign-extension for 64-bit hosts).  */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  FILE *f;
+  const char fname[] = "sk1test.dat";
+  const char tsttxt[]
+    = "A random line of text, used to test correct read, write and seek.\n";
+  char buf[sizeof tsttxt] = "";
+  const char correct[] = "correct";
+  char buf2[sizeof correct] = {0};
+  int fd;
+
+  f = fopen (fname, "wb");
+  if (f == NULL
+      || fwrite (tsttxt, 1, strlen (tsttxt), f) != strlen (tsttxt)
+      || fclose (f) != 0)
+    {
+      printf ("fail\n");
+      exit (1);
+    }
+
+  /* We have to use file-descriptor calls instead of stream calls to
+     provoke the bug (for stream calls, the lseek call is canonicalized
+     to use SEEK_SET).  */
+  fd = open (fname, O_RDONLY);
+  if (fd < 0
+      || read (fd, buf, strlen (tsttxt)) != strlen (tsttxt)
+      || strcmp (buf, tsttxt) != 0
+      || lseek (fd, -30L, SEEK_CUR) != 36
+      || read (fd, buf2, strlen (correct)) != strlen (correct)
+      || strcmp (buf2, correct) != 0)
+    {
+      printf ("fail\n");
+      exit (1);
+    }
+
+  printf ("pass\n");
+  exit (0);
+}
--- /dev/null	Tue Oct 29 15:57:07 2002
+++ sim/testsuite/sim/cris/c/seek4.c	Wed Oct  6 00:56:53 2010
@@ -0,0 +1,44 @@
+/* Check for a sim bug, whereby an invalid seek (to a negative offset)
+   did not return an error.  */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  FILE *f;
+  const char fname[] = "sk1test.dat";
+  const char tsttxt[]
+    = "A random line of text, used to test correct read, write and seek.\n";
+  char buf[sizeof tsttxt] = "";
+  int fd;
+
+  f = fopen (fname, "wb");
+  if (f == NULL
+      || fwrite (tsttxt, 1, strlen (tsttxt), f) != strlen (tsttxt)
+      || fclose (f) != 0)
+    {
+      printf ("fail\n");
+      exit (1);
+    }
+
+  fd = open (fname, O_RDONLY);
+  if (fd < 0
+      || lseek (fd, -1L, SEEK_CUR) != -1
+      || errno != EINVAL
+      || read (fd, buf, strlen (tsttxt)) != strlen (tsttxt)
+      || strcmp (buf, tsttxt) != 0)
+    {
+      printf ("fail\n");
+      exit (1);
+    }
+
+  printf ("pass\n");
+  exit (0);
+}

brgds, H-P


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]