From owner-freebsd-hackers@freebsd.org Mon Aug 12 16:16:39 2019 Return-Path: Delivered-To: freebsd-hackers@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 47232B8321 for ; Mon, 12 Aug 2019 16:16:39 +0000 (UTC) (envelope-from glewis@eyesbeyond.com) Received: from misty.eyesbeyond.com (gerbercreations.com [71.39.140.16]) by mx1.freebsd.org (Postfix) with ESMTP id 466gvn2Tjtz4Xj3 for ; Mon, 12 Aug 2019 16:16:36 +0000 (UTC) (envelope-from glewis@eyesbeyond.com) Received: from misty.eyesbeyond.com (localhost.eyesbeyond.com [127.0.0.1]) by misty.eyesbeyond.com (8.15.2/8.15.2) with ESMTP id x7CGGTJ4000338 for ; Mon, 12 Aug 2019 09:16:29 -0700 (PDT) (envelope-from glewis@eyesbeyond.com) Received: (from glewis@localhost) by misty.eyesbeyond.com (8.15.2/8.15.2/Submit) id x7CGGT33000337 for freebsd-hackers@freebsd.org; Mon, 12 Aug 2019 09:16:29 -0700 (PDT) (envelope-from glewis@eyesbeyond.com) X-Authentication-Warning: misty.eyesbeyond.com: glewis set sender to glewis@eyesbeyond.com using -f Date: Mon, 12 Aug 2019 09:16:29 -0700 From: Greg Lewis To: freebsd-hackers@freebsd.org Subject: Java stack overflow segfaults Message-ID: <20190812161629.GA99971@misty.eyesbeyond.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.12.1 (2019-06-15) X-Rspamd-Queue-Id: 466gvn2Tjtz4Xj3 X-Spamd-Bar: / Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=none; spf=none (mx1.freebsd.org: domain of glewis@eyesbeyond.com has no SPF policy when checking 71.39.140.16) smtp.mailfrom=glewis@eyesbeyond.com X-Spamd-Result: default: False [0.30 / 15.00]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-0.06)[-0.058,0]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; NEURAL_HAM_LONG(-0.38)[-0.379,0]; MIME_GOOD(-0.10)[text/plain]; PREVIOUSLY_DELIVERED(0.00)[freebsd-hackers@freebsd.org]; HAS_XAW(0.00)[]; AUTH_NA(1.00)[]; RCPT_COUNT_ONE(0.00)[1]; TO_DN_NONE(0.00)[]; NEURAL_HAM_SHORT(-0.25)[-0.254,0]; DMARC_NA(0.00)[eyesbeyond.com]; R_SPF_NA(0.00)[]; RCVD_NO_TLS_LAST(0.10)[]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:+]; ASN(0.00)[asn:209, ipnet:71.39.128.0/20, country:US]; RCVD_COUNT_TWO(0.00)[2]; IP_SCORE(-0.01)[asn: 209(-0.00), country: US(-0.05)] X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 16:16:39 -0000 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