-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use python binary instead of libpython when it's a PIE #612
Comments
You can't Does |
Yes, it works. |
Hmm... So Any guess why? (@isuruf BTW, it looks like I don't need I created a conda environment with julia> using Libdl
julia> const libpath = abspath("py/bin/python")
"/home/takafumi/.julia/dev/_wt/PyCall/pie/py/bin/python"
julia> const wPYTHONHOME = Base.cconvert(Cwstring, string(abspath("py"), ':', abspath("py")));
julia> const wpyprogramname = Base.cconvert(Cwstring, libpath);
julia> h = Libdl.dlopen(libpath, Libdl.RTLD_LAZY|Libdl.RTLD_DEEPBIND|Libdl.RTLD_GLOBAL)
Ptr{Nothing} @0x0000000002b6ab10
julia> unsafe_string(ccall((:Py_GetVersion, libpath), Ptr{UInt8}, ()))
"3.7.1 (default, Oct 23 2018, 19:19:42) \n[GCC 7.3.0]"
julia> ccall((:Py_SetProgramName, libpath), Cvoid, (Ptr{Cwchar_t},), wpyprogramname)
julia> ccall((:Py_SetPythonHome, libpath), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
julia> ccall((:Py_InitializeEx, libpath), Cvoid, (Cint,), 0)
signal (11): Segmentation fault
in expression starting at no file:0
fileno_unlocked at /usr/lib/libc.so.6 (unknown line)
_PySys_BeginInit at /tmp/build/80754af9/python_1540319607830/work/Python/sysmodule.c:2292
_Py_InitializeCore_impl at /tmp/build/80754af9/python_1540319607830/work/Python/pylifecycle.c:753
_Py_InitializeCore at /tmp/build/80754af9/python_1540319607830/work/Python/pylifecycle.c:859
_Py_InitializeFromConfig at /tmp/build/80754af9/python_1540319607830/work/Python/pylifecycle.c:1002
Py_InitializeEx at /tmp/build/80754af9/python_1540319607830/work/Python/pylifecycle.c:1034
top-level scope at ./none:0
jl_fptr_trampoline at /buildworker/worker/package_linux64/build/src/gf.c:1831
jl_toplevel_eval_flex at /buildworker/worker/package_linux64/build/src/toplevel.c:807
jl_toplevel_eval_in at /buildworker/worker/package_linux64/build/src/builtins.c:622
eval at ./boot.jl:319
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2184
eval_user_input at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:85
macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:117 [inlined]
#28 at ./task.jl:259
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2184
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1537 [inlined]
start_task at /buildworker/worker/package_linux64/build/src/task.c:268
unknown function (ip: 0xffffffffffffffff)
Allocations: 882346 (Pool: 882247; Big: 99); GC: 0 |
Can you check what Py_IsInitialized gives you? |
OTOH |
@isuruf julia> using Libdl
julia> pyhome = abspath("py")
"/home/takafumi/.julia/dev/_wt/PyCall/pie/py"
julia> const libpath = "$pyhome/bin/python"
"/home/takafumi/.julia/dev/_wt/PyCall/pie/py/bin/python"
julia> const wPYTHONHOME = Base.cconvert(Cwstring, string(pyhome, ':', pyhome));
julia> const wpyprogramname = Base.cconvert(Cwstring, libpath);
julia> h = Libdl.dlopen(libpath, Libdl.RTLD_LAZY|Libdl.RTLD_DEEPBIND|Libdl.RTLD_GLOBAL)
Ptr{Nothing} @0x00000000026dabc0
julia> unsafe_string(ccall((:Py_GetVersion, libpath), Ptr{UInt8}, ()))
"3.7.1 (default, Oct 23 2018, 19:19:42) \n[GCC 7.3.0]"
julia> ccall((:Py_IsInitialized, libpath), Cint, ())
0
julia> ccall((:Py_SetProgramName, libpath), Cvoid, (Ptr{Cwchar_t},), wpyprogramname)
julia> ccall((:Py_SetPythonHome, libpath), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
julia> ccall((:Py_InitializeEx, libpath), Cvoid, (Cint,), 0)
signal (11): Segmentation fault
in expression starting at no file:0
fileno_unlocked at /usr/lib/libc.so.6 (unknown line)
_PySys_BeginInit at /tmp/build/80754af9/python_1540319607830/work/Python/sysmodule.c:2292 |
With julia> using Libdl
julia> pyhome = "/usr"
"/usr"
julia> const libpath = "$pyhome/bin/python"
"/usr/bin/python"
julia> const wPYTHONHOME = Base.cconvert(Cwstring, string(pyhome, ':', pyhome));
julia> const wpyprogramname = Base.cconvert(Cwstring, libpath);
julia> h = Libdl.dlopen(libpath, Libdl.RTLD_LAZY|Libdl.RTLD_DEEPBIND|Libdl.RTLD_GLOBAL)
Ptr{Nothing} @0x00000000024d8410
julia> unsafe_string(ccall((:Py_GetVersion, libpath), Ptr{UInt8}, ()))
"3.7.0 (default, Jul 15 2018, 10:44:58) \n[GCC 8.1.1 20180531]"
julia> ccall((:Py_IsInitialized, libpath), Cint, ())
0
julia> ccall((:Py_SetProgramName, libpath), Cvoid, (Ptr{Cwchar_t},), wpyprogramname)
julia> ccall((:Py_SetPythonHome, libpath), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
julia> ccall((:Py_InitializeEx, libpath), Cvoid, (Cint,), 0)
julia> ccall((:Py_IsInitialized, libpath), Cint, ())
1 |
Okay. Looks like this idea won't work |
julia> using Libdl
julia> const libpython = "/usr/bin/python"
"/usr/bin/python"
julia> const libpython_handle = Libdl.dlopen(libpython, Libdl.RTLD_LOCAL)
Ptr{Nothing} @0x000000000118c890
julia> using PyCall
julia> include("/home/isuru/.julia/packages/PyCall/0jMpb/test/runtests.jl")
┌ Info: Python version 2.7.15-rc1 from /usr/bin/python, PYTHONHOME=/usr:/usr
│ ENV[PYTHONPATH]=
│ ENV[PYTHONHOME]=
└ ENV[PYTHONEXECUTABLE]=
Test Summary: | Pass Total
PyCall | 432 432
Test Summary: | Pass Total
pydef | 6 6
Test Summary: | Pass Total
callback | 3 3
Test Summary: | Pass Total
pycall! | 16 16
Test.DefaultTestSet("pycall!", Any[DefaultTestSet("basics", Any[], 8, false), DefaultTestSet("kwargs", Any[], 8, false)], 0, false)
julia> using Pkg
julia> Pkg.dir("PyCall")
┌ Warning: `Pkg.dir(pkgname, paths...)` is deprecated; instead, do `import PyCall; joinpath(dirname(pathof(PyCall)), "..", paths...)`.
└ @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/Pkg/src/API.jl:454
"/home/isuru/.julia/packages/PyCall/0jMpb/" $ cat ~/.julia/packages/PyCall/0jMpb/deps/deps.jl
const python = "/usr/bin/python"
const pyprogramname = "/usr/bin/python"
const wpyprogramname = Base.cconvert(Cwstring, "/usr/bin/python")
const pyversion_build = v"2.7.15-rc1"
const PYTHONHOME = "/usr:/usr"
const wPYTHONHOME = Base.cconvert(Cwstring, "/usr:/usr")
const libpython = "/usr/bin/python"
"True if we are using the Python distribution in the Conda package."
const conda = false |
Cool! But do you need to pass
|
What is the Linux distribution you are using? |
Ubuntu 18.04 |
|
@isuruf Thanks! Yeah I just figured that out too :) |
Looks like |
That issue needs only RTLD_GLOBAL and RTLD_DEEPBIND is not needed. (I can reproduce after removing the workaround and cannot when RTLD_DEEPBIND is removed) |
So I put things together in a PR #614. But the same segmentation fault as above #612 (comment) happens even if I put the code that works in REPL in A MWE is: module PIEPyCall
using Libdl
const pyhome = abspath("py")
const libpython = "$pyhome/bin/python3.7"
const wPYTHONHOME = Base.cconvert(Cwstring, string(pyhome, ':', pyhome));
const wpyprogramname = Base.cconvert(Cwstring, libpython);
# function __init__()
h = Libdl.dlopen(libpython, Libdl.RTLD_LAZY|Libdl.RTLD_GLOBAL)
@show unsafe_string(ccall((:Py_GetVersion, libpython), Ptr{UInt8}, ()))
@show ccall((:Py_IsInitialized, libpython), Cint, ())
ccall((:Py_SetProgramName, libpython), Cvoid, (Ptr{Cwchar_t},), wpyprogramname)
ccall((:Py_SetPythonHome, libpython), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
ccall((:Py_InitializeEx, libpython), Cvoid, (Cint,), 0)
@show ccall((:Py_IsInitialized, libpython), Cint, ())
# end
end where removing the |
Interestingly, #614 works with conda in macOS https://travis-ci.org/JuliaPy/PyCall.jl/jobs/452716145#L230 |
Following works, but don't know why
|
Yes, it does! Puzzling... |
looks like |
I see! There is https://github.com/JuliaLang/julia/blob/c50aaeacc5c702f3a772c57ddacda0a80c2aafeb/src/julia.h#L1514 #define JL_RTLD_DEFAULT (JL_RTLD_LAZY | JL_RTLD_DEEPBIND) which is used in I wonder if there is a way to avoid Libdl.dlopen(libpython, Libdl.RTLD_LAZY|Libdl.RTLD_GLOBAL)
function __init__()
@show unsafe_string(ccall((:Py_GetVersion, libpython), Ptr{UInt8}, ()))
@show ccall((:Py_IsInitialized, libpython), Cint, ())
ccall((:Py_SetProgramName, libpython), Cvoid, (Ptr{Cwchar_t},), wpyprogramname)
ccall((:Py_SetPythonHome, libpython), Cvoid, (Ptr{Cwchar_t},), wPYTHONHOME)
ccall((:Py_InitializeEx, libpython), Cvoid, (Cint,), 0)
@show ccall((:Py_IsInitialized, libpython), Cint, ())
end |
Resetting stdio in python namespace like this works (i.e., diff --git a/src/pyinit.jl b/src/pyinit.jl
index e80af15..c822e52 100644
--- a/src/pyinit.jl
+++ b/src/pyinit.jl
@@ -89,6 +89,17 @@ function __init__()
# issue #189
libpy_handle = libpython === nothing ? C_NULL :
Libdl.dlopen(libpython, Libdl.RTLD_LAZY|Libdl.RTLD_GLOBAL)
+ if is_pie
+ unsafe_store!(
+ cglobal((@pysym :stdin), Ptr{Cvoid}),
+ unsafe_load(cglobal(:stdin, Ptr{Cvoid})))
+ unsafe_store!(
+ cglobal((@pysym :stdout), Ptr{Cvoid}),
+ unsafe_load(cglobal(:stdout, Ptr{Cvoid})))
+ unsafe_store!(
+ cglobal((@pysym :stderr), Ptr{Cvoid}),
+ unsafe_load(cglobal(:stderr, Ptr{Cvoid})))
+ end
already_inited = 0 != ccall((@pysym :Py_IsInitialized), Cint, ()) Not sure if this is safe, though. For example, would it close stdio twice? According to https://stackoverflow.com/a/24556049 it's undefined behavior. Maybe reopening stdio is safer? |
I had to check if
We always(?) have dynamic linking in Windows so it's not relevant there. Also, it looks tricky to load an executable as a library. |
Presumably, this would let us share precompilation cache between PyCall and PyJulia in more situations [1]: conda-forge/python-feedstock#222 (comment)
[1] Not all situation. For example, non-PIE statically linked
python
still won't work.The text was updated successfully, but these errors were encountered: