diff options
| author | Paul Eggert | 2016-05-27 13:39:34 -0700 |
|---|---|---|
| committer | Paul Eggert | 2016-05-27 13:41:22 -0700 |
| commit | 9d356f62b3c24d9f2b2bc3831cf19e8351860a86 (patch) | |
| tree | 97241f72d0825ca2de1a203da2b9edec2a064af8 /src | |
| parent | 168163434678dcc030d1e2844765ddae7b555721 (diff) | |
| download | emacs-9d356f62b3c24d9f2b2bc3831cf19e8351860a86.tar.gz emacs-9d356f62b3c24d9f2b2bc3831cf19e8351860a86.zip | |
Robustify stack-size calculation
* src/emacs.c: Include getpagesize.h.
(main): Check for integer overflow when computing stack size.
Round new rlim_cur to pagesize boundary on all platforms, as this
is easy and would have prevented Bug#23622. If setrlimit
fails, use current limit to determine re_max_failures.
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/src/emacs.c b/src/emacs.c index 3e0cf596402..bdcebbe1637 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -91,6 +91,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 91 | #include "systime.h" | 91 | #include "systime.h" |
| 92 | #include "puresize.h" | 92 | #include "puresize.h" |
| 93 | 93 | ||
| 94 | #include "getpagesize.h" | ||
| 94 | #include "gnutls.h" | 95 | #include "gnutls.h" |
| 95 | 96 | ||
| 96 | #if (defined PROFILING \ | 97 | #if (defined PROFILING \ |
| @@ -672,9 +673,6 @@ main (int argc, char **argv) | |||
| 672 | bool do_initial_setlocale; | 673 | bool do_initial_setlocale; |
| 673 | bool dumping; | 674 | bool dumping; |
| 674 | int skip_args = 0; | 675 | int skip_args = 0; |
| 675 | #ifdef HAVE_SETRLIMIT | ||
| 676 | struct rlimit rlim; | ||
| 677 | #endif | ||
| 678 | bool no_loadup = 0; | 676 | bool no_loadup = 0; |
| 679 | char *junk = 0; | 677 | char *junk = 0; |
| 680 | char *dname_arg = 0; | 678 | char *dname_arg = 0; |
| @@ -825,38 +823,51 @@ main (int argc, char **argv) | |||
| 825 | is built with an 8MB stack. Moreover, the setrlimit call can | 823 | is built with an 8MB stack. Moreover, the setrlimit call can |
| 826 | cause problems on Cygwin | 824 | cause problems on Cygwin |
| 827 | (https://www.cygwin.com/ml/cygwin/2015-07/msg00096.html). */ | 825 | (https://www.cygwin.com/ml/cygwin/2015-07/msg00096.html). */ |
| 828 | if (1 | 826 | struct rlimit rlim; |
| 829 | #ifndef CANNOT_DUMP | 827 | if (getrlimit (RLIMIT_STACK, &rlim) == 0 |
| 830 | && (!noninteractive || initialized) | 828 | && 0 <= rlim.rlim_cur && rlim.rlim_cur <= LONG_MAX) |
| 831 | #endif | ||
| 832 | && !getrlimit (RLIMIT_STACK, &rlim)) | ||
| 833 | { | 829 | { |
| 834 | long newlim; | 830 | long lim = rlim.rlim_cur; |
| 835 | /* Approximate the amount regex.c needs per unit of re_max_failures. */ | 831 | |
| 832 | /* Approximate the amount regex.c needs per unit of | ||
| 833 | re_max_failures, then add 33% to cover the size of the | ||
| 834 | smaller stacks that regex.c successively allocates and | ||
| 835 | discards on its way to the maximum. */ | ||
| 836 | int ratio = 20 * sizeof (char *); | 836 | int ratio = 20 * sizeof (char *); |
| 837 | /* Then add 33% to cover the size of the smaller stacks that regex.c | ||
| 838 | successively allocates and discards, on its way to the maximum. */ | ||
| 839 | ratio += ratio / 3; | 837 | ratio += ratio / 3; |
| 840 | /* Add in some extra to cover | 838 | |
| 841 | what we're likely to use for other reasons. */ | 839 | /* Extra space to cover what we're likely to use for other reasons. */ |
| 842 | newlim = re_max_failures * ratio + 200000; | 840 | int extra = 200000; |
| 843 | #ifdef __NetBSD__ | 841 | |
| 844 | /* NetBSD (at least NetBSD 1.2G and former) has a bug in its | 842 | bool try_to_grow_stack = true; |
| 845 | stack allocation routine for new process that the allocation | 843 | #ifndef CANNOT_DUMP |
| 846 | fails if stack limit is not on page boundary. So, round up the | 844 | try_to_grow_stack = !noninteractive || initialized; |
| 847 | new limit to page boundary. */ | 845 | #endif |
| 848 | newlim = (newlim + getpagesize () - 1) / getpagesize () * getpagesize (); | 846 | |
| 849 | #endif | 847 | if (try_to_grow_stack) |
| 850 | if (newlim > rlim.rlim_max) | ||
| 851 | { | 848 | { |
| 852 | newlim = rlim.rlim_max; | 849 | long newlim = re_max_failures * ratio + extra; |
| 853 | /* Don't let regex.c overflow the stack we have. */ | 850 | |
| 854 | re_max_failures = (newlim - 200000) / ratio; | 851 | /* Round the new limit to a page boundary; this is needed |
| 852 | for Darwin kernel 15.4.0 (see Bug#23622) and perhaps | ||
| 853 | other systems. Do not shrink the stack and do not exceed | ||
| 854 | rlim_max. Don't worry about values like RLIM_INFINITY | ||
| 855 | since in practice they are so large that the code does | ||
| 856 | the right thing anyway. */ | ||
| 857 | long pagesize = getpagesize (); | ||
| 858 | newlim = min (newlim + pagesize - 1, rlim.rlim_max); | ||
| 859 | newlim -= newlim % pagesize; | ||
| 860 | |||
| 861 | if (pagesize <= newlim - lim) | ||
| 862 | { | ||
| 863 | rlim.rlim_cur = newlim; | ||
| 864 | if (setrlimit (RLIMIT_STACK, &rlim) == 0) | ||
| 865 | lim = newlim; | ||
| 866 | } | ||
| 855 | } | 867 | } |
| 856 | if (rlim.rlim_cur < newlim) | ||
| 857 | rlim.rlim_cur = newlim; | ||
| 858 | 868 | ||
| 859 | setrlimit (RLIMIT_STACK, &rlim); | 869 | /* Don't let regex.c overflow the stack. */ |
| 870 | re_max_failures = lim < extra ? 0 : min (lim - extra, SIZE_MAX) / ratio; | ||
| 860 | } | 871 | } |
| 861 | #endif /* HAVE_SETRLIMIT and RLIMIT_STACK and not CYGWIN */ | 872 | #endif /* HAVE_SETRLIMIT and RLIMIT_STACK and not CYGWIN */ |
| 862 | 873 | ||