Skip to content

[fix] Null-guard the cling.printValue lookup in op_str - #56

Open
conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
chicagotrading:opstr-null-guard
Open

[fix] Null-guard the cling.printValue lookup in op_str#56
conrade-ctc wants to merge 1 commit into
compiler-research:mainfrom
chicagotrading:opstr-null-guard

Conversation

@conrade-ctc

Copy link
Copy Markdown

str() on any instance without an ostream inserter segfaults on current
main. Commit 5a33027 dropped the faked cling::runtime::gCling, and the
pretty-print fallback in op_str then dereferenced the failed
cppjit.gbl.cling lookup. This guards both lookups, clears the
AttributeError, and falls back to the generic repr.

Repro:

import cppjit
cppjit.cppdef("struct Bare { int x; };")
str(cppjit.gbl.Bare())      # SIGSEGV

A regression test is included. The crash kills the interpreter, so the test
asserts the fixed behaviour rather than the crash.

@conrade-ctc
conrade-ctc force-pushed the opstr-null-guard branch 4 times, most recently from cc6b1ab to 06c8899 Compare August 31, 2026 19:54
Comment thread src/cpyrt/CPPInstance.cxx
PyObject* cl = PyObject_GetAttrString(gbl, (char*)"cling");
printValue = PyObject_GetAttrString(cl, (char*)"printValue");
Py_DECREF(cl);
// no cling namespace exists unless user code declares one

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can just short-circuit this path completely if we know the interpreter is clang-repl, since that lookup would always return null. We could use the compile-time definition CPPJIT_USE_CLING, or a runtime check like in test/support.py

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — done. The whole pretty-printing block now sits behind #ifdef CPPJIT_USE_CLING, so clang-repl builds compile it out and str() falls straight through to the generic repr; strings on the clang-repl libcppjit.so shows the printValue lookup gone, and the object shrinks slightly. One thing the gate needed: CPPJIT_USE_CLING was only ever a CMake option and never reached the sources, so I added the matching target_compile_definitions entry — without it the #ifdef would have been false on the cling build too. The null-guards stay inside the cling branch, in case an odd cling state leaves the lookup empty. Worth naming the trade-off: a user-declared namespace cling { printValue } is no longer honored on clang-repl, which I think is right given the native value-printing direction in compiler-research/CppInterOp#1100.

conrade-ctc pushed a commit to chicagotrading/cppjit that referenced this pull request Aug 31, 2026
The in-process test52 crashed the llvm22 and cling CI lanes with a
SIGSEGV, hiding the rest of the suite. Match
compiler-research#56's head: the cling pretty-print path in
op_str now compiles out entirely behind CPPJIT_USE_CLING on
clang-repl, with the matching CMake compile-definition wiring, and the
regression test runs its repro in a subprocess so a crash fails the
assertion instead of the runner.

Co-developed-with-the-help-of: Claude Code (Sonnet 5, human in the loop)
Commit 5a33027 dropped the faked cling::runtime::gCling and with it the
last cling namespace in the interpreter. The pretty-print fallback in
op_str then dereferenced the failed cppjit.gbl.cling lookup. str() of
any instance without an ostream inserter crashed with SIGSEGV. Guard
both lookups, clear the AttributeError, and fall back to the generic
repr.

clang-repl has no cling namespace to look up, so the whole pretty-print
path now compiles out behind CPPJIT_USE_CLING. CMake gains the matching
compile definition: the option existed but never reached the sources.
The null-guards stay on the cling side. This drops the old escape hatch
where a user-declared namespace cling { printValue } was honored on
clang-repl, which matches the native value-printing direction in
compiler-research/CppInterOp#1100.

The regression test runs the repro in a subprocess, so a return of the
crash cannot kill the test runner. The subprocess gets this process's
sys.path through PYTHONPATH, because a build system can put cppjit on
the path in-process instead. A clean exit passes, whichever repr form
the backend prints. Output that names the upstream toString stub
xfails. Anything else fails and reports the child's output.

Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
Comment thread src/cpyrt/CPPInstance.cxx
// reasons)
// reasons). Cling only: clang-repl has no cling namespace to look up, so the
// whole path compiles out and str() falls through to the generic repr.
#ifdef CPPJIT_USE_CLING

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be required to CppInterOp’s toString interface which will still crash for clang-repl but this time we can fix it there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to make that change here: route str() through Cpp::ObjToString and drop the cling-only block. clang-repl would then keep failing in toString until compiler-research/CppInterOp#1100 lands the fix there. Do you want that in this PR, or should we keep the short-circuit and switch once #1100 is fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants