imagej/pyimagej

SIGSEV on tab-completion with osx / OpenJDK 8

Closed this issue · 7 comments

Fresh setup recently with:

conda create -n ij -c conda-forge pyimagej openjdk=8
source activate ij
Click to expand packages

(ij) ~ $conda list
# packages in environment at /opt/anaconda/envs/ij:
#
# Name                    Version                   Build  Channel
bzip2                     1.0.6             h1de35cc_1002    conda-forge
ca-certificates           2019.3.9             hecc5488_0    conda-forge
certifi                   2019.3.9                 py37_0    conda-forge
cycler                    0.10.0                     py_1    conda-forge
freetype                  2.10.0               h24853df_0    conda-forge
imglyb                    0.3.4           py37h24bf2e0_1000    conda-forge
jgo                       0.3.0                 py37_1000    conda-forge
kiwisolver                1.0.1           py37h04f5b5a_1002    conda-forge
libblas                   3.8.0                4_openblas    conda-forge
libcblas                  3.8.0                4_openblas    conda-forge
libcxx                    8.0.0                         1    conda-forge
libcxxabi                 8.0.0                         1    conda-forge
libffi                    3.2.1             h6de7cb9_1006    conda-forge
libgfortran               3.0.1                         0    conda-forge
liblapack                 3.8.0                4_openblas    conda-forge
libpng                    1.6.36            ha441bb4_1000    conda-forge
matplotlib                3.0.3                    py37_0    conda-forge
matplotlib-base           3.0.3            py37hf043ca5_0    conda-forge
maven                     3.6.0                         0    conda-forge
ncurses                   6.1               h0a44026_1002    conda-forge
numpy                     1.16.2           py37hbb3c62a_1    conda-forge
openblas                  0.3.5             h436c29b_1001    conda-forge
openjdk                   8.0.192           h1de35cc_1003    conda-forge
openssl                   1.1.1b               h01d97ff_2    conda-forge
pip                       19.0.3                   py37_0    conda-forge
pyimagej                  0.4.0                 py37_1001    conda-forge
pyjnius                   1.2.0            py37h90b5fae_0    conda-forge
pyparsing                 2.4.0                      py_0    conda-forge
python                    3.7.3                h0d93f26_0    conda-forge
python-dateutil           2.8.0                      py_0    conda-forge
readline                  7.0               hcfe32e1_1001    conda-forge
scyjava                   0.1.0                 py37_1001    conda-forge
setuptools                41.0.0                   py37_0    conda-forge
six                       1.12.0                py37_1000    conda-forge
sqlite                    3.26.0            h1765d9f_1001    conda-forge
tk                        8.6.9             ha441bb4_1001    conda-forge
tornado                   6.0.2            py37h01d97ff_0    conda-forge
wheel                     0.33.1                   py37_0    conda-forge
xz                        5.2.4             h1de35cc_1001    conda-forge
zlib                      1.2.11            h1de35cc_1004    conda-forge

Initialized with:

import imagej
ij = imagej.init("sc.fiji:fiji")

import jnius
ImageReader = jnius.autoclass("loci.formats.ImageReader")
ir = ImageReader()
ir.setId("/a.fake")

Typing ir.<tab> segfaults. Capturing here in case anyone else is having similar issues.

Click to expand error

>>> ir.setId("/a.fake")
17:49:46.135 [AWT-AppKit] DEBUG loci.common.NIOByteBufferProvider - Using mapped byte buffer? false
17:49:46.149 [AWT-AppKit] INFO  loci.formats.ImageReader - FakeReader initializing /a.fake
17:49:46.151 [AWT-AppKit] DEBUG loci.formats.FormatHandler - FakeReader initializing /a.fake
17:49:46.151 [AWT-AppKit] DEBUG loci.formats.FormatHandler - loci.formats.in.FakeReader.initFile(/a.fake)
17:49:46.173 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Loaded properties from: services.properties
17:49:46.391 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.POIService and implementation class loci.formats.services.POIServiceImpl
17:49:46.393 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.MDBService and implementation class loci.formats.services.MDBServiceImpl
17:49:46.393 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.JPEGTurboService and implementation class loci.formats.services.JPEGTurboServiceImpl
17:49:46.396 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface ome.codecs.services.LuraWaveService and implementation class ome.codecs.services.LuraWaveServiceImpl
17:49:46.398 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.JAIIIOService and implementation class loci.formats.services.JAIIIOServiceImpl
17:49:46.401 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.WlzService and implementation class loci.formats.services.WlzServiceImpl
17:49:46.402 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.JHDFService and implementation class loci.formats.services.JHDFServiceImpl
17:49:46.404 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.NetCDFService and implementation class loci.formats.services.NetCDFServiceImpl
17:49:46.405 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.EXIFService and implementation class loci.formats.services.EXIFServiceImpl
17:49:46.406 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.MetakitService and implementation class loci.formats.services.MetakitServiceImpl
17:49:46.406 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.LuraWaveService and implementation class loci.formats.services.LuraWaveServiceImpl
17:49:46.408 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.OMEXMLService and implementation class loci.formats.services.OMEXMLServiceImpl
17:49:46.409 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface ome.codecs.services.JAIIIOService and implementation class ome.codecs.services.JAIIIOServiceImpl
17:49:46.410 [AWT-AppKit] DEBUG loci.common.services.ServiceFactory - Added interface interface loci.formats.services.JPEGXRService and implementation class loci.formats.services.JPEGXRServiceImpl
>>> ir.#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000109820051, pid=51954, tid=0x0000000000000307
#
# JRE version: OpenJDK Runtime Environment (8.0_192-b01) (build 1.8.0_192-b01)
# Java VM: OpenJDK 64-Bit Server VM (25.192-b01 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.dylib+0x2eb051]  jni_GetIntField+0x96
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/jamoore/hs_err_pid51954.log
#
# If you would like to submit a bug report, please visit:
#   http://www.azulsystems.com/support/
#
Abort trap: 6

I am able to reproduce this problem with conda-forge's openjdk 8.0.192 build h1de35cc_1003, as well as openjdk 11.0.1 build h01d97ff_1015, and also AdoptOpenJDK build 12+33 (the latter by setting JAVA_HOME accordingly).

As a workaround for now, you can use:

dir(ir)

to get the names.

Or to print method signatures including argument types:

def methods(o):
    for m in ij.py.from_java(ij.notebook().methods(o)):
        print("{}({})".format(m['name'], m['arguments']))

methods(ir)

Weirdly, if I imagej.init('/Applications/Fiji.app') then I cannot reproduce—the tab-completion works. I am still able to reproduce when using sc.fiji:fiji though.

Wait, Wait, I know this one! The problem is that JNI functions can not be called when the thread is not attached and tab completion triggers a JNI call. Most IDE's use a separate thread for tab completion so that triggers a search on a disconnected thread. JPype gave up on trying to have the user handle connections and instead went with automatic attachment to fix this exact same bug after trying a bunch of work around for different IDEs, we ended with "just check thread is attached, before each call". The user can still disconnect manually when threads are complete, but forcing them to attach was just an endless issue generator.

I can confirm that in my dev version of pyimagej built on the latest jpype, the above tab completion now works, and does not crash.

Has the issue of tab completion been reported over to PyJNIus?

This is unfortunately a hard problem for library developers like JPype and PyJNIus. If you let users manage thread connection then IDEs will try to use unconnected which causes crashes which is a problem for desktop users. If you automatically connect then you have a potential resource leak if something is very aggressive about creating threads. And those automatic connections need to be daemon or the JVM can't shutdown properly.

It would be nice if Python had a "on thread exit" routine that you could place on individual threads so that when the Python run exits it calls the clean up routine automatically. Unfortunately I haven't found such a hook.

Fixed with the merge of #92.