Date: Mon, 12 Aug 2019 09:16:29 -0700 From: Greg Lewis <glewis@eyesbeyond.com> To: freebsd-hackers@freebsd.org Subject: Java stack overflow segfaults Message-ID: <20190812161629.GA99971@misty.eyesbeyond.com>
next in thread | raw e-mail | index | archive | help
Hi all, I'm investigating an issue where, on FreeBSD, Java will crash rather than throw a StackOverflowError given a simple test program with a function that just calls itself over and over. There's an example of such a test in https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222146 This affects, I suspect, every native version of Java in the ports tree, although I've only tried openjdk8 and higher. My investigation has mostly focused on openjdk11. To outline the situation, Java uses pthreads internally for threading. It doesn't use the pthreads own guard page(s), but instead creates it's own guard area at the bottom of the stack (which grows downward) using mprotect. It then installs a signal handler and examines any SIGSEGV's fault address to see if it falls within the guard area, and if so throws a StackOverflowError. This logic is the same across all of the OSes I've looked at and works on OpenBSD, Linux, etc. On FreeBSD though, the fault address lies in the page above the guard zone, rather than in the guard zone, which results in a crash rather than throwing StackOverflowError. An diagram may help here: --- <- Stack top | | Untouched memory + stack frames + etc. | | | <-- SIGSEGV signal info fault address (< 1 page above guard zone) --- <- Start of JVM reserved zone / guard zone | | JVM Reserved page | --- <- Start of JVM yellow zone | | JVM Yellow pages | --- <- Start of JVM red zone | | JVM Red page | --- <- Stack bottom | | Pthread guard page(s) | --- On my FreeBSD 11.3/amd64 machine the JVM uses a total of four pages for the guard zone (1 reserved, 2 yellow, 1 red). The page size is 4K, and I see the follow mprotect calls with truss: mprotect(stack bottom address, 4K, PROT_NONE) (Just the red zone) mprotect(stack bottom address, 16K, PROT_NONE) (The entire guard zone) mprotect(top of red zone address, 12K, PROT_READ|PROT_WRITE) (Reserved + yellow) mprotect(top of red zone address, 12K, PROT_NONE) (Reserved + yellow) While I've committed a workaround for openjdk8, which just rounds down the fault address, it isn't entirely satisfactory (it's a hack) and I wondered if anyone had any insight into what may be going on. I've done an analysis of the sizes and addresses being used and used truss to check the parameters to the mprotect calls, and everything appears to add up. The same problem also occurs under FreeBSD 12.0/i386 and on aarch64, so it doesn't appear to be either version or platform specific. I've simplified a little here, but am happy to provide additional details and code references. -- Greg
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20190812161629.GA99971>