Virtualise the stack rlimit for the main thread and make valgrind enforce
that limit when growing the stack. Also add a message when the stack in any
thread overflows.

CCMAIL: 73818-done@bugs.kde.org


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2689 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/core.h b/coregrind/core.h
index deff872..2a99c42 100644
--- a/coregrind/core.h
+++ b/coregrind/core.h
@@ -1243,6 +1243,7 @@
 extern Addr VG_(valgrind_last); // Nb: last byte, rather than one past the end
 
 extern vki_rlimit VG_(client_rlimit_data); /* client's original rlimit data */
+extern vki_rlimit VG_(client_rlimit_stack); /* client's original rlimit stack */
 
 /* client executable file descriptor */
 extern Int  VG_(clexecfd);
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 183fa2e..a077d58 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -113,6 +113,7 @@
 Addr VG_(valgrind_last);
 
 vki_rlimit VG_(client_rlimit_data);
+vki_rlimit VG_(client_rlimit_stack);
 
 /* This is set early to indicate whether this CPU has the
    SSE/fxsave/fxrestor features.  */
@@ -2496,7 +2497,10 @@
    VG_(getrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
    zero.rlim_max = VG_(client_rlimit_data).rlim_max;
    VG_(setrlimit)(VKI_RLIMIT_DATA, &zero);
-   
+
+   // Get the current process stack rlimit.
+   VG_(getrlimit)(VKI_RLIMIT_STACK, &VG_(client_rlimit_stack));
+
    //--------------------------------------------------------------
    // Check we were launched by stage1
    //   p: n/a
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index b181746..cf4050c 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -394,7 +394,7 @@
 */
 void VG_(scheduler_init) ( void )
 {
-   Int      i;
+   Int i;
    ThreadId tid_main;
 
    for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
@@ -428,7 +428,7 @@
    VG_(threads)[tid_main].stack_highest_word 
       = VG_(clstk_end) - 4;
    VG_(threads)[tid_main].stack_base = VG_(clstk_base);
-   VG_(threads)[tid_main].stack_size = VG_(clstk_end) - VG_(clstk_base);
+   VG_(threads)[tid_main].stack_size = VG_(client_rlimit_stack).rlim_cur;
 
    /* So now ... */
    vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c
index 4f4061b..9a8ace7 100644
--- a/coregrind/vg_signals.c
+++ b/coregrind/vg_signals.c
@@ -2109,7 +2109,8 @@
 	    then extend the stack segment. 
 	 */
 	 Addr base = PGROUNDDN(esp);
-         if ((void*)-1 != VG_(mmap)((Char *)base, seg->addr - base,
+         if (seg->len + (seg->addr - base) <= VG_(threads)[tid].stack_size &&
+             (void*)-1 != VG_(mmap)((Char *)base, seg->addr - base,
                               VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
                               VKI_MAP_PRIVATE|VKI_MAP_FIXED|VKI_MAP_ANONYMOUS|VKI_MAP_CLIENT,
                               SF_STACK|SF_GROWDOWN,
@@ -2138,6 +2139,14 @@
 	    recursion--;
 	 }
       }
+
+      if (info->si_code == 1		&&	/* SEGV_MAPERR */
+	  seg != NULL                   &&
+	  fault >= esp			&&
+	  fault < seg->addr		&&
+	  (seg->flags & SF_STACK)) {
+         VG_(message)(Vg_UserMsg, "Stack overflow in thread %d", tid);
+      }
    }
 
    /* Can't continue; must longjmp back to the scheduler and thus
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 2934f40..14ea259 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -2346,6 +2346,10 @@
     case VKI_RLIMIT_DATA:
 	*((vki_rlimit *)arg2) = VG_(client_rlimit_data);
 	break;
+
+    case VKI_RLIMIT_STACK:
+	*((vki_rlimit *)arg2) = VG_(client_rlimit_stack);
+	break;
     }
 }
 
@@ -4692,6 +4696,17 @@
       VG_(client_rlimit_data) = *(vki_rlimit *)arg2;
       res = 0;
    }
+   else if (arg1 == VKI_RLIMIT_STACK && tid == 1) {
+      if (((vki_rlimit *)arg2)->rlim_cur > ((vki_rlimit *)arg2)->rlim_max ||
+          ((vki_rlimit *)arg2)->rlim_max > ((vki_rlimit *)arg2)->rlim_max) {
+         res = -VKI_EPERM;
+      }
+      else {
+         VG_(threads)[tid].stack_size = ((vki_rlimit *)arg2)->rlim_cur;
+         VG_(client_rlimit_stack) = *(vki_rlimit *)arg2;
+         res = 0;
+      }
+   }
 }
 
 PRE(setuid)