PIQP win diag: loop conic.py 5x, dump real test tracebacks #22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Reproduce macos-14 py3.14 test_DMcrash SIGSEGV with EXACT failing artifact | |
| # Mac py3.14 test-python keeps failing with: | |
| # test_DMcrash (matrix.Matrixtests.test_DMcrash) ... Segmentation fault: 11 | |
| # despite the SWIG owning-bytes fix landing in nightly-abi3 (linux verified | |
| # locally with debug py3.14 — passes cleanly). | |
| # | |
| # This workflow pulls the EXACT artifact that the failing test-python job | |
| # consumed (run 25970736288, artifact casadi-osx-arm64-py311) and runs | |
| # the same test path with `-X faulthandler` to capture the C-frame trace | |
| # that bare CI doesn't expose. | |
| # | |
| # Also runs against the nightly-abi3 release-asset (.whl) as a control — | |
| # if the release-asset wheel passes but the workflow-artifact .zip fails, | |
| # we know they're not byte-identical despite both originating from the | |
| # same python-osx job. | |
| on: [push, workflow_dispatch] | |
| jobs: | |
| diag: | |
| runs-on: macos-14 | |
| steps: | |
| - name: Checkout casadi/casadi (abi3) for the test/python dir | |
| uses: actions/checkout@v6.0.2 | |
| with: | |
| repository: casadi/casadi | |
| ref: abi3 | |
| - name: Download FAILING CI artifact (casadi-osx-arm64-py311 from run 25970736288) | |
| uses: actions/download-artifact@v8.0.1 | |
| with: | |
| name: casadi-osx-arm64-py311 | |
| run-id: 25970736288 | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| repository: casadi/casadi | |
| - name: Layout | |
| run: | | |
| ls -la | |
| ls -la *.zip || true | |
| - name: Unpack artifact like CI (mirror binaries.yml line 1100) | |
| run: | | |
| unzip -q casadi-osx-arm64-py311.zip -d artifact | |
| ls artifact/casadi/ | head -10 | |
| echo "--- md5 of artifact-derived _casadi.so ---" | |
| md5 artifact/casadi/_casadi.so | |
| - name: Also download the nightly-abi3 release-asset .whl (control) | |
| run: | | |
| curl -sL -o release.whl \ | |
| https://github.com/casadi/casadi/releases/download/nightly-abi3/casadi-3.7.2.dev%2Babi3-cp311-abi3-macosx_11_0_arm64.whl | |
| mkdir -p release && unzip -q release.whl -d release | |
| echo "--- md5 of release-asset _casadi.so ---" | |
| md5 release/casadi/_casadi.so | |
| echo "--- diff metadata ---" | |
| ls -la artifact/casadi/_casadi.so release/casadi/_casadi.so | |
| - name: Inspect mach-o headers and dependencies | |
| run: | | |
| F=artifact/casadi/_casadi.so | |
| file $F | |
| echo "--- otool -L (linked dylibs) ---" | |
| otool -L $F | head -20 | |
| echo "--- nm: PyUnicode_AsUTF8String? (the fix's call) ---" | |
| nm -gU $F 2>/dev/null | grep -i PyUnicode | head -10 || true | |
| nm -u $F 2>/dev/null | grep -i PyUnicode | head -10 || true | |
| - name: Set up conda py3.14 (matches CI) | |
| uses: conda-incubator/setup-miniconda@77236efeba76d591229f44c36f2469426cc33dec | |
| with: | |
| python-version: 3.14 | |
| activate-environment: py3.14 | |
| auto-update-conda: true | |
| channels: pkgs/main, conda-forge, conda-forge/label/python_rc | |
| - name: "Install deps (mirror CI: pip + numpy scipy pandas looseversion pyright)" | |
| shell: bash -el {0} | |
| run: | | |
| conda install -y pip | |
| pip install numpy scipy pandas looseversion pyright | |
| - name: Try import (artifact wheel) | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| set -x | |
| which python && python -V | |
| python -c 'import casadi; print("import OK", casadi.__version__)' 2>&1 | tail -10 | |
| - name: Reproduce test_DMcrash on ARTIFACT wheel under -X faulthandler | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| set -x | |
| python -X faulthandler -c " | |
| from casadi import DM | |
| print('starting test_DMcrash path') | |
| try: | |
| DM([DM([1,2]), DM([1,2])]) | |
| print('NO EXCEPTION (unexpected)') | |
| except Exception as e: | |
| print('caught:', type(e).__name__) | |
| print('msg:', repr(str(e))[:300]) | |
| a = DM([DM([1]), DM([2])]) | |
| print('second DM OK, value:', a) | |
| print('all clear') | |
| " 2>&1 | tail -80 | |
| echo "exit=$?" | |
| - name: Run full matrix.py suite (matches the actual failing test path) | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| set -x | |
| cd test/python | |
| python -X faulthandler -c " | |
| import sys, unittest | |
| sys.path.insert(0, '.') | |
| import matrix | |
| res = unittest.TextTestRunner(verbosity=2).run( | |
| unittest.TestLoader().loadTestsFromModule(matrix)) | |
| print('tests run:', res.testsRun, 'failures:', len(res.failures), 'errors:', len(res.errors)) | |
| " 2>&1 | tail -50 | |
| echo "exit=$?" | |
| - name: Reproduce test_DMcrash on RELEASE-ASSET wheel under -X faulthandler (control) | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/release | |
| run: | | |
| set -x | |
| python -X faulthandler -c " | |
| from casadi import DM | |
| try: | |
| DM([DM([1,2]), DM([1,2])]) | |
| print('NO EXCEPTION') | |
| except Exception as e: | |
| print('caught:', type(e).__name__, str(e)[:200]) | |
| a = DM([DM([1]), DM([2])]) | |
| print('release-asset all clear') | |
| " 2>&1 | tail -40 | |
| echo "exit=$?" | |
| - name: Try with MallocStackLogging + MallocScribble for UAF detection | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| MallocScribble: "1" | |
| MallocPreScribble: "1" | |
| MallocGuardEdges: "1" | |
| run: | | |
| set -x | |
| python -X faulthandler -c " | |
| from casadi import DM | |
| try: | |
| DM([DM([1,2]), DM([1,2])]) | |
| except Exception as e: | |
| print('caught:', type(e).__name__, str(e)[:200]) | |
| print('mallocscribble clear') | |
| " 2>&1 | tail -40 | |
| # ===== CONTROL: same wheel + py3.11 (to isolate py3.14-specific bug) ===== | |
| - name: Set up conda py3.11 (control) | |
| uses: conda-incubator/setup-miniconda@77236efeba76d591229f44c36f2469426cc33dec | |
| with: | |
| python-version: "3.11" | |
| activate-environment: py3.11 | |
| auto-update-conda: true | |
| channels: pkgs/main, conda-forge | |
| - name: "Install deps in py3.11 (pip + numpy)" | |
| shell: bash -el {0} | |
| run: | | |
| conda activate py3.11 | |
| conda install -y pip | |
| pip install numpy | |
| - name: Reproduce test_DMcrash under py3.11 (control) — same wheel | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| conda activate py3.11 | |
| which python && python -V | |
| set -x | |
| python -X faulthandler -c " | |
| from casadi import DM | |
| try: | |
| DM([DM([1,2]), DM([1,2])]) | |
| except Exception as e: | |
| print('py3.11 caught:', type(e).__name__, str(e)[:200]) | |
| a = DM([DM([1]), DM([2])]) | |
| print('py3.11 all clear, a =', a) | |
| " 2>&1 | tail -40 | |
| echo "py3.11 exit=$?" | |
| # ===== lldb attach for C-frame capture (py3.14 again) ===== | |
| - name: Capture crash with lldb on py3.14 | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| conda activate py3.14 | |
| which python && python -V | |
| # Generate a tiny script first (lldb is happier with file input) | |
| cat > /tmp/crashprobe.py <<'PYEOF' | |
| import sys | |
| print('about to call DM([DM([1,2]), DM([1,2])])', flush=True) | |
| from casadi import DM | |
| DM([DM([1,2]), DM([1,2])]) | |
| print('unreachable: did not crash', flush=True) | |
| PYEOF | |
| # Run under lldb, dump backtrace on SIGSEGV | |
| lldb -o "settings set target.process.stop-on-exec false" \ | |
| -o "run /tmp/crashprobe.py" \ | |
| -o "thread backtrace all" \ | |
| -o "register read" \ | |
| -o "image lookup --address \$pc" \ | |
| -o "quit" \ | |
| -- $(which python) 2>&1 | tail -120 || true | |
| # ===== Refcount instrumentation: print sys.getrefcount before/around the crash ===== | |
| - name: Refcount probe (does PyTuple_SET_ITEM in funpack steal a borrowed ref?) | |
| continue-on-error: true | |
| shell: bash -el {0} | |
| env: | |
| PYTHONPATH: ${{ github.workspace }}/artifact | |
| run: | | |
| conda activate py3.14 | |
| set -x | |
| python -X faulthandler -c " | |
| import sys | |
| from casadi import DM | |
| a = DM([1,2]) | |
| b = DM([1,2]) | |
| arg_list = [a, b] | |
| print('before call: refcount(a)=', sys.getrefcount(a), 'refcount(arg_list)=', sys.getrefcount(arg_list), flush=True) | |
| try: | |
| DM(arg_list) | |
| except Exception as e: | |
| print('caught:', type(e).__name__, str(e)[:200], flush=True) | |
| print('after call: refcount(a)=', sys.getrefcount(a), 'refcount(arg_list)=', sys.getrefcount(arg_list), flush=True) | |
| " 2>&1 | tail -40 | |
| echo "refcount-probe exit=$?" |