Skip to content
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

Rust 1.54.0 optimized compilation overwrites stack variable, causing segfault #87947

Closed
indygreg opened this issue Aug 12, 2021 · 16 comments
Closed
Labels
C-bug Category: This is a bug. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@indygreg
Copy link
Contributor

I am able to reliably reproduce a crash on x86_64-unknown-linux-gnu when building in --release mode with 1.54.0. The same code and build configuration works properly on 1.53.0.

I'm not a great assembly-level debugger, but I believe the compiler is confused about register/variable aliasing and this effectively leads to corruption of a variable on the stack, which leads to a segfault.

Rust 1.54.0 Analysis

We're about to return from _PyArgv_AsWstrList (from the CPython 3.9 internals):

105     in Python/preconfig.c
   0x0000555555ae1456 <+54>:    mov    %r14,%rdi
   0x0000555555ae1459 <+57>:    call   0x555555ad9020 <_PyWideStringList_Copy>
   0x0000555555ae145e <+62>:    test   %eax,%eax
   0x0000555555ae1460 <+64>:    js     0x555555ae14dc <_PyArgv_AsWstrList+188>

106     in Python/preconfig.c
107     in Python/preconfig.c
108     in Python/preconfig.c
109     in Python/preconfig.c
=> 0x0000555555ae1462 <+66>:    xorps  %xmm0,%xmm0
   0x0000555555ae1465 <+69>:    movups %xmm0,0x10(%r15)
   0x0000555555ae146a <+74>:    movups %xmm0,(%r15)

110     in Python/preconfig.c
   0x0000555555ae146e <+78>:    mov    %r15,%rax
   0x0000555555ae1471 <+81>:    add    $0x20,%rsp
   0x0000555555ae1475 <+85>:    pop    %rbx
   0x0000555555ae1476 <+86>:    pop    %r12
   0x0000555555ae1478 <+88>:    pop    %r13
   0x0000555555ae147a <+90>:    pop    %r14
   0x0000555555ae147c <+92>:    pop    %r15
   0x0000555555ae147e <+94>:    ret

(gdb) info registers
rax            0x5555559e8ae0      93824997034720
rbx            0x7fffffffc530      140737488340272
rcx            0x7ffff7808008      140737345781768
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x1                 0x1
rsp            0x7fffffffc4c0      0x7fffffffc4c0
r8             0x1                 1
r9             0x0                 0
r10            0x0                 0
r11            0x7ffff7809000      140737345785856
r12            0x7fffffffc4d8      140737488340184
r13            0x1                 1
r14            0x7fffffffc848      140737488341064
r15            0x7fffffffc600      140737488340480
rip            0x555555ae1462      0x555555ae1462 <_PyArgv_AsWstrList+66>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

And here's the last few frame pointers.

(gdb) info frame 0
Stack frame at 0x7fffffffc510:
 rip = 0x555555ae1462 in _PyArgv_AsWstrList (Python/preconfig.c:109); saved rip = 0x5555558733f2
 called by frame at 0x7fffffffc570
 source language c.
 Arglist at 0x7fffffffc4b8, args: args=0x7fffffffc530, list=0x7fffffffc848
 Locals at 0x7fffffffc4b8, Previous frame's sp is 0x7fffffffc510
 Saved registers:
  rbx at 0x7fffffffc4e0, r12 at 0x7fffffffc4e8, r13 at 0x7fffffffc4f0, r14 at 0x7fffffffc4f8, r15 at 0x7fffffffc500, rip at 0x7fffffffc508

(gdb) info frame 1
Stack frame at 0x7fffffffc570:
 rip = 0x5555558733f2 in _PyConfig_SetPyArgv (./Python/initconfig.c:2448); saved rip = 0x555555a4c92c
 inlined into frame 2, caller of frame at 0x7fffffffc510
 source language c.
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0x7fffffffc510
 Saved registers:
  rbx at 0x7fffffffc4e0, r12 at 0x7fffffffc4e8, r13 at 0x7fffffffc4f0, r14 at 0x7fffffffc4f8, r15 at 0x7fffffffc500, rip at 0x7fffffffc508

(gdb) info frame 2
Stack frame at 0x7fffffffc570:
 rip = 0x5555558733f2 in PyConfig_SetBytesArgv (./Python/initconfig.c:2462); saved rip = 0x555555a4c92c
 called by frame at 0x7fffffffc650, caller of frame at 0x7fffffffc570
 source language c.
 Arglist at 0x7fffffffc508, args: config=<optimized out>, argc=<optimized out>, argv=<optimized out>
 Locals at 0x7fffffffc508, Previous frame's sp is 0x7fffffffc570
 Saved registers:
  rbx at 0x7fffffffc550, r14 at 0x7fffffffc558, r15 at 0x7fffffffc560, rip at 0x7fffffffc568

(gdb) info frame 3
Stack frame at 0x7fffffffc650:
 rip = 0x555555a4c92c in pyembed::interpreter_config::set_argv (/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:215);
    saved rip = 0x555555a04e1d
 called by frame at 0x7fffffffcb20, caller of frame at 0x7fffffffc570
 source language rust.
 Arglist at 0x7fffffffc570, args: config=0x0, args=...
 Locals at 0x7fffffffc570, Previous frame's sp is 0x7fffffffc650
 Saved registers:
  rbx at 0x7fffffffc618, rbp at 0x7fffffffc640, r12 at 0x7fffffffc620, r13 at 0x7fffffffc628, r14 at 0x7fffffffc630, r15 at 0x7fffffffc638,
  rip at 0x7fffffffc648

(gdb) info frame 4
Stack frame at 0x7fffffffcb20:
 rip = 0x555555a04e1d in pyembed::interpreter_config::{{impl}}::try_into (/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:592);
    saved rip = 0x555555a49736
 called by frame at 0x7fffffffd9e0, caller of frame at 0x7fffffffc650
 source language rust.
 Arglist at 0x7fffffffc648, args: self=0x7fffffffcff0
 Locals at 0x7fffffffc648, Previous frame's sp is 0x7fffffffcb20
 Saved registers:
  rbx at 0x7fffffffcaf8, r12 at 0x7fffffffcb00, r14 at 0x7fffffffcb08, r15 at 0x7fffffffcb10, rip at 0x7fffffffcb18

(gdb) info frame 5
Stack frame at 0x7fffffffd9e0:
 rip = 0x555555a49736 in pyembed::interpreter::MainPythonInterpreter::init (/home/gps/src/pyoxidizer.git/pyembed/src/interpreter.rs:169);
    saved rip = 0x5555559dde78
 inlined into frame 6, caller of frame at 0x7fffffffcb20
 source language rust.
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0x7fffffffcb20
 Saved registers:
  rbx at 0x7fffffffcaf8, r12 at 0x7fffffffcb00, r14 at 0x7fffffffcb08, r15 at 0x7fffffffcb10, rip at 0x7fffffffcb18

We eventually crash in frame 4. So let's look at it's state:

(gdb) f 4
#4  0x0000555555a04e1d in pyembed::interpreter_config::{{impl}}::try_into (self=0x7fffffffcff0)
    at /home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:592
592                 set_argv(&mut config, argv)?;
(gdb) info registers
rax            0x5555559e8ae0      93824997034720
rbx            0x7fffffffcff0      140737488343024
rcx            0x7ffff7808008      140737345781768
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x7fffffffd308      0x7fffffffd308
rsp            0x7fffffffc650      0x7fffffffc650
r8             0x1                 1
r9             0x0                 0
r10            0x0                 0
r11            0x7ffff7809000      140737345785856
r12            0x7ffff7d9ff40      140737351647040
r13            0x0                 0
r14            0x7fffffffcc70      140737488342128
r15            0x7fffffffc970      140737488341360
rip            0x555555a04e1d      0x555555a04e1d <pyembed::interpreter_config::{{impl}}::try_into+173>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

Here are the important details:

The instructions we're about to execute are:

0x0000555555ae1462 <+66>:    xorps  %xmm0,%xmm0
0x0000555555ae1465 <+69>:    movups %xmm0,0x10(%r15)
0x0000555555ae146a <+74>:    movups %xmm0,(%r15)

self in frame 4 is 0x7fffffffcff0, which appears to be inhabiting rbx.

The value of r15 is 0x7fffffffc600. This memory address is close to frame 4's arglist and locals (0x7fffffffc648). The value returned by this function is propagating through the intermediate frames to frame 4, which operates on it. So the compiler likely optimized things to a variable write directly into frame 4's locals space. Cool.

Before we execute that movups %xmm0,0x10(%r15), here is the memory we're operating on:

0x7fffffffc600: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffc610: 0x00000000      0x00000000      0xffffcff0      0x00007fff
0x7fffffffc620: 0xf7d9ff40      0x00007fff      0x00000000      0x00000000
0x7fffffffc630: 0xffffcc70      0x00007fff      0xffffc970      0x00007fff
0x7fffffffc640: 0xffffd308      0x00007fff      0x55a04e1d      0x00005555
0x7fffffffc650: 0xffffc8d0      0x00007fff      0x00000000      0x00000000
0x7fffffffc660: 0x00000003      0x00000001      0x00000000      0x00000000

And after:

0x7fffffffc600: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffc610: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffc620: 0xf7d9ff40      0x00007fff      0x00000000      0x00000000
0x7fffffffc630: 0xffffcc70      0x00007fff      0xffffc970      0x00007fff
0x7fffffffc640: 0xffffd308      0x00007fff      0x55a04e1d      0x00005555
0x7fffffffc650: 0xffffc8d0      0x00007fff      0x00000000      0x00000000
0x7fffffffc660: 0x00000003      0x00000001      0x00000000      0x00000000

The change there is:

 0x7fffffffc600: 0x00000000      0x00000000      0x00000000      0x00000000
-0x7fffffffc610: 0x00000000      0x00000000      0xffffcff0      0x00007fff
+0x7fffffffc610: 0x00000000      0x00000000      0x00000000      0x00000000
 0x7fffffffc620: 0xf7d9ff40      0x00007fff      0x00000000      0x00000000

So the 16 bytes between 0x7fffffffc610-0x7fffffffc61f got cleared out. Makes sense: that's what the instructions told it to do.

However, 0x7fffffffc618 contained the saved register value (0x7fffffffcff0) for rbx, holding the address of self. This value is now zeroed.

We confirm this from GDB:

(gdb) f 4
#4  0x0000555555a04e1d in pyembed::interpreter_config::{{impl}}::try_into (self=0x0)
    at /home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:592
592                 set_argv(&mut config, argv)?;
(gdb) info registers
rax            0x5555559e8ae0      93824997034720
rbx            0x0                 0
rcx            0x7ffff7808008      140737345781768
rdx            0x0                 0

Note that rbx is 0x0 and self=0x0.

Several instructions later, we return to frame 4 and execute assembly corresponding to the Rust code if self.exe.is_none() {. Since self is NULL, we get a segfault.

Rust 1.53.0 Analysis

Compiling the same source code with Rust 1.53.0, things look similar:

105     in Python/preconfig.c
   0x0000555555ae0886 <+54>:    mov    %r14,%rdi
   0x0000555555ae0889 <+57>:    call   0x555555ad8450 <_PyWideStringList_Copy>
   0x0000555555ae088e <+62>:    test   %eax,%eax
   0x0000555555ae0890 <+64>:    js     0x555555ae090c <_PyArgv_AsWstrList+188>

106     in Python/preconfig.c
107     in Python/preconfig.c
108     in Python/preconfig.c
109     in Python/preconfig.c
=> 0x0000555555ae0892 <+66>:    xorps  %xmm0,%xmm0
   0x0000555555ae0895 <+69>:    movups %xmm0,0x10(%r15)
   0x0000555555ae089a <+74>:    movups %xmm0,(%r15)

110     in Python/preconfig.c
   0x0000555555ae089e <+78>:    mov    %r15,%rax
   0x0000555555ae08a1 <+81>:    add    $0x20,%rsp
   0x0000555555ae08a5 <+85>:    pop    %rbx
   0x0000555555ae08a6 <+86>:    pop    %r12
   0x0000555555ae08a8 <+88>:    pop    %r13
   0x0000555555ae08aa <+90>:    pop    %r14
   0x0000555555ae08ac <+92>:    pop    %r15
   0x0000555555ae08ae <+94>:    ret

(gdb) info frame 0
Stack frame at 0x7fffffffc410:
 rip = 0x555555ae0892 in _PyArgv_AsWstrList (Python/preconfig.c:109); saved rip = 0x5555558724a2
 called by frame at 0x7fffffffc470
 source language c.
 Arglist at 0x7fffffffc3b8, args: args=0x7fffffffc430, list=0x7fffffffc8e0
 Locals at 0x7fffffffc3b8, Previous frame's sp is 0x7fffffffc410
 Saved registers:
  rbx at 0x7fffffffc3e0, r12 at 0x7fffffffc3e8, r13 at 0x7fffffffc3f0, r14 at 0x7fffffffc3f8, r15 at 0x7fffffffc400, rip at 0x7fffffffc408

(gdb) info frame 1
Stack frame at 0x7fffffffc470:
 rip = 0x5555558724a2 in _PyConfig_SetPyArgv (./Python/initconfig.c:2448); saved rip = 0x555555a42a6c
 inlined into frame 2, caller of frame at 0x7fffffffc410
 source language c.
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0x7fffffffc410
 Saved registers:
  rbx at 0x7fffffffc3e0, r12 at 0x7fffffffc3e8, r13 at 0x7fffffffc3f0, r14 at 0x7fffffffc3f8, r15 at 0x7fffffffc400, rip at 0x7fffffffc408

(gdb) info frame 2
Stack frame at 0x7fffffffc470:
 rip = 0x5555558724a2 in PyConfig_SetBytesArgv (./Python/initconfig.c:2462); saved rip = 0x555555a42a6c
 called by frame at 0x7fffffffc550, caller of frame at 0x7fffffffc470
 source language c.
 Arglist at 0x7fffffffc408, args: config=<optimized out>, argc=<optimized out>, argv=<optimized out>
 Locals at 0x7fffffffc408, Previous frame's sp is 0x7fffffffc470
 Saved registers:
  rbx at 0x7fffffffc450, r14 at 0x7fffffffc458, r15 at 0x7fffffffc460, rip at 0x7fffffffc468

(gdb) info frame 3
Stack frame at 0x7fffffffc550:
 rip = 0x555555a42a6c in pyembed::interpreter_config::set_argv (/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:215);
    saved rip = 0x5555559fe846
 called by frame at 0x7fffffffca30, caller of frame at 0x7fffffffc470
 source language rust.
 Arglist at 0x7fffffffc470, args: config=0x0, args=...
 Locals at 0x7fffffffc470, Previous frame's sp is 0x7fffffffc550
 Saved registers:
  rbx at 0x7fffffffc518, rbp at 0x7fffffffc540, r12 at 0x7fffffffc520, r13 at 0x7fffffffc528, r14 at 0x7fffffffc530, r15 at 0x7fffffffc538,
  rip at 0x7fffffffc548

(gdb) info frame 4
Stack frame at 0x7fffffffca30:
 rip = 0x5555559fe846 in pyembed::interpreter_config::{{impl}}::try_into (/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:592);
    saved rip = 0x555555a36692
 called by frame at 0x7fffffffd9e0, caller of frame at 0x7fffffffc550
 source language rust.
 Arglist at 0x7fffffffc548, args: self=0x7fffffffcff0
 Locals at 0x7fffffffc548, Previous frame's sp is 0x7fffffffca30
 Saved registers:
  rbx at 0x7fffffffca08, r12 at 0x7fffffffca10, r14 at 0x7fffffffca18, r15 at 0x7fffffffca20, rip at 0x7fffffffca28
(gdb) info registers
rax            0x5555559e70a0      93824997028000
rbx            0x7fffffffc430      140737488340016
rcx            0x7ffff7808008      140737345781768
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x1                 0x1
rsp            0x7fffffffc3c0      0x7fffffffc3c0
r8             0x1                 1
r9             0x0                 0
r10            0x0                 0
r11            0x7ffff7809000      140737345785856
r12            0x7fffffffc3d8      140737488339928
r13            0x1                 1
r14            0x7fffffffc8e0      140737488341216
r15            0x7fffffffc500      140737488340224
rip            0x555555ae0892      0x555555ae0892 <_PyArgv_AsWstrList+66>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) frame 4
#4  0x00005555559fe846 in pyembed::interpreter_config::{{impl}}::try_into (self=0x7fffffffcff0)
    at /home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:592
592                 set_argv(&mut config, argv)?;

(gdb) info registers
rax            0x5555559e70a0      93824997028000
rbx            0x0                 0
rcx            0x7ffff7808008      140737345781768
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x7fffffffd308      0x7fffffffd308
rsp            0x7fffffffc550      0x7fffffffc550
r8             0x1                 1
r9             0x0                 0
r10            0x0                 0
r11            0x7ffff7809000      140737345785856
r12            0x7fffffffcff0      140737488343024
r13            0x0                 0
r14            0x7fffffffcb00      140737488341760
r15            0x7fffffffcff0      140737488343024
rip            0x5555559fe846      0x5555559fe846 <pyembed::interpreter_config::{{impl}}::try_into+166>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

This time r15 is 0x7fffffffc500.

And frame 4's arglist is at 0x7fffffffc548. The offsets are the same here. So the assembly changes the same relative bytes.

But, the starting bytes that are nulled out start out as NULL, so the movups is effectively a no-op:

0x7fffffffc4f0: 0x00000001      0x00000000      0x00000001      0x00000000
0x7fffffffc500: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffc510: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffc520: 0xffffcff0      0x00007fff      0x00000000      0x00000000
0x7fffffffc530: 0xffffcb00      0x00007fff      0xffffcff0      0x00007fff
0x7fffffffc540: 0xffffd308      0x00007fff      0x559fe846      0x00005555
0x7fffffffc550: 0x00000038      0x00000000      0x00000000      0x00000000

However, this version does not crash because self is not overwritten because its address isn't stored in rbx. The address of self (0x7fffffffcff0) is stored in r12 and r15. (I'm unsure how the memory address for self is calculated here.)

Hypothesis

This smells like a compiler optimization bug. Rust 1.54.0 seems to be emitting assembly that aliases 2 variables/registers to the same memory address.

Steps to Reproduce

git clone https://github.com/indygreg/PyOxidizer.git
cd PyOxidizer
git checkout rust-crash
cargo run --bin pyoxidizer -- init-rust-project ~/tmp/crash
cd ~/tmp/crash

cat > Cargo.toml <<EOF
[profile.release]
debug = true
EOF

cargo run --release --features allocator-jemalloc

In a debugger, try setting a breakpoint at preconfig.c:109. This should stop just before self gets overwritten.

The Rust function call from the crashing frame is https://github.com/indygreg/PyOxidizer/blob/0ca3236bac944b63ea8506f273b064167e25f47b/pyembed/src/interpreter_config.rs#L592. This calls into another Rust function which calls into CPython C APIs. The crash occurs at https://github.com/indygreg/PyOxidizer/blob/0ca3236bac944b63ea8506f273b064167e25f47b/pyembed/src/interpreter_config.rs#L595 when dereferencing a NULL self.

@indygreg indygreg added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels Aug 12, 2021
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Aug 12, 2021
@indygreg
Copy link
Contributor Author

Oh, I forgot to mention I can make the bug/crash go away by inserting a println!("{}", argv) line at https://github.com/indygreg/PyOxidizer/blob/0ca3236bac944b63ea8506f273b064167e25f47b/pyembed/src/interpreter_config.rs#L592 as well as performing other minor changes to the code in question. This being a provable heisenbug amplifies my theory of a compiler bug and not something wrong in my code. Although this reproduce case is making ample use of unsafe so bad code should not be ruled out.

@indygreg
Copy link
Contributor Author

Using the ccffcafd5 2021-08-11 nightly, I can reproduce this bug with the default configuration and with RUSTFLAGS="-Z mutable-noalias=yes" and RUSTFLAGS="-Z mutable-noalias=no". So it doesn't seem to be a mutable-noalias issue.

The memory layout in nightly is the same as 1.54.0: self is stored in rbx in the crashing frame and is incorrectly overwritten.

@JohnTitor JohnTitor added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. and removed regression-untriaged Untriaged performance or correctness regression. labels Aug 12, 2021
@eddyb
Copy link
Member

eddyb commented Aug 12, 2021

If this is a LLVM optimization change, you can try comparing the output from:

cargo rustc -- -Z no-parallel-llvm -C llvm-args=-print-after-all -Z symbol-mangling-version=v0 2> llvm.log

cc @nikic @nagisa

@apiraino apiraino added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 12, 2021
@indygreg
Copy link
Contributor Author

If this is a LLVM optimization change, you can try comparing the output from:

cargo rustc -- -Z no-parallel-llvm -C llvm-args=-print-after-all -Z symbol-mangling-version=v0 2> llvm.log

Thanks for the pointer.

I was able to do this. However, the diff is quite large and I'm not really sure what I'm looking at.

I probably should have posted the disassembly from the crashing function (https://github.com/indygreg/PyOxidizer/blob/0ca3236bac944b63ea8506f273b064167e25f47b/pyembed/src/interpreter_config.rs#L585).

Here's the working version in 1.53.0:

Dump of assembler code for function _ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E:
/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
585         fn try_into(self) -> Result<pyffi::PyConfig, Self::Error> {
   0x0000555555a02e30 <+0>:     push   %r15
   0x0000555555a02e32 <+2>:     push   %r14
   0x0000555555a02e34 <+4>:     push   %rbx
   0x0000555555a02e35 <+5>:     sub    $0x4b0,%rsp
   0x0000555555a02e3c <+12>:    mov    %rsi,%r15
   0x0000555555a02e3f <+15>:    mov    %rdi,%r14

586             // We use the raw configuration as a base then we apply any adjustments,
587             // as needed.
588             let mut config: pyffi::PyConfig =
589                 python_interpreter_config_to_py_config(&self.interpreter_config)?;
=> 0x0000555555a02e42 <+18>:    add    $0x30,%rsi
   0x0000555555a02e46 <+22>:    lea    0x198(%rsp),%rdi
   0x0000555555a02e4e <+30>:    call   0x555555a42bd0 <_ZN7pyembed18interpreter_config38python_interpreter_config_to_py_config17h7c09a0c959ab9a73E>

/rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/result.rs:
1636    /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/result.rs: No such file or directory.
   0x0000555555a02e53 <+35>:    mov    0x198(%rsp),%rbx
   0x0000555555a02e5b <+43>:    lea    0x1a0(%rsp),%rsi
   0x0000555555a02e63 <+51>:    lea    0x10(%rsp),%rdi
   0x0000555555a02e68 <+56>:    mov    $0x188,%edx
   0x0000555555a02e6d <+61>:    call   *0x147169d(%rip)        # 0x555556e74510

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
589                 python_interpreter_config_to_py_config(&self.interpreter_config)?;
   0x0000555555a02e73 <+67>:    cmp    $0x1,%rbx
   0x0000555555a02e77 <+71>:    jne    0x555555a02e92 <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+98>
   0x0000555555a02e79 <+73>:    movups 0x10(%rsp),%xmm0
   0x0000555555a02e7e <+78>:    movups 0x20(%rsp),%xmm1
   0x0000555555a02e83 <+83>:    movups %xmm1,0x18(%r14)
   0x0000555555a02e88 <+88>:    movups %xmm0,0x8(%r14)
   0x0000555555a02e8d <+93>:    jmp    0x555555a03026 <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+502>
   0x0000555555a02e92 <+98>:    lea    0x328(%rsp),%rdi
   0x0000555555a02e9a <+106>:   lea    0x10(%rsp),%rsi
   0x0000555555a02e9f <+111>:   mov    $0x188,%edx
   0x0000555555a02ea4 <+116>:   call   *0x1471666(%rip)        # 0x555556e74510

590
591             if let Some(argv) = &self.argv {
   0x0000555555a02eaa <+122>:   mov    0x290(%r15),%rdx
   0x0000555555a02eb1 <+129>:   test   %rdx,%rdx
   0x0000555555a02eb4 <+132>:   je     0x555555a02efe <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+206>

/rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/alloc/src/vec/mod.rs:
2323    /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/alloc/src/vec/mod.rs: No such file or directory.
   0x0000555555a02eb6 <+134>:   mov    0x2a0(%r15),%rcx
   0x0000555555a02ebd <+141>:   lea    0x198(%rsp),%rdi
   0x0000555555a02ec5 <+149>:   lea    0x328(%rsp),%rsi

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
592                 set_argv(&mut config, argv)?;
   0x0000555555a02ecd <+157>:   call   0x555555a42790 <_ZN7pyembed18interpreter_config8set_argv17hedd5bbad1f1fa6c0E>

/rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/result.rs:
1636    /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/result.rs: No such file or directory.
   0x0000555555a02ed2 <+162>:   mov    0x198(%rsp),%rax
   0x0000555555a02eda <+170>:   movups 0x1a0(%rsp),%xmm0
   0x0000555555a02ee2 <+178>:   movaps %xmm0,0x10(%rsp)
   0x0000555555a02ee7 <+183>:   mov    0x1b0(%rsp),%rcx
   0x0000555555a02eef <+191>:   mov    %rcx,0x20(%rsp)

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
592                 set_argv(&mut config, argv)?;
   0x0000555555a02ef4 <+196>:   cmp    $0x2,%rax
   0x0000555555a02ef8 <+200>:   jne    0x555555a0300f <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+479>

/rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/option.rs:
197     /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/option.rs: No such file or directory.
   0x0000555555a02efe <+206>:   mov    (%r15),%rcx
   0x0000555555a02f01 <+209>:   test   %rcx,%rcx

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
595             if self.exe.is_none() {
   0x0000555555a02f04 <+212>:   je     0x555555a0302f <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+511>

/rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/option.rs:
197     /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/option.rs: No such file or directory.
   0x0000555555a02f0a <+218>:   cmpq   $0x0,0x18(%r15)

And the bad / 1.54.0 version:

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
585         fn try_into(self) -> Result<pyffi::PyConfig, Self::Error> {
   0x0000555555a0cff0 <+0>:     push   %r15
   0x0000555555a0cff2 <+2>:     push   %r14
   0x0000555555a0cff4 <+4>:     push   %r12
   0x0000555555a0cff6 <+6>:     push   %rbx
   0x0000555555a0cff7 <+7>:     sub    $0x4a8,%rsp
   0x0000555555a0cffe <+14>:    mov    %rsi,%rbx
   0x0000555555a0d001 <+17>:    mov    %rdi,%r14

586             // We use the raw configuration as a base then we apply any adjustments,
587             // as needed.
588             let mut config: pyffi::PyConfig =
589                 python_interpreter_config_to_py_config(&self.interpreter_config)?;
=> 0x0000555555a0d004 <+20>:    add    $0x30,%rsi
   0x0000555555a0d008 <+24>:    lea    0x8(%rsp),%rdi
   0x0000555555a0d00d <+29>:    call   0x555555a4cd00 <_ZN7pyembed18interpreter_config38python_interpreter_config_to_py_config17h8fe88207c7bebad5E>

/rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs:
1664    /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs: No such file or directory.
   0x0000555555a0d012 <+34>:    cmpl   $0x1,0x8(%rsp)
   0x0000555555a0d017 <+39>:    lea    0x10(%rsp),%rsi
   0x0000555555a0d01c <+44>:    jne    0x555555a0d04b <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+91>

1665    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
   0x0000555555a0d01e <+46>:    movups (%rsi),%xmm0
   0x0000555555a0d021 <+49>:    movups 0x10(%rsi),%xmm1
   0x0000555555a0d025 <+53>:    movaps %xmm1,0x330(%rsp)
   0x0000555555a0d02d <+61>:    movaps %xmm0,0x320(%rsp)

1666    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1667    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1668    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1669    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1670    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1671    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1672    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1673    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1674    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
1675    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
   0x0000555555a0d035 <+69>:    movups %xmm1,0x18(%r14)
   0x0000555555a0d03a <+74>:    movups %xmm0,0x8(%r14)
   0x0000555555a0d03f <+79>:    movq   $0x1,(%r14)
   0x0000555555a0d046 <+86>:    jmp    0x555555a0d1cb <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+475>
   0x0000555555a0d04b <+91>:    lea    0x320(%rsp),%r15
   0x0000555555a0d053 <+99>:    mov    0x1464446(%rip),%r12        # 0x555556e714a0

1664    in /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs
   0x0000555555a0d05a <+106>:   mov    $0x188,%edx
   0x0000555555a0d05f <+111>:   mov    %r15,%rdi
   0x0000555555a0d062 <+114>:   call   *%r12
   0x0000555555a0d065 <+117>:   lea    0x198(%rsp),%rdi

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
589                 python_interpreter_config_to_py_config(&self.interpreter_config)?;
   0x0000555555a0d06d <+125>:   mov    $0x188,%edx
   0x0000555555a0d072 <+130>:   mov    %r15,%rsi
   0x0000555555a0d075 <+133>:   call   *%r12

590
591             if let Some(argv) = &self.argv {
   0x0000555555a0d078 <+136>:   mov    0x290(%rbx),%rdx
   0x0000555555a0d07f <+143>:   test   %rdx,%rdx
   0x0000555555a0d082 <+146>:   je     0x555555a0d0ac <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+188>

/rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/alloc/src/vec/mod.rs:
2366    /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/alloc/src/vec/mod.rs: No such file or directory.
   0x0000555555a0d084 <+148>:   mov    0x2a0(%rbx),%rcx
   0x0000555555a0d08b <+155>:   lea    0x8(%rsp),%rdi
   0x0000555555a0d090 <+160>:   lea    0x198(%rsp),%rsi

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
592                 set_argv(&mut config, argv)?;
   0x0000555555a0d098 <+168>:   call   0x555555a4c8c0 <_ZN7pyembed18interpreter_config8set_argv17hbfb1f04fcddc907fE>

/rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs:
1664    /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/result.rs: No such file or directory.
   0x0000555555a0d09d <+173>:   mov    0x8(%rsp),%rax
   0x0000555555a0d0a2 <+178>:   cmp    $0x2,%rax
   0x0000555555a0d0a6 <+182>:   jne    0x555555a0d178 <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+392>

/rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:
199     /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs: No such file or directory.
   0x0000555555a0d0ac <+188>:   mov    (%rbx),%rcx
   0x0000555555a0d0af <+191>:   test   %rcx,%rcx

/home/gps/src/pyoxidizer.git/pyembed/src/interpreter_config.rs:
595             if self.exe.is_none() {
   0x0000555555a0d0b2 <+194>:   je     0x555555a0d198 <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+424>

/rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs:
199     /rustc/a178d0322ce20e33eac124758e837cbd80a6f633/library/core/src/option.rs: No such file or directory.
   0x0000555555a0d0b8 <+200>:   cmpq   $0x0,0x18(%rbx)

There are clearly differences here.

I'm not great at reading assembly, but the differences in the call to set_argv(&mut config, argv)? are perplexing me.

Here's the good version:

   0x0000555555a02eb6 <+134>:   mov    0x2a0(%r15),%rcx
   0x0000555555a02ebd <+141>:   lea    0x198(%rsp),%rdi
   0x0000555555a02ec5 <+149>:   lea    0x328(%rsp),%rsi
   0x0000555555a02ecd <+157>:   call   0x555555a42790 
   0x0000555555a02ed2 <+162>:   mov    0x198(%rsp),%rax
   0x0000555555a02eda <+170>:   movups 0x1a0(%rsp),%xmm0
   0x0000555555a02ee2 <+178>:   movaps %xmm0,0x10(%rsp)
   0x0000555555a02ee7 <+183>:   mov    0x1b0(%rsp),%rcx
   0x0000555555a02eef <+191>:   mov    %rcx,0x20(%rsp)
   0x0000555555a02ef4 <+196>:   cmp    $0x2,%rax
   0x0000555555a02ef8 <+200>:   jne    0x555555a0300f <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h749e4f0eba59cec2E+479>

And the bad:

   0x0000555555a0d084 <+148>:   mov    0x2a0(%rbx),%rcx
   0x0000555555a0d08b <+155>:   lea    0x8(%rsp),%rdi
   0x0000555555a0d090 <+160>:   lea    0x198(%rsp),%rsi
   0x0000555555a0d098 <+168>:   call   0x555555a4c8c0 <_ZN7pyembed18interpreter_config8set_argv17hbfb1f04fcddc907fE>
   0x0000555555a0d09d <+173>:   mov    0x8(%rsp),%rax
   0x0000555555a0d0a2 <+178>:   cmp    $0x2,%rax
   0x0000555555a0d0a6 <+182>:   jne    0x555555a0d178 <_ZN7pyembed18interpreter_config161_$LT$impl$u20$core..convert..TryInto$LT$pyo3..ffi..cpython..initconfig..PyConfig$GT$$u20$for$u20$$RF$pyembed..config..ResolvedOxidizedPythonInterpreterConfig$GT$8try_into17h3c0366d657e57554E+392>

We clearly see the 2 lea to %rdi and %rsi to set up the arguments. Followed by the call. But then things diverge. The bad version clearly lacks some additional moves. I'm unsure if these missing instructions are critical as part of restoring caller state or whether they shouldn't be necessary. The callee has already trampled on the register holding self at this point (%rbx). And the memory layout is quite different between these 2 functions. So I dunno.

@indygreg
Copy link
Contributor Author

I was able to isolate this down to a regression in the 2021-05-19 nightly:

  • 2021-05-15: good
  • 2021-05-16: good
  • 2021-05-17: good
  • 2021-05-18: good
  • 2021-05-19: bad
  • 2021-05-20: bad
  • 2021-05-21: bad

That means the regression range is somewhere between 3e99439..4e3e6db.

@glandium
Copy link
Contributor

cargo-bisect-rustc should be able to pin that down to a merge commit. https://github.com/rust-lang/cargo-bisect-rustc/blob/master/TUTORIAL.md

@indygreg
Copy link
Contributor Author

cargo-bisect-rustc identified commit 4e3e6db (#84767) as the cause of the regression. The previous toolchain (491cf55) works just fine.

I can probably work on simpler steps to reproduce. Let me know.

cc @scottmcm

@indygreg
Copy link
Contributor Author

I am able to reproduce the issue with cargo +nightly-2021-05-19 rustc --release --features allocator-jemalloc -- --C llvm-args=-opt-bisect-limit=0. I think what this is doing is bypassing LLVM's optimization passes, effectively testing the LLVM IR that rustc emits, and in this case isolating this to an LLVM IR emission bug in rustc, not an LLVM optimization error?

Strangely, cargo +nightly-2021-05-19 rustc --release --features allocator-jemalloc -- -C no-prepopulate-passes (which I think is the preferred way to turn off LLVM IR optimization passes) fails:

error: could not compile `myapp`

Caused by:
  process didn't exit successfully: `rustc --crate-name myapp --edition=2018 src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C opt-level=3 -C embed-bitcode=no -C debuginfo=2 -C no-prepopulate-passes --cfg 'feature="allocator-jemalloc"' --cfg 'feature="build-mode-pyoxidizer-exe"' --cfg 'feature="default"' -C metadata=d92e577e2d36bc93 -C extra-filename=-d92e577e2d36bc93 --out-dir /home/gps/tmp/myapp/target/release/deps -L dependency=/home/gps/tmp/myapp/target/release/deps --extern pyembed=/home/gps/tmp/myapp/target/release/deps/libpyembed-846f76a23fec60bf.rlib -C link-args=-Wl,-export-dynamic -L native=/tmp/pyoxidizer-build-exe-packaging7UiBSc -L native=/home/gps/.cache/pyoxidizer/python_distributions/python.343e2d349779/python/build/lib -L native=/home/gps/tmp/myapp/build/x86_64-unknown-linux-gnu/release/resources -L native=/home/gps/tmp/myapp/target/release/build/jemalloc-sys-e62986af855335b6/out/build/lib -L native=/home/gps/.pyenv/versions/3.9.6/lib` (signal: 11, SIGSEGV: invalid memory reference)

If someone tells me how to get rustc to --emit files from crates that aren't the main crate being compiled, I can diff the output and try to isolate the regression. But when I run commands like cargo rustc -- -Z no-parallel-llvm -C llvm-args=-print-after-all -Z symbol-mangling-version=v0 it appears the output only contains symbols for the main crate being built. Unfortunately, the bad assembly is in a dependency crate.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Aug 12, 2021

That PR introduces a MIR pass. Maybe try -Z mir-opt-level=0 to see if bad codegen persists?

EDIT: It looks like that only MIR tests are modified, there are no new MIR passes.

@indygreg
Copy link
Contributor Author

Oh, I realized that when building with cargo I need to use RUSTFLAGS + cargo build instead of cargo rustc to get rustc options (like --emit=mir) to work for all creates. I should be able to get some useful data soon...

Also, thanks for that -Z mir-opt-level=0 suggestion: I'll try that.

@indygreg
Copy link
Contributor Author

My earlier assertion about cargo +nightly-2021-05-19 rustc --release --features allocator-jemalloc -- --C llvm-args=-opt-bisect-limit=0 implying this was a rustc IR emission issue appears to be incorrect: that command was only impacting compilation of the main crate, not the crate that was being miscompiled.

I'm able to reproduce the issue with RUSTFLAGS="-Z mir-opt-level=0" cargo +nightly-2021-05-19 build --release --features allocator-jemalloc.

I suspect this is an LLVM IR optimization bug because:

  • good: RUSTFLAGS="-Z symbol-mangling-version=v0 -Z no-parallel-llvm -C llvm-args=-opt-bisect-limit=0" cargo +nightly-2021-05-19 build --release --features allocator-jemalloc
  • bad: RUSTFLAGS="-Z symbol-mangling-version=v0 -Z no-parallel-llvm -C llvm-args=-opt-bisect-limit=20000000" cargo +nightly-2021-05-19 build --release --features allocator-jemalloc

Give me time to bisect the exact pass, as there are a lot of them...

If anyone has any tricks to make this easier, I'm all ears.

@indygreg
Copy link
Contributor Author

I'm having difficulty getting reliable results bisecting the LLVM optimization passes. I suspect this is due to something non-deterministic in LLVM? Anyone have any pointers?

Also, the bug goes away with -C codegen-units=2 or lower. RUSTFLAGS="-Z symbol-mangling-version=v0 -Z no-parallel-llvm -C codegen-units=3" cargo +nightly-2021-05-19 build --release --features allocator-jemalloc still reproduces.

@indygreg
Copy link
Contributor Author

Well, it looks like the rustc emits quite different LLVM IR between these 2 nightlies, even before it goes into LLVM optimization passes.

nightly-2021-05-18:

*** IR Dump After Instrument function entry/exit with calls to e.g. mcount() (pre inlining) ***
; Function Attrs: nonlazybind uwtable
define void @_RNvXs_NtCsijNWNMdNqoj_7pyembed18interpreter_configRNtNtB6_6config39ResolvedOxidizedPythonInterpreterConfigINtNtCskrsM4FCwAVA_4core7convert7TryIntoNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigE8try_into(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1) unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality !dbg !78453 {
  %3 = alloca %"std::path::PathBuf"*, align 8
  %4 = alloca %"std::vec::Vec<std::ffi::OsString>"*, align 8
  %5 = alloca { i8*, i32 }, align 8
  %6 = alloca {}, align 1
  %7 = alloca {}, align 1
  %8 = alloca {}, align 1
  %9 = alloca %"config::ResolvedOxidizedPythonInterpreterConfig"*, align 8
  %10 = alloca %"pyo3::ffi::PyConfig", align 8
  %11 = alloca %"error::NewInterpreterError", align 8
  %12 = alloca %"error::NewInterpreterError", align 8
  %13 = alloca %"error::NewInterpreterError", align 8
  %14 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %15 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %16 = alloca %"error::NewInterpreterError", align 8
  %17 = alloca %"error::NewInterpreterError", align 8
  %18 = alloca %"error::NewInterpreterError", align 8
  %19 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %20 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %21 = alloca {}, align 1
  %22 = alloca {}, align 1
  %23 = alloca %"std::path::PathBuf"*, align 8
  %24 = alloca %"error::NewInterpreterError", align 8
  %25 = alloca %"error::NewInterpreterError", align 8
  %26 = alloca %"error::NewInterpreterError", align 8
  %27 = alloca %"error::NewInterpreterError", align 8
  %28 = alloca %"error::NewInterpreterError", align 8
  %29 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %30 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %31 = alloca {}, align 1
  %32 = alloca %"pyo3::ffi::PyConfig", align 8
  %33 = alloca %"error::NewInterpreterError", align 8
  %34 = alloca %"error::NewInterpreterError", align 8
  %35 = alloca %"error::NewInterpreterError", align 8
  %36 = alloca %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>", align 8
  %37 = alloca %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>", align 8
  %38 = alloca %"pyo3::ffi::PyConfig", align 8
  store %"config::ResolvedOxidizedPythonInterpreterConfig"* %1, %"config::ResolvedOxidizedPythonInterpreterConfig"** %9, align 8
  call void @llvm.dbg.declare(metadata %"config::ResolvedOxidizedPythonInterpreterConfig"** %9, metadata !78457, metadata !DIExpression()), !dbg !78482
  call void @llvm.dbg.declare(metadata %"pyo3::ffi::PyConfig"* %38, metadata !78458, metadata !DIExpression()), !dbg !78483
  call void @llvm.dbg.declare(metadata %"error::NewInterpreterError"* %35, metadata !78460, metadata !DIExpression()), !dbg !78484
  call void @llvm.dbg.declare(metadata %"pyo3::ffi::PyConfig"* %32, metadata !78462, metadata !DIExpression()), !dbg !78485
  call void @llvm.dbg.declare(metadata %"error::NewInterpreterError"* %28, metadata !78466, metadata !DIExpression()), !dbg !78486
  call void @llvm.dbg.declare(metadata {}* %8, metadata !78468, metadata !DIExpression()), !dbg !78487
  call void @llvm.dbg.declare(metadata %"std::path::PathBuf"** %23, metadata !78470, metadata !DIExpression()), !dbg !78488
  call void @llvm.dbg.declare(metadata %"error::NewInterpreterError"* %18, metadata !78474, metadata !DIExpression()), !dbg !78489
  call void @llvm.dbg.declare(metadata {}* %7, metadata !78476, metadata !DIExpression()), !dbg !78490
  call void @llvm.dbg.declare(metadata %"error::NewInterpreterError"* %13, metadata !78478, metadata !DIExpression()), !dbg !78491
  call void @llvm.dbg.declare(metadata {}* %6, metadata !78480, metadata !DIExpression()), !dbg !78492
  %39 = bitcast %"pyo3::ffi::PyConfig"* %38 to i8*, !dbg !78493
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %39), !dbg !78493
  %40 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i8*, !dbg !78494
  call void @llvm.lifetime.start.p0i8(i64 400, i8* %40), !dbg !78494
  %41 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %36 to i8*, !dbg !78494
  call void @llvm.lifetime.start.p0i8(i64 400, i8* %41), !dbg !78494
  %42 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78495
  br label %43, !dbg !78495

43:                                               ; preds = %2
  %44 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %42, i32 0, i32 5, !dbg !78496
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config38python_interpreter_config_to_py_config(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %36, %"python_packaging::interpreter::PythonInterpreterConfig"* noalias readonly align 8 dereferenceable(560) %44), !dbg !78494
  br label %45, !dbg !78494

45:                                               ; preds = %43
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try11into_resultB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %37, %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture dereferenceable(400) %36)
          to label %46 unwind label %58, !dbg !78494

46:                                               ; preds = %45
  %47 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %36 to i8*, !dbg !78494
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %47), !dbg !78494
  %48 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i64*, !dbg !78497
  %49 = load i64, i64* %48, align 8, !dbg !78497, !range !2867
  switch i64 %49, label %65 [
    i64 0, label %66
    i64 1, label %79
  ], !dbg !78497

50:                                               ; preds = %349, %281, %156, %91, %58
  %51 = bitcast { i8*, i32 }* %5 to i8**, !dbg !78498
  %52 = load i8*, i8** %51, align 8, !dbg !78498
  %53 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1, !dbg !78498
  %54 = load i32, i32* %53, align 8, !dbg !78498
  %55 = bitcast { i8*, i32 }* %5 to i8*, !dbg !78498
  call void @llvm.lifetime.end.p0i8(i64 16, i8* %55), !dbg !78498
  %56 = insertvalue { i8*, i32 } undef, i8* %52, 0, !dbg !78498
  %57 = insertvalue { i8*, i32 } %56, i32 %54, 1, !dbg !78498
  resume { i8*, i32 } %57, !dbg !78498

58:                                               ; preds = %321, %253, %128, %45
  %59 = landingpad { i8*, i32 }
          cleanup
  %60 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %60)
  %61 = extractvalue { i8*, i32 } %59, 0
  %62 = extractvalue { i8*, i32 } %59, 1
  %63 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %61, i8** %63, align 8
  %64 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %62, i32* %64, align 8
  br label %50

65:                                               ; preds = %46
  unreachable, !dbg !78494

66:                                               ; preds = %46
  %67 = bitcast %"pyo3::ffi::PyConfig"* %32 to i8*, !dbg !78494
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %67), !dbg !78494
  %68 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"*, !dbg !78494
  %69 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"* %68, i32 0, i32 1, !dbg !78494
  %70 = bitcast %"pyo3::ffi::PyConfig"* %32 to i8*, !dbg !78494
  %71 = bitcast %"pyo3::ffi::PyConfig"* %69 to i8*, !dbg !78494
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %70, i8* align 8 %71, i64 392, i1 false), !dbg !78494
  %72 = bitcast %"pyo3::ffi::PyConfig"* %38 to i8*, !dbg !78485
  %73 = bitcast %"pyo3::ffi::PyConfig"* %32 to i8*, !dbg !78485
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %72, i8* align 8 %73, i64 392, i1 false), !dbg !78485
  %74 = bitcast %"pyo3::ffi::PyConfig"* %32 to i8*, !dbg !78497
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %74), !dbg !78497
  %75 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i64*, !dbg !78499
  %76 = load i64, i64* %75, align 8, !dbg !78499, !range !2867
  %77 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i8*, !dbg !78499
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %77), !dbg !78499
  %78 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78500
  br label %109, !dbg !78500

79:                                               ; preds = %46
  %80 = bitcast %"error::NewInterpreterError"* %35 to i8*, !dbg !78497
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %80), !dbg !78497
  %81 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"*, !dbg !78497
  %82 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"* %81, i32 0, i32 1, !dbg !78497
  %83 = bitcast %"error::NewInterpreterError"* %35 to i8*, !dbg !78497
  %84 = bitcast %"error::NewInterpreterError"* %82 to i8*, !dbg !78497
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %83, i8* align 8 %84, i64 32, i1 false), !dbg !78497
  %85 = bitcast %"error::NewInterpreterError"* %34 to i8*, !dbg !78484
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %85), !dbg !78484
  %86 = bitcast %"error::NewInterpreterError"* %33 to i8*, !dbg !78484
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %86), !dbg !78484
  %87 = bitcast %"error::NewInterpreterError"* %33 to i8*, !dbg !78484
  %88 = bitcast %"error::NewInterpreterError"* %35 to i8*, !dbg !78484
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %87, i8* align 8 %88, i64 32, i1 false), !dbg !78484
  invoke void @_RNvXs2_NtCskrsM4FCwAVA_4core7convertNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorINtB5_4FromBy_E4fromBC_(%"error::NewInterpreterError"* noalias nocapture sret(%"error::NewInterpreterError") dereferenceable(32) %34, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %33)
          to label %89 unwind label %94, !dbg !78484

89:                                               ; preds = %79
  %90 = bitcast %"error::NewInterpreterError"* %33 to i8*, !dbg !78484
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %90), !dbg !78484
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try10from_errorB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %34)
          to label %101 unwind label %94, !dbg !78501

91:                                               ; preds = %94
  %92 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i64*, !dbg !78499
  %93 = load i64, i64* %92, align 8, !dbg !78499, !range !2867
  br label %50, !dbg !78499

94:                                               ; preds = %89, %79
  %95 = landingpad { i8*, i32 }
          cleanup
  %96 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %96)
  %97 = extractvalue { i8*, i32 } %95, 0
  %98 = extractvalue { i8*, i32 } %95, 1
  %99 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %97, i8** %99, align 8
  %100 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %98, i32* %100, align 8
  br label %91

101:                                              ; preds = %89
  %102 = bitcast %"error::NewInterpreterError"* %34 to i8*, !dbg !78501
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %102), !dbg !78501
  %103 = bitcast %"error::NewInterpreterError"* %35 to i8*, !dbg !78497
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %103), !dbg !78497
  %104 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i64*, !dbg !78499
  %105 = load i64, i64* %104, align 8, !dbg !78499, !range !2867
  %106 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %37 to i8*, !dbg !78499
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %106), !dbg !78499
  br label %107, !dbg !78502

107:                                              ; preds = %303, %204, %184, %169, %101
  %108 = bitcast %"pyo3::ffi::PyConfig"* %38 to i8*, !dbg !78504
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %108), !dbg !78504
  br label %371, !dbg !78505

109:                                              ; preds = %66
  %110 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %78, i32 0, i32 11, !dbg !78506
  %111 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>"* %110 to {}**, !dbg !78507
  %112 = load {}*, {}** %111, align 8, !dbg !78507
  %113 = icmp eq {}* %112, null, !dbg !78507
  %114 = select i1 %113, i64 0, i64 1, !dbg !78507
  %115 = icmp eq i64 %114, 1, !dbg !78507
  br i1 %115, label %116, label %124, !dbg !78507

116:                                              ; preds = %109
  %117 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>"* %110 to %"std::option::Option<std::vec::Vec<std::ffi::OsString>>::Some"*, !dbg !78508
  %118 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>::Some"* %117 to %"std::vec::Vec<std::ffi::OsString>"*, !dbg !78508
  store %"std::vec::Vec<std::ffi::OsString>"* %118, %"std::vec::Vec<std::ffi::OsString>"** %4, align 8, !dbg !78508
  call void @llvm.dbg.declare(metadata %"std::vec::Vec<std::ffi::OsString>"** %4, metadata !78464, metadata !DIExpression()), !dbg !78509
  %119 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i8*, !dbg !78510
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %119), !dbg !78510
  %120 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %29 to i8*, !dbg !78510
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %120), !dbg !78510
  %121 = call { [0 x %"std::ffi::OsString"]*, i64 } @_RNvXs8_NtCshECKBmVgND8_5alloc3vecINtB5_3VecNtNtNtCsahqMUB7vfgm_3std3ffi6os_str8OsStringENtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5derefCsijNWNMdNqoj_7pyembed(%"std::vec::Vec<std::ffi::OsString>"* noalias readonly align 8 dereferenceable(24) %118), !dbg !78511
  %122 = extractvalue { [0 x %"std::ffi::OsString"]*, i64 } %121, 0, !dbg !78511
  %123 = extractvalue { [0 x %"std::ffi::OsString"]*, i64 } %121, 1, !dbg !78511
  br label %127, !dbg !78511

124:                                              ; preds = %109
  br label %125, !dbg !78512

125:                                              ; preds = %137, %124
  %126 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78513
  br label %178, !dbg !78513

127:                                              ; preds = %116
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config8set_argv(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %29, %"pyo3::ffi::PyConfig"* noalias align 8 dereferenceable(392) %38, [0 x %"std::ffi::OsString"]* noalias nonnull readonly align 8 %122, i64 %123), !dbg !78510
  br label %128, !dbg !78510

128:                                              ; preds = %127
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try11into_resultBP_(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %30, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %29)
          to label %129 unwind label %58, !dbg !78510

129:                                              ; preds = %128
  %130 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %29 to i8*, !dbg !78510
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %130), !dbg !78510
  %131 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i64*, !dbg !78514
  %132 = load i64, i64* %131, align 8, !dbg !78514, !range !29786
  %133 = sub i64 %132, 2, !dbg !78514
  %134 = icmp eq i64 %133, 0, !dbg !78514
  %135 = select i1 %134, i64 0, i64 1, !dbg !78514
  switch i64 %135, label %136 [
    i64 0, label %137
    i64 1, label %144
  ], !dbg !78514

136:                                              ; preds = %129
  unreachable, !dbg !78510

137:                                              ; preds = %129
  %138 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i64*, !dbg !78515
  %139 = load i64, i64* %138, align 8, !dbg !78515, !range !29786
  %140 = sub i64 %139, 2, !dbg !78515
  %141 = icmp eq i64 %140, 0, !dbg !78515
  %142 = select i1 %141, i64 0, i64 1, !dbg !78515
  %143 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i8*, !dbg !78515
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %143), !dbg !78515
  br label %125, !dbg !78512

144:                                              ; preds = %129
  %145 = bitcast %"error::NewInterpreterError"* %28 to i8*, !dbg !78514
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %145), !dbg !78514
  %146 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to %"std::result::Result<(), error::NewInterpreterError>::Err"*, !dbg !78514
  %147 = bitcast %"std::result::Result<(), error::NewInterpreterError>::Err"* %146 to %"error::NewInterpreterError"*, !dbg !78514
  %148 = bitcast %"error::NewInterpreterError"* %28 to i8*, !dbg !78514
  %149 = bitcast %"error::NewInterpreterError"* %147 to i8*, !dbg !78514
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %148, i8* align 8 %149, i64 32, i1 false), !dbg !78514
  %150 = bitcast %"error::NewInterpreterError"* %27 to i8*, !dbg !78486
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %150), !dbg !78486
  %151 = bitcast %"error::NewInterpreterError"* %26 to i8*, !dbg !78486
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %151), !dbg !78486
  %152 = bitcast %"error::NewInterpreterError"* %26 to i8*, !dbg !78486
  %153 = bitcast %"error::NewInterpreterError"* %28 to i8*, !dbg !78486
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %152, i8* align 8 %153, i64 32, i1 false), !dbg !78486
  invoke void @_RNvXs2_NtCskrsM4FCwAVA_4core7convertNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorINtB5_4FromBy_E4fromBC_(%"error::NewInterpreterError"* noalias nocapture sret(%"error::NewInterpreterError") dereferenceable(32) %27, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %26)
          to label %154 unwind label %162, !dbg !78486

154:                                              ; preds = %144
  %155 = bitcast %"error::NewInterpreterError"* %26 to i8*, !dbg !78486
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %155), !dbg !78486
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try10from_errorB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %27)
          to label %169 unwind label %162, !dbg !78516

156:                                              ; preds = %162
  %157 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i64*, !dbg !78515
  %158 = load i64, i64* %157, align 8, !dbg !78515, !range !29786
  %159 = sub i64 %158, 2, !dbg !78515
  %160 = icmp eq i64 %159, 0, !dbg !78515
  %161 = select i1 %160, i64 0, i64 1, !dbg !78515
  br label %50, !dbg !78515

162:                                              ; preds = %154, %144
  %163 = landingpad { i8*, i32 }
          cleanup
  %164 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %164)
  %165 = extractvalue { i8*, i32 } %163, 0
  %166 = extractvalue { i8*, i32 } %163, 1
  %167 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %165, i8** %167, align 8
  %168 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %166, i32* %168, align 8
  br label %156

169:                                              ; preds = %154
  %170 = bitcast %"error::NewInterpreterError"* %27 to i8*, !dbg !78516
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %170), !dbg !78516
  %171 = bitcast %"error::NewInterpreterError"* %28 to i8*, !dbg !78514
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %171), !dbg !78514
  %172 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i64*, !dbg !78515
  %173 = load i64, i64* %172, align 8, !dbg !78515, !range !29786
  %174 = sub i64 %173, 2, !dbg !78515
  %175 = icmp eq i64 %174, 0, !dbg !78515
  %176 = select i1 %175, i64 0, i64 1, !dbg !78515
  %177 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %30 to i8*, !dbg !78515
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %177), !dbg !78515
  br label %107, !dbg !78517

178:                                              ; preds = %125
  %179 = bitcast %"config::OxidizedPythonInterpreterConfig"* %126 to %"std::option::Option<std::path::PathBuf>"*, !dbg !78513
  %180 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %179), !dbg !78513
  br label %181, !dbg !78513

181:                                              ; preds = %178
  br i1 %180, label %184, label %182, !dbg !78519

182:                                              ; preds = %181
  %183 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78520
  br label %197, !dbg !78520

184:                                              ; preds = %181
  %185 = bitcast %"error::NewInterpreterError"* %25 to i8*, !dbg !78521
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %185), !dbg !78521
  %186 = bitcast %"error::NewInterpreterError"* %25 to %"error::NewInterpreterError::Simple"*, !dbg !78521
  %187 = getelementptr inbounds %"error::NewInterpreterError::Simple", %"error::NewInterpreterError::Simple"* %186, i32 0, i32 1, !dbg !78521
  %188 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %187, i32 0, i32 0, !dbg !78521
  store [0 x i8]* bitcast (<{ [57 x i8] }>* @293 to [0 x i8]*), [0 x i8]** %188, align 8, !dbg !78521
  %189 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %187, i32 0, i32 1, !dbg !78521
  store i64 57, i64* %189, align 8, !dbg !78521
  %190 = bitcast %"error::NewInterpreterError"* %25 to i64*, !dbg !78521
  store i64 0, i64* %190, align 8, !dbg !78521
  %191 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"*, !dbg !78522
  %192 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"* %191, i32 0, i32 1, !dbg !78522
  %193 = bitcast %"error::NewInterpreterError"* %192 to i8*, !dbg !78522
  %194 = bitcast %"error::NewInterpreterError"* %25 to i8*, !dbg !78522
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %193, i8* align 8 %194, i64 32, i1 false), !dbg !78522
  %195 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !78522
  store i64 1, i64* %195, align 8, !dbg !78522
  %196 = bitcast %"error::NewInterpreterError"* %25 to i8*, !dbg !78523
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %196), !dbg !78523
  br label %107, !dbg !78517

197:                                              ; preds = %182
  %198 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %183, i32 0, i32 3, !dbg !78520
  %199 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %198), !dbg !78520
  br label %200, !dbg !78520

200:                                              ; preds = %197
  br i1 %199, label %204, label %201, !dbg !78524

201:                                              ; preds = %200
  %202 = bitcast %"std::path::PathBuf"** %23 to i8*, !dbg !78525
  call void @llvm.lifetime.start.p0i8(i64 8, i8* %202), !dbg !78525
  %203 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78526
  br label %217, !dbg !78526

204:                                              ; preds = %200
  %205 = bitcast %"error::NewInterpreterError"* %24 to i8*, !dbg !78527
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %205), !dbg !78527
  %206 = bitcast %"error::NewInterpreterError"* %24 to %"error::NewInterpreterError::Simple"*, !dbg !78527
  %207 = getelementptr inbounds %"error::NewInterpreterError::Simple", %"error::NewInterpreterError::Simple"* %206, i32 0, i32 1, !dbg !78527
  %208 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %207, i32 0, i32 0, !dbg !78527
  store [0 x i8]* bitcast (<{ [45 x i8] }>* @294 to [0 x i8]*), [0 x i8]** %208, align 8, !dbg !78527
  %209 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %207, i32 0, i32 1, !dbg !78527
  store i64 45, i64* %209, align 8, !dbg !78527
  %210 = bitcast %"error::NewInterpreterError"* %24 to i64*, !dbg !78527
  store i64 0, i64* %210, align 8, !dbg !78527
  %211 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"*, !dbg !78528
  %212 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"* %211, i32 0, i32 1, !dbg !78528
  %213 = bitcast %"error::NewInterpreterError"* %212 to i8*, !dbg !78528
  %214 = bitcast %"error::NewInterpreterError"* %24 to i8*, !dbg !78528
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %213, i8* align 8 %214, i64 32, i1 false), !dbg !78528
  %215 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !78528
  store i64 1, i64* %215, align 8, !dbg !78528
  %216 = bitcast %"error::NewInterpreterError"* %24 to i8*, !dbg !78529
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %216), !dbg !78529
  br label %107, !dbg !78517

217:                                              ; preds = %201
  %218 = bitcast %"config::OxidizedPythonInterpreterConfig"* %203 to %"std::option::Option<std::path::PathBuf>"*, !dbg !78526
  %219 = call align 8 dereferenceable_or_null(24) i64* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE6as_refCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %218), !dbg !78526
  br label %220, !dbg !78526

220:                                              ; preds = %217
  %221 = call align 8 dereferenceable(24) %"std::path::PathBuf"* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionRNtNtCsahqMUB7vfgm_3std4path7PathBufE6unwrapCsijNWNMdNqoj_7pyembed(i64* noalias readonly align 8 dereferenceable_or_null(24) %219, %"std::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @296 to %"std::panic::Location"*)), !dbg !78526
  store %"std::path::PathBuf"* %221, %"std::path::PathBuf"** %23, align 8, !dbg !78526
  br label %222, !dbg !78526

222:                                              ; preds = %220
  %223 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78530
  br label %224, !dbg !78530

224:                                              ; preds = %222
  %225 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %223, i32 0, i32 3, !dbg !78530
  %226 = call align 8 dereferenceable_or_null(24) i64* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE6as_refCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %225), !dbg !78530
  br label %227, !dbg !78530

227:                                              ; preds = %224
  %228 = call align 8 dereferenceable(24) %"std::path::PathBuf"* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionRNtNtCsahqMUB7vfgm_3std4path7PathBufE6unwrapCsijNWNMdNqoj_7pyembed(i64* noalias readonly align 8 dereferenceable_or_null(24) %226, %"std::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @297 to %"std::panic::Location"*)), !dbg !78530
  store %"std::path::PathBuf"* %228, %"std::path::PathBuf"** %3, align 8, !dbg !78530
  call void @llvm.dbg.declare(metadata %"std::path::PathBuf"** %3, metadata !78472, metadata !DIExpression()), !dbg !78531
  br label %229, !dbg !78530

229:                                              ; preds = %227
  %230 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78532
  br label %231, !dbg !78532

231:                                              ; preds = %229
  %232 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %230, i32 0, i32 31, !dbg !78532
  %233 = load i8, i8* %232, align 2, !dbg !78532, !range !7200
  %234 = trunc i8 %233 to i1, !dbg !78532
  br i1 %234, label %236, label %235, !dbg !78533

235:                                              ; preds = %231
  br label %373, !dbg !78533

236:                                              ; preds = %231
  %237 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78534
  br label %238, !dbg !78534

238:                                              ; preds = %236
  %239 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %237, i32 0, i32 5, !dbg !78534
  %240 = getelementptr inbounds %"python_packaging::interpreter::PythonInterpreterConfig", %"python_packaging::interpreter::PythonInterpreterConfig"* %239, i32 0, i32 25, !dbg !78534
  %241 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %240), !dbg !78534
  br label %242, !dbg !78534

242:                                              ; preds = %238
  br i1 %241, label %244, label %243, !dbg !78535

243:                                              ; preds = %242
  br label %305, !dbg !78535

244:                                              ; preds = %242
  %245 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i8*, !dbg !78536
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %245), !dbg !78536
  %246 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %19 to i8*, !dbg !78536
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %246), !dbg !78536
  %247 = getelementptr inbounds %"pyo3::ffi::PyConfig", %"pyo3::ffi::PyConfig"* %38, i32 0, i32 39, !dbg !78537
  %248 = load %"std::path::PathBuf"*, %"std::path::PathBuf"** %23, align 8, !dbg !78538, !nonnull !4
  %249 = call { %"std::path::Path"*, i64 } @"_ZN62_$LT$std..path..PathBuf$u20$as$u20$core..ops..deref..Deref$GT$5deref17he7f3f920ba1b2649E"(%"std::path::PathBuf"* noalias readonly align 8 dereferenceable(24) %248), !dbg !78538
  %250 = extractvalue { %"std::path::Path"*, i64 } %249, 0, !dbg !78538
  %251 = extractvalue { %"std::path::Path"*, i64 } %249, 1, !dbg !78538
  br label %252, !dbg !78538

252:                                              ; preds = %244
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config27set_config_string_from_path(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %19, %"pyo3::ffi::PyConfig"* noalias readonly align 8 dereferenceable(392) %38, i32** noalias readonly align 8 dereferenceable(8) %247, %"std::path::Path"* noalias nonnull readonly align 1 %250, i64 %251, [0 x i8]* noalias nonnull readonly align 1 bitcast (<{ [20 x i8] }>* @298 to [0 x i8]*), i64 20), !dbg !78536
  br label %253, !dbg !78536

253:                                              ; preds = %252
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try11into_resultBP_(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %20, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %19)
          to label %254 unwind label %58, !dbg !78536

254:                                              ; preds = %253
  %255 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %19 to i8*, !dbg !78536
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %255), !dbg !78536
  %256 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i64*, !dbg !78539
  %257 = load i64, i64* %256, align 8, !dbg !78539, !range !29786
  %258 = sub i64 %257, 2, !dbg !78539
  %259 = icmp eq i64 %258, 0, !dbg !78539
  %260 = select i1 %259, i64 0, i64 1, !dbg !78539
  switch i64 %260, label %261 [
    i64 0, label %262
    i64 1, label %269
  ], !dbg !78539

261:                                              ; preds = %254
  unreachable, !dbg !78536

262:                                              ; preds = %254
  %263 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i64*, !dbg !78540
  %264 = load i64, i64* %263, align 8, !dbg !78540, !range !29786
  %265 = sub i64 %264, 2, !dbg !78540
  %266 = icmp eq i64 %265, 0, !dbg !78540
  %267 = select i1 %266, i64 0, i64 1, !dbg !78540
  %268 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i8*, !dbg !78540
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %268), !dbg !78540
  br label %305, !dbg !78535

269:                                              ; preds = %254
  %270 = bitcast %"error::NewInterpreterError"* %18 to i8*, !dbg !78539
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %270), !dbg !78539
  %271 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to %"std::result::Result<(), error::NewInterpreterError>::Err"*, !dbg !78539
  %272 = bitcast %"std::result::Result<(), error::NewInterpreterError>::Err"* %271 to %"error::NewInterpreterError"*, !dbg !78539
  %273 = bitcast %"error::NewInterpreterError"* %18 to i8*, !dbg !78539
  %274 = bitcast %"error::NewInterpreterError"* %272 to i8*, !dbg !78539
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %273, i8* align 8 %274, i64 32, i1 false), !dbg !78539
  %275 = bitcast %"error::NewInterpreterError"* %17 to i8*, !dbg !78489
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %275), !dbg !78489
  %276 = bitcast %"error::NewInterpreterError"* %16 to i8*, !dbg !78489
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %276), !dbg !78489
  %277 = bitcast %"error::NewInterpreterError"* %16 to i8*, !dbg !78489
  %278 = bitcast %"error::NewInterpreterError"* %18 to i8*, !dbg !78489
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %277, i8* align 8 %278, i64 32, i1 false), !dbg !78489
  invoke void @_RNvXs2_NtCskrsM4FCwAVA_4core7convertNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorINtB5_4FromBy_E4fromBC_(%"error::NewInterpreterError"* noalias nocapture sret(%"error::NewInterpreterError") dereferenceable(32) %17, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %16)
          to label %279 unwind label %287, !dbg !78489

279:                                              ; preds = %269
  %280 = bitcast %"error::NewInterpreterError"* %16 to i8*, !dbg !78489
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %280), !dbg !78489
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try10from_errorB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %17)
          to label %294 unwind label %287, !dbg !78541

281:                                              ; preds = %287
  %282 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i64*, !dbg !78540
  %283 = load i64, i64* %282, align 8, !dbg !78540, !range !29786
  %284 = sub i64 %283, 2, !dbg !78540
  %285 = icmp eq i64 %284, 0, !dbg !78540
  %286 = select i1 %285, i64 0, i64 1, !dbg !78540
  br label %50, !dbg !78540

287:                                              ; preds = %279, %269
  %288 = landingpad { i8*, i32 }
          cleanup
  %289 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %289)
  %290 = extractvalue { i8*, i32 } %288, 0
  %291 = extractvalue { i8*, i32 } %288, 1
  %292 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %290, i8** %292, align 8
  %293 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %291, i32* %293, align 8
  br label %281

294:                                              ; preds = %279
  %295 = bitcast %"error::NewInterpreterError"* %17 to i8*, !dbg !78541
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %295), !dbg !78541
  %296 = bitcast %"error::NewInterpreterError"* %18 to i8*, !dbg !78539
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %296), !dbg !78539
  %297 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i64*, !dbg !78540
  %298 = load i64, i64* %297, align 8, !dbg !78540, !range !29786
  %299 = sub i64 %298, 2, !dbg !78540
  %300 = icmp eq i64 %299, 0, !dbg !78540
  %301 = select i1 %300, i64 0, i64 1, !dbg !78540
  %302 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %20 to i8*, !dbg !78540
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %302), !dbg !78540
  br label %303, !dbg !78542

303:                                              ; preds = %362, %294
  %304 = bitcast %"std::path::PathBuf"** %23 to i8*, !dbg !78544
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %304), !dbg !78544
  br label %107, !dbg !78517

305:                                              ; preds = %243, %262
  %306 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !78545
  br label %307, !dbg !78545

307:                                              ; preds = %305
  %308 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %306, i32 0, i32 5, !dbg !78545
  %309 = getelementptr inbounds %"python_packaging::interpreter::PythonInterpreterConfig", %"python_packaging::interpreter::PythonInterpreterConfig"* %308, i32 0, i32 19, !dbg !78545
  %310 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %309), !dbg !78545
  br label %311, !dbg !78545

311:                                              ; preds = %307
  br i1 %310, label %313, label %312, !dbg !78546

312:                                              ; preds = %311
  br label %372, !dbg !78546

313:                                              ; preds = %311
  %314 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i8*, !dbg !78547
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %314), !dbg !78547
  %315 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %14 to i8*, !dbg !78547
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %315), !dbg !78547
  %316 = getelementptr inbounds %"pyo3::ffi::PyConfig", %"pyo3::ffi::PyConfig"* %38, i32 0, i32 79, !dbg !78548
  %317 = call { %"std::path::Path"*, i64 } @"_ZN62_$LT$std..path..PathBuf$u20$as$u20$core..ops..deref..Deref$GT$5deref17he7f3f920ba1b2649E"(%"std::path::PathBuf"* noalias readonly align 8 dereferenceable(24) %228), !dbg !78549
  %318 = extractvalue { %"std::path::Path"*, i64 } %317, 0, !dbg !78549
  %319 = extractvalue { %"std::path::Path"*, i64 } %317, 1, !dbg !78549
  br label %320, !dbg !78549

320:                                              ; preds = %313
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config27set_config_string_from_path(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %14, %"pyo3::ffi::PyConfig"* noalias readonly align 8 dereferenceable(392) %38, i32** noalias readonly align 8 dereferenceable(8) %316, %"std::path::Path"* noalias nonnull readonly align 1 %318, i64 %319, [0 x i8]* noalias nonnull readonly align 1 bitcast (<{ [12 x i8] }>* @299 to [0 x i8]*), i64 12), !dbg !78547
  br label %321, !dbg !78547

321:                                              ; preds = %320
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try11into_resultBP_(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %15, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %14)
          to label %322 unwind label %58, !dbg !78547

322:                                              ; preds = %321
  %323 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %14 to i8*, !dbg !78547
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %323), !dbg !78547
  %324 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i64*, !dbg !78550
  %325 = load i64, i64* %324, align 8, !dbg !78550, !range !29786
  %326 = sub i64 %325, 2, !dbg !78550
  %327 = icmp eq i64 %326, 0, !dbg !78550
  %328 = select i1 %327, i64 0, i64 1, !dbg !78550
  switch i64 %328, label %329 [
    i64 0, label %330
    i64 1, label %337
  ], !dbg !78550

329:                                              ; preds = %322
  unreachable, !dbg !78547

330:                                              ; preds = %322
  %331 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i64*, !dbg !78551
  %332 = load i64, i64* %331, align 8, !dbg !78551, !range !29786
  %333 = sub i64 %332, 2, !dbg !78551
  %334 = icmp eq i64 %333, 0, !dbg !78551
  %335 = select i1 %334, i64 0, i64 1, !dbg !78551
  %336 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i8*, !dbg !78551
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %336), !dbg !78551
  br label %372, !dbg !78546

337:                                              ; preds = %322
  %338 = bitcast %"error::NewInterpreterError"* %13 to i8*, !dbg !78550
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %338), !dbg !78550
  %339 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to %"std::result::Result<(), error::NewInterpreterError>::Err"*, !dbg !78550
  %340 = bitcast %"std::result::Result<(), error::NewInterpreterError>::Err"* %339 to %"error::NewInterpreterError"*, !dbg !78550
  %341 = bitcast %"error::NewInterpreterError"* %13 to i8*, !dbg !78550
  %342 = bitcast %"error::NewInterpreterError"* %340 to i8*, !dbg !78550
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %341, i8* align 8 %342, i64 32, i1 false), !dbg !78550
  %343 = bitcast %"error::NewInterpreterError"* %12 to i8*, !dbg !78491
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %343), !dbg !78491
  %344 = bitcast %"error::NewInterpreterError"* %11 to i8*, !dbg !78491
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %344), !dbg !78491
  %345 = bitcast %"error::NewInterpreterError"* %11 to i8*, !dbg !78491
  %346 = bitcast %"error::NewInterpreterError"* %13 to i8*, !dbg !78491
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %345, i8* align 8 %346, i64 32, i1 false), !dbg !78491
  invoke void @_RNvXs2_NtCskrsM4FCwAVA_4core7convertNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorINtB5_4FromBy_E4fromBC_(%"error::NewInterpreterError"* noalias nocapture sret(%"error::NewInterpreterError") dereferenceable(32) %12, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %11)
          to label %347 unwind label %355, !dbg !78491

347:                                              ; preds = %337
  %348 = bitcast %"error::NewInterpreterError"* %11 to i8*, !dbg !78491
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %348), !dbg !78491
  invoke void @_RNvXsy_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops3try3Try10from_errorB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"error::NewInterpreterError"* noalias nocapture dereferenceable(32) %12)
          to label %362 unwind label %355, !dbg !78552

349:                                              ; preds = %355
  %350 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i64*, !dbg !78551
  %351 = load i64, i64* %350, align 8, !dbg !78551, !range !29786
  %352 = sub i64 %351, 2, !dbg !78551
  %353 = icmp eq i64 %352, 0, !dbg !78551
  %354 = select i1 %353, i64 0, i64 1, !dbg !78551
  br label %50, !dbg !78551

355:                                              ; preds = %347, %337
  %356 = landingpad { i8*, i32 }
          cleanup
  %357 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %357)
  %358 = extractvalue { i8*, i32 } %356, 0
  %359 = extractvalue { i8*, i32 } %356, 1
  %360 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %358, i8** %360, align 8
  %361 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %359, i32* %361, align 8
  br label %349

362:                                              ; preds = %347
  %363 = bitcast %"error::NewInterpreterError"* %12 to i8*, !dbg !78552
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %363), !dbg !78552
  %364 = bitcast %"error::NewInterpreterError"* %13 to i8*, !dbg !78550
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %364), !dbg !78550
  %365 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i64*, !dbg !78551
  %366 = load i64, i64* %365, align 8, !dbg !78551, !range !29786
  %367 = sub i64 %366, 2, !dbg !78551
  %368 = icmp eq i64 %367, 0, !dbg !78551
  %369 = select i1 %368, i64 0, i64 1, !dbg !78551
  %370 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %15 to i8*, !dbg !78551
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %370), !dbg !78551
  br label %303, !dbg !78542

371:                                              ; preds = %373, %107
  ret void, !dbg !78505

372:                                              ; preds = %312, %330
  br label %373, !dbg !78533

373:                                              ; preds = %235, %372
  %374 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !78553
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %374), !dbg !78553
  %375 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !78553
  %376 = bitcast %"pyo3::ffi::PyConfig"* %38 to i8*, !dbg !78553
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %375, i8* align 8 %376, i64 392, i1 false), !dbg !78553
  %377 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"*, !dbg !78554
  %378 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"* %377, i32 0, i32 1, !dbg !78554
  %379 = bitcast %"pyo3::ffi::PyConfig"* %378 to i8*, !dbg !78554
  %380 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !78554
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %379, i8* align 8 %380, i64 392, i1 false), !dbg !78554
  %381 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !78554
  store i64 0, i64* %381, align 8, !dbg !78554
  %382 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !78555
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %382), !dbg !78555
  %383 = bitcast %"std::path::PathBuf"** %23 to i8*, !dbg !78544
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %383), !dbg !78544
  %384 = bitcast %"pyo3::ffi::PyConfig"* %38 to i8*, !dbg !78504
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %384), !dbg !78504
  br label %371, !dbg !78505

nightly-2021-05-19:

*** IR Dump After Instrument function entry/exit with calls to e.g. mcount() (pre inlining) ***
; Function Attrs: nonlazybind uwtable
define void @_RNvXs_NtCsijNWNMdNqoj_7pyembed18interpreter_configRNtNtB6_6config39ResolvedOxidizedPythonInterpreterConfigINtNtCskrsM4FCwAVA_4core7convert7TryIntoNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigE8try_into(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1) unnamed_addr #0 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality !dbg !80111 {
  %3 = alloca %"std::path::PathBuf"*, align 8
  %4 = alloca %"std::vec::Vec<std::ffi::OsString>"*, align 8
  %5 = alloca { i8*, i32 }, align 8
  %6 = alloca {}, align 1
  %7 = alloca {}, align 1
  %8 = alloca {}, align 1
  %9 = alloca %"config::ResolvedOxidizedPythonInterpreterConfig"*, align 8
  %10 = alloca %"pyo3::ffi::PyConfig", align 8
  %11 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %12 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %13 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %14 = alloca %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>", align 8
  %15 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %16 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %17 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %18 = alloca %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>", align 8
  %19 = alloca {}, align 1
  %20 = alloca {}, align 1
  %21 = alloca %"std::path::PathBuf"*, align 8
  %22 = alloca %"error::NewInterpreterError", align 8
  %23 = alloca %"error::NewInterpreterError", align 8
  %24 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %25 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %26 = alloca %"std::result::Result<(), error::NewInterpreterError>", align 8
  %27 = alloca %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>", align 8
  %28 = alloca {}, align 1
  %29 = alloca %"pyo3::ffi::PyConfig", align 8
  %30 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %31 = alloca %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err", align 8
  %32 = alloca %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>", align 8
  %33 = alloca %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>", align 8
  %34 = alloca %"pyo3::ffi::PyConfig", align 8
  store %"config::ResolvedOxidizedPythonInterpreterConfig"* %1, %"config::ResolvedOxidizedPythonInterpreterConfig"** %9, align 8
  call void @llvm.dbg.declare(metadata %"config::ResolvedOxidizedPythonInterpreterConfig"** %9, metadata !80115, metadata !DIExpression()), !dbg !80140
  call void @llvm.dbg.declare(metadata %"pyo3::ffi::PyConfig"* %34, metadata !80116, metadata !DIExpression()), !dbg !80141
  call void @llvm.dbg.declare(metadata %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %31, metadata !80118, metadata !DIExpression()), !dbg !80142
  call void @llvm.dbg.declare(metadata %"pyo3::ffi::PyConfig"* %29, metadata !80120, metadata !DIExpression()), !dbg !80143
  call void @llvm.dbg.declare(metadata %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %25, metadata !80124, metadata !DIExpression()), !dbg !80144
  call void @llvm.dbg.declare(metadata {}* %8, metadata !80126, metadata !DIExpression()), !dbg !80145
  call void @llvm.dbg.declare(metadata %"std::path::PathBuf"** %21, metadata !80128, metadata !DIExpression()), !dbg !80146
  call void @llvm.dbg.declare(metadata %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %16, metadata !80132, metadata !DIExpression()), !dbg !80147
  call void @llvm.dbg.declare(metadata {}* %7, metadata !80134, metadata !DIExpression()), !dbg !80148
  call void @llvm.dbg.declare(metadata %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %12, metadata !80136, metadata !DIExpression()), !dbg !80149
  call void @llvm.dbg.declare(metadata {}* %6, metadata !80138, metadata !DIExpression()), !dbg !80150
  %35 = bitcast %"pyo3::ffi::PyConfig"* %34 to i8*, !dbg !80151
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %35), !dbg !80151
  %36 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i8*, !dbg !80152
  call void @llvm.lifetime.start.p0i8(i64 400, i8* %36), !dbg !80152
  %37 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %32 to i8*, !dbg !80152
  call void @llvm.lifetime.start.p0i8(i64 400, i8* %37), !dbg !80152
  %38 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80153
  br label %39, !dbg !80153

39:                                               ; preds = %2
  %40 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %38, i32 0, i32 5, !dbg !80154
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config38python_interpreter_config_to_py_config(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %32, %"python_packaging::interpreter::PythonInterpreterConfig"* noalias readonly align 8 dereferenceable(560) %40), !dbg !80152
  br label %41, !dbg !80152

41:                                               ; preds = %39
  invoke void @_RNvXsz_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops9try_trait3Try6branchB1M_(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* noalias nocapture sret(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>") dereferenceable(400) %33, %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture dereferenceable(400) %32)
          to label %42 unwind label %54, !dbg !80152

42:                                               ; preds = %41
  %43 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %32 to i8*, !dbg !80152
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %43), !dbg !80152
  %44 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i64*, !dbg !80155
  %45 = load i64, i64* %44, align 8, !dbg !80155, !range !2867
  switch i64 %45, label %61 [
    i64 0, label %62
    i64 1, label %75
  ], !dbg !80155

46:                                               ; preds = %342, %277, %155, %90, %54
  %47 = bitcast { i8*, i32 }* %5 to i8**, !dbg !80156
  %48 = load i8*, i8** %47, align 8, !dbg !80156
  %49 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1, !dbg !80156
  %50 = load i32, i32* %49, align 8, !dbg !80156
  %51 = bitcast { i8*, i32 }* %5 to i8*, !dbg !80156
  call void @llvm.lifetime.end.p0i8(i64 16, i8* %51), !dbg !80156
  %52 = insertvalue { i8*, i32 } undef, i8* %48, 0, !dbg !80156
  %53 = insertvalue { i8*, i32 } %52, i32 %50, 1, !dbg !80156
  resume { i8*, i32 } %53, !dbg !80156

54:                                               ; preds = %308, %243, %121, %41
  %55 = landingpad { i8*, i32 }
          cleanup
  %56 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %56)
  %57 = extractvalue { i8*, i32 } %55, 0
  %58 = extractvalue { i8*, i32 } %55, 1
  %59 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %57, i8** %59, align 8
  %60 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %58, i32* %60, align 8
  br label %46

61:                                               ; preds = %42
  unreachable, !dbg !80152

62:                                               ; preds = %42
  %63 = bitcast %"pyo3::ffi::PyConfig"* %29 to i8*, !dbg !80152
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %63), !dbg !80152
  %64 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Continue"*, !dbg !80152
  %65 = getelementptr inbounds %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Continue", %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Continue"* %64, i32 0, i32 1, !dbg !80152
  %66 = bitcast %"pyo3::ffi::PyConfig"* %29 to i8*, !dbg !80152
  %67 = bitcast %"pyo3::ffi::PyConfig"* %65 to i8*, !dbg !80152
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %66, i8* align 8 %67, i64 392, i1 false), !dbg !80152
  %68 = bitcast %"pyo3::ffi::PyConfig"* %34 to i8*, !dbg !80143
  %69 = bitcast %"pyo3::ffi::PyConfig"* %29 to i8*, !dbg !80143
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %68, i8* align 8 %69, i64 392, i1 false), !dbg !80143
  %70 = bitcast %"pyo3::ffi::PyConfig"* %29 to i8*, !dbg !80155
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %70), !dbg !80155
  %71 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i64*, !dbg !80157
  %72 = load i64, i64* %71, align 8, !dbg !80157, !range !2867
  %73 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i8*, !dbg !80157
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %73), !dbg !80157
  %74 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80158
  br label %102, !dbg !80158

75:                                               ; preds = %42
  %76 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %31 to i8*, !dbg !80155
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %76), !dbg !80155
  %77 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Break"*, !dbg !80155
  %78 = getelementptr inbounds %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Break", %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>::Break"* %77, i32 0, i32 1, !dbg !80155
  %79 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %31 to i8*, !dbg !80155
  %80 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %78 to i8*, !dbg !80155
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %79, i8* align 8 %80, i64 32, i1 false), !dbg !80155
  %81 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %30 to i8*, !dbg !80142
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %81), !dbg !80142
  %82 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %30 to i8*, !dbg !80142
  %83 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %31 to i8*, !dbg !80142
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %82, i8* align 8 %83, i64 32, i1 false), !dbg !80142
  invoke void @_RNvXsA_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorEINtNtNtB7_3ops9try_trait12FromResidualIBy_NtNtB7_7convert10InfallibleB1I_EE13from_residualB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* noalias nocapture dereferenceable(32) %30)
          to label %84 unwind label %93, !dbg !80159

84:                                               ; preds = %75
  %85 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %30 to i8*, !dbg !80159
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %85), !dbg !80159
  %86 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %31 to i8*, !dbg !80155
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %86), !dbg !80155
  %87 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i64*, !dbg !80157
  %88 = load i64, i64* %87, align 8, !dbg !80157, !range !2867
  %89 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i8*, !dbg !80157
  call void @llvm.lifetime.end.p0i8(i64 400, i8* %89), !dbg !80157
  br label %100, !dbg !80160

90:                                               ; preds = %93
  %91 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>, pyo3::ffi::PyConfig>"* %33 to i64*, !dbg !80157
  %92 = load i64, i64* %91, align 8, !dbg !80157, !range !2867
  br label %46, !dbg !80157

93:                                               ; preds = %75
  %94 = landingpad { i8*, i32 }
          cleanup
  %95 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %95)
  %96 = extractvalue { i8*, i32 } %94, 0
  %97 = extractvalue { i8*, i32 } %94, 1
  %98 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %96, i8** %98, align 8
  %99 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %97, i32* %99, align 8
  br label %90

100:                                              ; preds = %290, %194, %174, %146, %84
  %101 = bitcast %"pyo3::ffi::PyConfig"* %34 to i8*, !dbg !80162
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %101), !dbg !80162
  br label %355, !dbg !80163

102:                                              ; preds = %62
  %103 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %74, i32 0, i32 11, !dbg !80164
  %104 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>"* %103 to {}**, !dbg !80165
  %105 = load {}*, {}** %104, align 8, !dbg !80165
  %106 = icmp eq {}* %105, null, !dbg !80165
  %107 = select i1 %106, i64 0, i64 1, !dbg !80165
  %108 = icmp eq i64 %107, 1, !dbg !80165
  br i1 %108, label %109, label %117, !dbg !80165

109:                                              ; preds = %102
  %110 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>"* %103 to %"std::option::Option<std::vec::Vec<std::ffi::OsString>>::Some"*, !dbg !80166
  %111 = bitcast %"std::option::Option<std::vec::Vec<std::ffi::OsString>>::Some"* %110 to %"std::vec::Vec<std::ffi::OsString>"*, !dbg !80166
  store %"std::vec::Vec<std::ffi::OsString>"* %111, %"std::vec::Vec<std::ffi::OsString>"** %4, align 8, !dbg !80166
  call void @llvm.dbg.declare(metadata %"std::vec::Vec<std::ffi::OsString>"** %4, metadata !80122, metadata !DIExpression()), !dbg !80167
  %112 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i8*, !dbg !80168
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %112), !dbg !80168
  %113 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %26 to i8*, !dbg !80168
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %113), !dbg !80168
  %114 = call { [0 x %"std::ffi::OsString"]*, i64 } @_RNvXs8_NtCshECKBmVgND8_5alloc3vecINtB5_3VecNtNtNtCsahqMUB7vfgm_3std3ffi6os_str8OsStringENtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5derefCsijNWNMdNqoj_7pyembed(%"std::vec::Vec<std::ffi::OsString>"* noalias readonly align 8 dereferenceable(24) %111), !dbg !80169
  %115 = extractvalue { [0 x %"std::ffi::OsString"]*, i64 } %114, 0, !dbg !80169
  %116 = extractvalue { [0 x %"std::ffi::OsString"]*, i64 } %114, 1, !dbg !80169
  br label %120, !dbg !80169

117:                                              ; preds = %102
  br label %118, !dbg !80170

118:                                              ; preds = %130, %117
  %119 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80171
  br label %168, !dbg !80171

120:                                              ; preds = %109
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config8set_argv(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %26, %"pyo3::ffi::PyConfig"* noalias align 8 dereferenceable(392) %34, [0 x %"std::ffi::OsString"]* noalias nonnull readonly align 8 %115, i64 %116), !dbg !80168
  br label %121, !dbg !80168

121:                                              ; preds = %120
  invoke void @_RNvXsz_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops9try_trait3Try6branchBP_(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* noalias nocapture sret(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>") dereferenceable(32) %27, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %26)
          to label %122 unwind label %54, !dbg !80168

122:                                              ; preds = %121
  %123 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %26 to i8*, !dbg !80168
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %123), !dbg !80168
  %124 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i64*, !dbg !80172
  %125 = load i64, i64* %124, align 8, !dbg !80172, !range !29490
  %126 = sub i64 %125, 2, !dbg !80172
  %127 = icmp eq i64 %126, 0, !dbg !80172
  %128 = select i1 %127, i64 0, i64 1, !dbg !80172
  switch i64 %128, label %129 [
    i64 0, label %130
    i64 1, label %137
  ], !dbg !80172

129:                                              ; preds = %122
  unreachable, !dbg !80168

130:                                              ; preds = %122
  %131 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i64*, !dbg !80173
  %132 = load i64, i64* %131, align 8, !dbg !80173, !range !29490
  %133 = sub i64 %132, 2, !dbg !80173
  %134 = icmp eq i64 %133, 0, !dbg !80173
  %135 = select i1 %134, i64 0, i64 1, !dbg !80173
  %136 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i8*, !dbg !80173
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %136), !dbg !80173
  br label %118, !dbg !80170

137:                                              ; preds = %122
  %138 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %25 to i8*, !dbg !80172
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %138), !dbg !80172
  %139 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"*, !dbg !80172
  %140 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"* %139 to %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"*, !dbg !80172
  %141 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %25 to i8*, !dbg !80172
  %142 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %140 to i8*, !dbg !80172
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %141, i8* align 8 %142, i64 32, i1 false), !dbg !80172
  %143 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %24 to i8*, !dbg !80144
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %143), !dbg !80144
  %144 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %24 to i8*, !dbg !80144
  %145 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %25 to i8*, !dbg !80144
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %144, i8* align 8 %145, i64 32, i1 false), !dbg !80144
  invoke void @_RNvXsA_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorEINtNtNtB7_3ops9try_trait12FromResidualIBy_NtNtB7_7convert10InfallibleB1I_EE13from_residualB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* noalias nocapture dereferenceable(32) %24)
          to label %146 unwind label %161, !dbg !80174

146:                                              ; preds = %137
  %147 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %24 to i8*, !dbg !80174
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %147), !dbg !80174
  %148 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %25 to i8*, !dbg !80172
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %148), !dbg !80172
  %149 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i64*, !dbg !80173
  %150 = load i64, i64* %149, align 8, !dbg !80173, !range !29490
  %151 = sub i64 %150, 2, !dbg !80173
  %152 = icmp eq i64 %151, 0, !dbg !80173
  %153 = select i1 %152, i64 0, i64 1, !dbg !80173
  %154 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i8*, !dbg !80173
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %154), !dbg !80173
  br label %100, !dbg !80175

155:                                              ; preds = %161
  %156 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %27 to i64*, !dbg !80173
  %157 = load i64, i64* %156, align 8, !dbg !80173, !range !29490
  %158 = sub i64 %157, 2, !dbg !80173
  %159 = icmp eq i64 %158, 0, !dbg !80173
  %160 = select i1 %159, i64 0, i64 1, !dbg !80173
  br label %46, !dbg !80173

161:                                              ; preds = %137
  %162 = landingpad { i8*, i32 }
          cleanup
  %163 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %163)
  %164 = extractvalue { i8*, i32 } %162, 0
  %165 = extractvalue { i8*, i32 } %162, 1
  %166 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %164, i8** %166, align 8
  %167 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %165, i32* %167, align 8
  br label %155

168:                                              ; preds = %118
  %169 = bitcast %"config::OxidizedPythonInterpreterConfig"* %119 to %"std::option::Option<std::path::PathBuf>"*, !dbg !80171
  %170 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %169), !dbg !80171
  br label %171, !dbg !80171

171:                                              ; preds = %168
  br i1 %170, label %174, label %172, !dbg !80177

172:                                              ; preds = %171
  %173 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80178
  br label %187, !dbg !80178

174:                                              ; preds = %171
  %175 = bitcast %"error::NewInterpreterError"* %23 to i8*, !dbg !80179
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %175), !dbg !80179
  %176 = bitcast %"error::NewInterpreterError"* %23 to %"error::NewInterpreterError::Simple"*, !dbg !80179
  %177 = getelementptr inbounds %"error::NewInterpreterError::Simple", %"error::NewInterpreterError::Simple"* %176, i32 0, i32 1, !dbg !80179
  %178 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %177, i32 0, i32 0, !dbg !80179
  store [0 x i8]* bitcast (<{ [57 x i8] }>* @296 to [0 x i8]*), [0 x i8]** %178, align 8, !dbg !80179
  %179 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %177, i32 0, i32 1, !dbg !80179
  store i64 57, i64* %179, align 8, !dbg !80179
  %180 = bitcast %"error::NewInterpreterError"* %23 to i64*, !dbg !80179
  store i64 0, i64* %180, align 8, !dbg !80179
  %181 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"*, !dbg !80180
  %182 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"* %181, i32 0, i32 1, !dbg !80180
  %183 = bitcast %"error::NewInterpreterError"* %182 to i8*, !dbg !80180
  %184 = bitcast %"error::NewInterpreterError"* %23 to i8*, !dbg !80180
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %183, i8* align 8 %184, i64 32, i1 false), !dbg !80180
  %185 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !80180
  store i64 1, i64* %185, align 8, !dbg !80180
  %186 = bitcast %"error::NewInterpreterError"* %23 to i8*, !dbg !80181
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %186), !dbg !80181
  br label %100, !dbg !80175

187:                                              ; preds = %172
  %188 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %173, i32 0, i32 3, !dbg !80178
  %189 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %188), !dbg !80178
  br label %190, !dbg !80178

190:                                              ; preds = %187
  br i1 %189, label %194, label %191, !dbg !80182

191:                                              ; preds = %190
  %192 = bitcast %"std::path::PathBuf"** %21 to i8*, !dbg !80183
  call void @llvm.lifetime.start.p0i8(i64 8, i8* %192), !dbg !80183
  %193 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80184
  br label %207, !dbg !80184

194:                                              ; preds = %190
  %195 = bitcast %"error::NewInterpreterError"* %22 to i8*, !dbg !80185
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %195), !dbg !80185
  %196 = bitcast %"error::NewInterpreterError"* %22 to %"error::NewInterpreterError::Simple"*, !dbg !80185
  %197 = getelementptr inbounds %"error::NewInterpreterError::Simple", %"error::NewInterpreterError::Simple"* %196, i32 0, i32 1, !dbg !80185
  %198 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %197, i32 0, i32 0, !dbg !80185
  store [0 x i8]* bitcast (<{ [45 x i8] }>* @297 to [0 x i8]*), [0 x i8]** %198, align 8, !dbg !80185
  %199 = getelementptr inbounds { [0 x i8]*, i64 }, { [0 x i8]*, i64 }* %197, i32 0, i32 1, !dbg !80185
  store i64 45, i64* %199, align 8, !dbg !80185
  %200 = bitcast %"error::NewInterpreterError"* %22 to i64*, !dbg !80185
  store i64 0, i64* %200, align 8, !dbg !80185
  %201 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"*, !dbg !80186
  %202 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Err"* %201, i32 0, i32 1, !dbg !80186
  %203 = bitcast %"error::NewInterpreterError"* %202 to i8*, !dbg !80186
  %204 = bitcast %"error::NewInterpreterError"* %22 to i8*, !dbg !80186
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %203, i8* align 8 %204, i64 32, i1 false), !dbg !80186
  %205 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !80186
  store i64 1, i64* %205, align 8, !dbg !80186
  %206 = bitcast %"error::NewInterpreterError"* %22 to i8*, !dbg !80187
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %206), !dbg !80187
  br label %100, !dbg !80175

207:                                              ; preds = %191
  %208 = bitcast %"config::OxidizedPythonInterpreterConfig"* %193 to %"std::option::Option<std::path::PathBuf>"*, !dbg !80184
  %209 = call align 8 dereferenceable_or_null(24) i64* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE6as_refCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %208), !dbg !80184
  br label %210, !dbg !80184

210:                                              ; preds = %207
  %211 = call align 8 dereferenceable(24) %"std::path::PathBuf"* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionRNtNtCsahqMUB7vfgm_3std4path7PathBufE6unwrapCsijNWNMdNqoj_7pyembed(i64* noalias readonly align 8 dereferenceable_or_null(24) %209, %"std::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @299 to %"std::panic::Location"*)), !dbg !80184
  store %"std::path::PathBuf"* %211, %"std::path::PathBuf"** %21, align 8, !dbg !80184
  br label %212, !dbg !80184

212:                                              ; preds = %210
  %213 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80188
  br label %214, !dbg !80188

214:                                              ; preds = %212
  %215 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %213, i32 0, i32 3, !dbg !80188
  %216 = call align 8 dereferenceable_or_null(24) i64* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE6as_refCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %215), !dbg !80188
  br label %217, !dbg !80188

217:                                              ; preds = %214
  %218 = call align 8 dereferenceable(24) %"std::path::PathBuf"* @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionRNtNtCsahqMUB7vfgm_3std4path7PathBufE6unwrapCsijNWNMdNqoj_7pyembed(i64* noalias readonly align 8 dereferenceable_or_null(24) %216, %"std::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @300 to %"std::panic::Location"*)), !dbg !80188
  store %"std::path::PathBuf"* %218, %"std::path::PathBuf"** %3, align 8, !dbg !80188
  call void @llvm.dbg.declare(metadata %"std::path::PathBuf"** %3, metadata !80130, metadata !DIExpression()), !dbg !80189
  br label %219, !dbg !80188

219:                                              ; preds = %217
  %220 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80190
  br label %221, !dbg !80190

221:                                              ; preds = %219
  %222 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %220, i32 0, i32 31, !dbg !80190
  %223 = load i8, i8* %222, align 2, !dbg !80190, !range !6865
  %224 = trunc i8 %223 to i1, !dbg !80190
  br i1 %224, label %226, label %225, !dbg !80191

225:                                              ; preds = %221
  br label %357, !dbg !80191

226:                                              ; preds = %221
  %227 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80192
  br label %228, !dbg !80192

228:                                              ; preds = %226
  %229 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %227, i32 0, i32 5, !dbg !80192
  %230 = getelementptr inbounds %"python_packaging::interpreter::PythonInterpreterConfig", %"python_packaging::interpreter::PythonInterpreterConfig"* %229, i32 0, i32 25, !dbg !80192
  %231 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %230), !dbg !80192
  br label %232, !dbg !80192

232:                                              ; preds = %228
  br i1 %231, label %234, label %233, !dbg !80193

233:                                              ; preds = %232
  br label %292, !dbg !80193

234:                                              ; preds = %232
  %235 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i8*, !dbg !80194
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %235), !dbg !80194
  %236 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %17 to i8*, !dbg !80194
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %236), !dbg !80194
  %237 = getelementptr inbounds %"pyo3::ffi::PyConfig", %"pyo3::ffi::PyConfig"* %34, i32 0, i32 39, !dbg !80195
  %238 = load %"std::path::PathBuf"*, %"std::path::PathBuf"** %21, align 8, !dbg !80196, !nonnull !4
  %239 = call { %"std::path::Path"*, i64 } @"_ZN62_$LT$std..path..PathBuf$u20$as$u20$core..ops..deref..Deref$GT$5deref17he7f3f920ba1b2649E"(%"std::path::PathBuf"* noalias readonly align 8 dereferenceable(24) %238), !dbg !80196
  %240 = extractvalue { %"std::path::Path"*, i64 } %239, 0, !dbg !80196
  %241 = extractvalue { %"std::path::Path"*, i64 } %239, 1, !dbg !80196
  br label %242, !dbg !80196

242:                                              ; preds = %234
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config27set_config_string_from_path(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %17, %"pyo3::ffi::PyConfig"* noalias readonly align 8 dereferenceable(392) %34, i32** noalias readonly align 8 dereferenceable(8) %237, %"std::path::Path"* noalias nonnull readonly align 1 %240, i64 %241, [0 x i8]* noalias nonnull readonly align 1 bitcast (<{ [20 x i8] }>* @301 to [0 x i8]*), i64 20), !dbg !80194
  br label %243, !dbg !80194

243:                                              ; preds = %242
  invoke void @_RNvXsz_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops9try_trait3Try6branchBP_(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* noalias nocapture sret(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>") dereferenceable(32) %18, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %17)
          to label %244 unwind label %54, !dbg !80194

244:                                              ; preds = %243
  %245 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %17 to i8*, !dbg !80194
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %245), !dbg !80194
  %246 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i64*, !dbg !80197
  %247 = load i64, i64* %246, align 8, !dbg !80197, !range !29490
  %248 = sub i64 %247, 2, !dbg !80197
  %249 = icmp eq i64 %248, 0, !dbg !80197
  %250 = select i1 %249, i64 0, i64 1, !dbg !80197
  switch i64 %250, label %251 [
    i64 0, label %252
    i64 1, label %259
  ], !dbg !80197

251:                                              ; preds = %244
  unreachable, !dbg !80194

252:                                              ; preds = %244
  %253 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i64*, !dbg !80198
  %254 = load i64, i64* %253, align 8, !dbg !80198, !range !29490
  %255 = sub i64 %254, 2, !dbg !80198
  %256 = icmp eq i64 %255, 0, !dbg !80198
  %257 = select i1 %256, i64 0, i64 1, !dbg !80198
  %258 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i8*, !dbg !80198
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %258), !dbg !80198
  br label %292, !dbg !80193

259:                                              ; preds = %244
  %260 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %16 to i8*, !dbg !80197
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %260), !dbg !80197
  %261 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"*, !dbg !80197
  %262 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"* %261 to %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"*, !dbg !80197
  %263 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %16 to i8*, !dbg !80197
  %264 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %262 to i8*, !dbg !80197
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %263, i8* align 8 %264, i64 32, i1 false), !dbg !80197
  %265 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %15 to i8*, !dbg !80147
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %265), !dbg !80147
  %266 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %15 to i8*, !dbg !80147
  %267 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %16 to i8*, !dbg !80147
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %266, i8* align 8 %267, i64 32, i1 false), !dbg !80147
  invoke void @_RNvXsA_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorEINtNtNtB7_3ops9try_trait12FromResidualIBy_NtNtB7_7convert10InfallibleB1I_EE13from_residualB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* noalias nocapture dereferenceable(32) %15)
          to label %268 unwind label %283, !dbg !80199

268:                                              ; preds = %259
  %269 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %15 to i8*, !dbg !80199
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %269), !dbg !80199
  %270 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %16 to i8*, !dbg !80197
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %270), !dbg !80197
  %271 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i64*, !dbg !80198
  %272 = load i64, i64* %271, align 8, !dbg !80198, !range !29490
  %273 = sub i64 %272, 2, !dbg !80198
  %274 = icmp eq i64 %273, 0, !dbg !80198
  %275 = select i1 %274, i64 0, i64 1, !dbg !80198
  %276 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i8*, !dbg !80198
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %276), !dbg !80198
  br label %290, !dbg !80200

277:                                              ; preds = %283
  %278 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %18 to i64*, !dbg !80198
  %279 = load i64, i64* %278, align 8, !dbg !80198, !range !29490
  %280 = sub i64 %279, 2, !dbg !80198
  %281 = icmp eq i64 %280, 0, !dbg !80198
  %282 = select i1 %281, i64 0, i64 1, !dbg !80198
  br label %46, !dbg !80198

283:                                              ; preds = %259
  %284 = landingpad { i8*, i32 }
          cleanup
  %285 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %285)
  %286 = extractvalue { i8*, i32 } %284, 0
  %287 = extractvalue { i8*, i32 } %284, 1
  %288 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %286, i8** %288, align 8
  %289 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %287, i32* %289, align 8
  br label %277

290:                                              ; preds = %333, %268
  %291 = bitcast %"std::path::PathBuf"** %21 to i8*, !dbg !80202
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %291), !dbg !80202
  br label %100, !dbg !80175

292:                                              ; preds = %233, %252
  %293 = call align 8 dereferenceable(776) %"config::OxidizedPythonInterpreterConfig"* @_RNvXs1_NtCsijNWNMdNqoj_7pyembed6configNtB5_39ResolvedOxidizedPythonInterpreterConfigNtNtNtCskrsM4FCwAVA_4core3ops5deref5Deref5deref(%"config::ResolvedOxidizedPythonInterpreterConfig"* noalias readonly align 8 dereferenceable(776) %1), !dbg !80203
  br label %294, !dbg !80203

294:                                              ; preds = %292
  %295 = getelementptr inbounds %"config::OxidizedPythonInterpreterConfig", %"config::OxidizedPythonInterpreterConfig"* %293, i32 0, i32 5, !dbg !80203
  %296 = getelementptr inbounds %"python_packaging::interpreter::PythonInterpreterConfig", %"python_packaging::interpreter::PythonInterpreterConfig"* %295, i32 0, i32 19, !dbg !80203
  %297 = call zeroext i1 @_RNvMNtCskrsM4FCwAVA_4core6optionINtB2_6OptionNtNtCsahqMUB7vfgm_3std4path7PathBufE7is_noneCsijNWNMdNqoj_7pyembed(%"std::option::Option<std::path::PathBuf>"* noalias readonly align 8 dereferenceable(24) %296), !dbg !80203
  br label %298, !dbg !80203

298:                                              ; preds = %294
  br i1 %297, label %300, label %299, !dbg !80204

299:                                              ; preds = %298
  br label %356, !dbg !80204

300:                                              ; preds = %298
  %301 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i8*, !dbg !80205
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %301), !dbg !80205
  %302 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %13 to i8*, !dbg !80205
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %302), !dbg !80205
  %303 = getelementptr inbounds %"pyo3::ffi::PyConfig", %"pyo3::ffi::PyConfig"* %34, i32 0, i32 79, !dbg !80206
  %304 = call { %"std::path::Path"*, i64 } @"_ZN62_$LT$std..path..PathBuf$u20$as$u20$core..ops..deref..Deref$GT$5deref17he7f3f920ba1b2649E"(%"std::path::PathBuf"* noalias readonly align 8 dereferenceable(24) %218), !dbg !80207
  %305 = extractvalue { %"std::path::Path"*, i64 } %304, 0, !dbg !80207
  %306 = extractvalue { %"std::path::Path"*, i64 } %304, 1, !dbg !80207
  br label %307, !dbg !80207

307:                                              ; preds = %300
  call void @_RNvNtCsijNWNMdNqoj_7pyembed18interpreter_config27set_config_string_from_path(%"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<(), error::NewInterpreterError>") dereferenceable(32) %13, %"pyo3::ffi::PyConfig"* noalias readonly align 8 dereferenceable(392) %34, i32** noalias readonly align 8 dereferenceable(8) %303, %"std::path::Path"* noalias nonnull readonly align 1 %305, i64 %306, [0 x i8]* noalias nonnull readonly align 1 bitcast (<{ [12 x i8] }>* @302 to [0 x i8]*), i64 12), !dbg !80205
  br label %308, !dbg !80205

308:                                              ; preds = %307
  invoke void @_RNvXsz_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultuNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorENtNtNtB7_3ops9try_trait3Try6branchBP_(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* noalias nocapture sret(%"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>") dereferenceable(32) %14, %"std::result::Result<(), error::NewInterpreterError>"* noalias nocapture dereferenceable(32) %13)
          to label %309 unwind label %54, !dbg !80205

309:                                              ; preds = %308
  %310 = bitcast %"std::result::Result<(), error::NewInterpreterError>"* %13 to i8*, !dbg !80205
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %310), !dbg !80205
  %311 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i64*, !dbg !80208
  %312 = load i64, i64* %311, align 8, !dbg !80208, !range !29490
  %313 = sub i64 %312, 2, !dbg !80208
  %314 = icmp eq i64 %313, 0, !dbg !80208
  %315 = select i1 %314, i64 0, i64 1, !dbg !80208
  switch i64 %315, label %316 [
    i64 0, label %317
    i64 1, label %324
  ], !dbg !80208

316:                                              ; preds = %309
  unreachable, !dbg !80205

317:                                              ; preds = %309
  %318 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i64*, !dbg !80209
  %319 = load i64, i64* %318, align 8, !dbg !80209, !range !29490
  %320 = sub i64 %319, 2, !dbg !80209
  %321 = icmp eq i64 %320, 0, !dbg !80209
  %322 = select i1 %321, i64 0, i64 1, !dbg !80209
  %323 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i8*, !dbg !80209
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %323), !dbg !80209
  br label %356, !dbg !80204

324:                                              ; preds = %309
  %325 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %12 to i8*, !dbg !80208
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %325), !dbg !80208
  %326 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"*, !dbg !80208
  %327 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>::Break"* %326 to %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"*, !dbg !80208
  %328 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %12 to i8*, !dbg !80208
  %329 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %327 to i8*, !dbg !80208
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %328, i8* align 8 %329, i64 32, i1 false), !dbg !80208
  %330 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %11 to i8*, !dbg !80149
  call void @llvm.lifetime.start.p0i8(i64 32, i8* %330), !dbg !80149
  %331 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %11 to i8*, !dbg !80149
  %332 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %12 to i8*, !dbg !80149
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %331, i8* align 8 %332, i64 32, i1 false), !dbg !80149
  invoke void @_RNvXsA_NtCskrsM4FCwAVA_4core6resultINtB5_6ResultNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigNtNtCsijNWNMdNqoj_7pyembed5error19NewInterpreterErrorEINtNtNtB7_3ops9try_trait12FromResidualIBy_NtNtB7_7convert10InfallibleB1I_EE13from_residualB1M_(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* noalias nocapture sret(%"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>") dereferenceable(400) %0, %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* noalias nocapture dereferenceable(32) %11)
          to label %333 unwind label %348, !dbg !80210

333:                                              ; preds = %324
  %334 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %11 to i8*, !dbg !80210
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %334), !dbg !80210
  %335 = bitcast %"std::result::Result<std::convert::Infallible, error::NewInterpreterError>::Err"* %12 to i8*, !dbg !80208
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %335), !dbg !80208
  %336 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i64*, !dbg !80209
  %337 = load i64, i64* %336, align 8, !dbg !80209, !range !29490
  %338 = sub i64 %337, 2, !dbg !80209
  %339 = icmp eq i64 %338, 0, !dbg !80209
  %340 = select i1 %339, i64 0, i64 1, !dbg !80209
  %341 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i8*, !dbg !80209
  call void @llvm.lifetime.end.p0i8(i64 32, i8* %341), !dbg !80209
  br label %290, !dbg !80200

342:                                              ; preds = %348
  %343 = bitcast %"std::ops::ControlFlow<std::result::Result<std::convert::Infallible, error::NewInterpreterError>>"* %14 to i64*, !dbg !80209
  %344 = load i64, i64* %343, align 8, !dbg !80209, !range !29490
  %345 = sub i64 %344, 2, !dbg !80209
  %346 = icmp eq i64 %345, 0, !dbg !80209
  %347 = select i1 %346, i64 0, i64 1, !dbg !80209
  br label %46, !dbg !80209

348:                                              ; preds = %324
  %349 = landingpad { i8*, i32 }
          cleanup
  %350 = bitcast { i8*, i32 }* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 16, i8* %350)
  %351 = extractvalue { i8*, i32 } %349, 0
  %352 = extractvalue { i8*, i32 } %349, 1
  %353 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 0
  store i8* %351, i8** %353, align 8
  %354 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %5, i32 0, i32 1
  store i32 %352, i32* %354, align 8
  br label %342

355:                                              ; preds = %357, %100
  ret void, !dbg !80163

356:                                              ; preds = %299, %317
  br label %357, !dbg !80191

357:                                              ; preds = %225, %356
  %358 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !80211
  call void @llvm.lifetime.start.p0i8(i64 392, i8* %358), !dbg !80211
  %359 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !80211
  %360 = bitcast %"pyo3::ffi::PyConfig"* %34 to i8*, !dbg !80211
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %359, i8* align 8 %360, i64 392, i1 false), !dbg !80211
  %361 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"*, !dbg !80212
  %362 = getelementptr inbounds %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok", %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>::Ok"* %361, i32 0, i32 1, !dbg !80212
  %363 = bitcast %"pyo3::ffi::PyConfig"* %362 to i8*, !dbg !80212
  %364 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !80212
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %363, i8* align 8 %364, i64 392, i1 false), !dbg !80212
  %365 = bitcast %"std::result::Result<pyo3::ffi::PyConfig, error::NewInterpreterError>"* %0 to i64*, !dbg !80212
  store i64 0, i64* %365, align 8, !dbg !80212
  %366 = bitcast %"pyo3::ffi::PyConfig"* %10 to i8*, !dbg !80213
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %366), !dbg !80213
  %367 = bitcast %"std::path::PathBuf"** %21 to i8*, !dbg !80202
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %367), !dbg !80202
  %368 = bitcast %"pyo3::ffi::PyConfig"* %34 to i8*, !dbg !80162
  call void @llvm.lifetime.end.p0i8(i64 392, i8* %368), !dbg !80162
  br label %355, !dbg !80163
}

Here's the command I used to build and capture LLVM IR:

RUSTFLAGS="-Z symbol-mangling-version=v0 -Z no-parallel-llvm -Z mir-opt-level=0 -C codegen-units=3 -C llvm-args=-filter-print-funcs=_RNvXs_NtCsijNWNMdNqoj_7pyembed18interpreter_configRNtNtB6_6config39ResolvedOxidizedPythonInterpreterConfigINtNtCskrsM4FCwAVA_4core7convert7TryIntoNtNtNtNtCs9hgvHLNfJdN_4pyo33ffi7cpython10initconfig8PyConfigE8try_into -C llvm-args=-print-after-all" cargo +nightly-2021-05-19 build --release --features allocator-jemalloc

@nbdd0121
Copy link
Contributor

Well, it looks like the rustc emits quite different LLVM IR between these 2 nightlies, even before it goes into LLVM optimization passes.

I think that's expected given the Try trait was changed

@indygreg
Copy link
Contributor Author

I'm starting to make headway into reducing the test case.

I'm able to reduce this to the following:

#[test]
fn crash() {
    let config = ResolvedOxidizedPythonInterpreterConfig {
        inner: OxidizedPythonInterpreterConfig {
            argv: Some(vec![std::ffi::OsString::default()]),
            ..OxidizedPythonInterpreterConfig::default()
        },
    };

    // These 2 functions do the same thing. However, only the 2nd crashes.
    //let mut py_config = try_crash(config).unwrap();
    let py_config: pyffi::PyConfig = (&config).try_into().unwrap();
}

(This has been pushed to the rust-crash branch of https://github.com/indygreg/PyOxidizer.)

What's interesting here is that if I call into a function defined in an impl<'a> TryInto<pyffi::PyConfig> for &'a ResolvedOxidizedPythonInterpreterConfig<'a>, we get a crash. But if I pull that function out to a regular fn try_crash(config: ResolvedOxidizedPythonInterpreterConfig) -> Result<pyffi::PyConfig, NewInterpreterError>, we don't get a crash!

This might indicate a bug in rustc LLVM IR emission. But I dunno.

I'll try to reduce this further.

@indygreg
Copy link
Contributor Author

I have reduced the reproduction case considerably and pushed it to a standalone repository: https://github.com/indygreg/rust-crash.

As part of trying to reduce it further by eliminating the use of unsafe and a 3rd party library (libpython), I noticed that there was a discrepancy between the definition of one of the C structs.

The Rust definition:

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyStatus {
    pub func: *const c_char,
    pub err_msg: *const c_char,
    pub exitcode: c_int,
}

And the canonical C definition:

typedef struct {
    enum {
        _PyStatus_TYPE_OK=0,
        _PyStatus_TYPE_ERROR=1,
        _PyStatus_TYPE_EXIT=2
    } _type;
    const char *func;
    const char *err_msg;
    int exitcode;
} PyStatus;

The omission of that _type field appears to have caused a stack allocated variable to be smaller than it should have been. In optimized builds, this caused an out-of-bounds write on the stack, corrupting a saved frame register, leading to a crash.

Correcting the C type definition makes the crash go away.

So this appears to be a bug in PyO3's FFI definitions, not a regression in the Rust compiler or LLVM.

I'm a bit embarrassed this turned out to be improper unsafe code. But, I learned a bit about how to debug the Rust compiler and brushed up on my very rusty x86_64 calling convention knowledge. So that's a silver lining, I suppose.

Sorry for the noise.

indygreg added a commit to indygreg/pyo3 that referenced this issue Aug 14, 2021
The field wasn't defined previously. And the enum wasn't defined as
`[repr(C)]`.

This missing field could result in memory corruption if a Rust-allocated
`PyStatus` was passed to a Python API, which could perform an
out-of-bounds write. In my code, the out-of-bounds write corrupted a
variable on the stack, leading to a segfault due to illegal memory
access. However, this crash only occurred on Rust 1.54! So I initially
mis-attribted it as a compiler bug / regression. It appears that a
low-level Rust change in 1.54.0 changed the LLVM IR in such a way to
cause LLVM optimization passes to produce sufficiently different
assembly code, tickling the crash. See
rust-lang/rust#87947 if you want to see
the wild goose chase I went on in Rust / LLVM land to potentially
pin this on a compiler bug.

Lessen learned: Rust crashes are almost certainly due to use of
`unsafe`.
indygreg added a commit to indygreg/pyo3 that referenced this issue Aug 14, 2021
The field wasn't defined previously. And the enum wasn't defined as
`[repr(C)]`.

This missing field could result in memory corruption if a Rust-allocated
`PyStatus` was passed to a Python API, which could perform an
out-of-bounds write. In my code, the out-of-bounds write corrupted a
variable on the stack, leading to a segfault due to illegal memory
access. However, this crash only occurred on Rust 1.54! So I initially
mis-attribted it as a compiler bug / regression. It appears that a
low-level Rust change in 1.54.0 changed the LLVM IR in such a way to
cause LLVM optimization passes to produce sufficiently different
assembly code, tickling the crash. See
rust-lang/rust#87947 if you want to see
the wild goose chase I went on in Rust / LLVM land to potentially
pin this on a compiler bug.

Lessen learned: Rust crashes are almost certainly due to use of
`unsafe`.
davidhewitt pushed a commit to PyO3/pyo3 that referenced this issue Aug 15, 2021
The field wasn't defined previously. And the enum wasn't defined as
`[repr(C)]`.

This missing field could result in memory corruption if a Rust-allocated
`PyStatus` was passed to a Python API, which could perform an
out-of-bounds write. In my code, the out-of-bounds write corrupted a
variable on the stack, leading to a segfault due to illegal memory
access. However, this crash only occurred on Rust 1.54! So I initially
mis-attribted it as a compiler bug / regression. It appears that a
low-level Rust change in 1.54.0 changed the LLVM IR in such a way to
cause LLVM optimization passes to produce sufficiently different
assembly code, tickling the crash. See
rust-lang/rust#87947 if you want to see
the wild goose chase I went on in Rust / LLVM land to potentially
pin this on a compiler bug.

Lessen learned: Rust crashes are almost certainly due to use of
`unsafe`.
@apiraino apiraino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Mar 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants