wlav / cppyy

Other
384 stars 38 forks source link

Crash when using class defined containing `std::vector` #241

Open marktsuchida opened 1 month ago

marktsuchida commented 1 month ago

I'm getting a crash when trying to access a type defined as struct S { std::vector<unsigned> v; };:

import cppyy
cppyy.cppdef("struct S { std::vector<unsigned> v; };")
cppyy.gbl.S  # Crash, stack trace below

macOS arm64, cppyy 3.1.2, Python 3.12.

On macOS arm64, it crashed when the vector element type was one of char, int, unsigned (shown above), or double, but not with [un]signed char, [unsigned] short, [unsigned] long, [unsigned] long long, float, or bool.

On macOS x86-64 (Rosetta 2), the crash occurred with element types char or unsigned only (among the same set of types tested).

On Linux and Windows I was unable to reproduce the crash.

If I defined instead template <typename T> struct S { std::vector<T> v; };, then I got a crash from cppyy.gbl.S["unsigned"]. Interestingly, the set of types that caused the crash for the template matched the set of types that caused the non-template version to crash, for each of arm64 and x86-64.

Just accessing std::vector (as in cppyy.gbl.std.vector["unsigned"]) did not crash. Furthermore, doing so before running the crashing case prevented the crash: the following does not crash:

import cppyy
cppyy.cppdef("struct S { std::vector<unsigned> v; };")
cppyy.gbl.std.vector["unsigned"]
cppyy.gbl.S  # No crash

Here is a stack trace on macOS arm64 for the first example above:

Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  libCling.so                    0x0000000109541fc8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  libCling.so                    0x000000010955c368 cling::DeclCollector::HandleInterestingDecl(clang::DeclGroupRef) (.cold.1) + 16
2  libCling.so                    0x0000000106bc92d4 cling::DeclCollector::HandleInterestingDecl(clang::DeclGroupRef) + 212
3  libCling.so                    0x00000001072aa16c clang::ASTReader::PassInterestingDeclsToConsumer() + 216
4  libCling.so                    0x0000000107258f34 clang::ASTReader::FinishedDeserializing() + 1148
5  libCling.so                    0x000000010736d324 clang::MultiplexExternalSemaSource::FinishedDeserializing() + 48
6  libCling.so                    0x0000000108aa2560 clang::RecordDecl::LoadFieldsFromExternalStorage() const + 192
7  libCling.so                    0x0000000108aa246c clang::RecordDecl::field_begin() const + 40
8  libCling.so                    0x0000000108c2c878 (anonymous namespace)::EmptySubobjectMap::ComputeEmptySubobjectSizes() + 200
9  libCling.so                    0x0000000108c26374 clang::ASTContext::getASTRecordLayout(clang::RecordDecl const*) const + 948
10 libCling.so                    0x0000000108c2c8d0 (anonymous namespace)::EmptySubobjectMap::ComputeEmptySubobjectSizes() + 288
11 libCling.so                    0x0000000108c26374 clang::ASTContext::getASTRecordLayout(clang::RecordDecl const*) const + 948
12 libCling.so                    0x0000000106b4bc98 CppyyLegacy::TClingDataMemberInfo::Offset() + 172
13 libCoreLegacy.so               0x00000001018c7bb0 CppyyLegacy::TDataMember::GetOffsetCint() const + 104
14 libcppyy.cpython-312-darwin.so 0x00000001010a5960 CPyCppyy::CPPDataMember::Set(unsigned long, unsigned long) + 60
15 libcppyy.cpython-312-darwin.so 0x00000001010fe0a8 CPyCppyy::AddPropertyToClass(_object*, unsigned long, unsigned long) + 76
16 libcppyy.cpython-312-darwin.so 0x00000001010fc898 CPyCppyy::CreateScopeProxy(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, _object*, unsigned int) + 8404
17 libcppyy.cpython-312-darwin.so 0x00000001010b58a0 CPyCppyy::meta_getattro(_object*, _object*) + 656
18 Python                         0x0000000101344668 PyObject_GetAttr + 68
19 Python                         0x00000001013dea60 _PyEval_EvalFrameDefault + 27668
20 Python                         0x00000001013d7bdc PyEval_EvalCode + 184
21 Python                         0x0000000101438b98 run_eval_code_obj + 88
22 Python                         0x0000000101436c28 run_mod + 132
23 Python                         0x00000001014359f0 PyRun_InteractiveOneObjectEx + 560
24 Python                         0x00000001014352e0 _PyRun_InteractiveLoopObject + 156
25 Python                         0x0000000101435178 _PyRun_AnyFileObject + 76
26 Python                         0x0000000101435744 PyRun_AnyFileExFlags + 68
27 Python                         0x0000000101459cac pymain_run_stdin + 164
28 Python                         0x00000001014591bc Py_RunMain + 452
29 Python                         0x00000001014594b0 Py_BytesMain + 40
30 dyld                           0x00000001933b60e0 start + 2360
Trace/BPT trap: 5
wlav commented 1 month ago

Deep in Clang, that's wild. :/

Yes, I can reproduce it. The crash is in Cling calculating the offset of v into the struct S (it's 0 here). Such offsets are needed to address the data member for access.

marktsuchida commented 1 month ago

Yeah, I expected this to be an upstream issue, but wasn't sure where/how best to report it other than here (or how to test whether it is still broken in upstream). Thanks for looking at it.

wlav commented 1 month ago

In DeclCollector::HandleInterestingDecl(DeclGroupRef DGR), the current transaction (m_CurTransaction) is nullptr.

@vgvassilev: any idea how this could happen?

vgvassilev commented 1 month ago

tclingdatamemberinfo::Offset needs PushTrabsactionRAII

wlav commented 1 month ago

Ah, quite. I checked upstream and it had grown one already. Yes, I confirm that that fixes it!

wlav commented 1 month ago

Fix and test are in repo. Thanks all!