TDF_Label.FindAttribute segfaults when the attribute is absent
- Dominant language
- C++
- Stars
- 197
- Forks
- 47
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 6
Description
## Summary
`TDF_Label.FindAttribute` **segfaults** when the requested attribute is not present on the label.
When the attribute *is* present it returns normally. There is no exception to catch — the process
dies with SIGSEGV.
This is related to #153 (open) and #55 (closed), but both of those report the *attribute-present*
path returning an unpopulated handle. The absent path crashing does not appear to be reported.
## Minimal reproducer
No STEP file or external data needed:
```python
from OCP.TCollection import TCollection_ExtendedString
from OCP.TDocStd import TDocStd_Document
from OCP.TDataStd import TDataStd_Name
doc = TDocStd_Document(TCollection_ExtendedString("XCAF"))
label = doc.Main() # a label with no TDataStd_Name
print("IsAttribute:", label.IsAttribute(TDataStd_Name.GetID_s())) # -> False, safe
n = TDataStd_Name()
label.FindAttribute(TDataStd_Name.GetID_s(), n) # -> SIGSEGV
```
```
IsAttribute: False
[1] segmentation fault
```
Exit status 139.
## Control: attribute present works
```python
from OCP.TCollection import TCollection_ExtendedString
from OCP.TDocStd import TDocStd_Document
from OCP.TDataStd import TDataStd_Name
doc = TDocStd_Document(TCollection_ExtendedString("XCAF"))
label = doc.Main()
TDataStd_Name.Set_s(label, TCollection_ExtendedString("hello"))
n = TDataStd_Name()
print("returned:", label.FindAttribute(TDataStd_Name.GetID_s(), n)) # True
print("name:", n.Get().ToExtString()) # hello
```
Runs clean, exit 0.
## Not specific to `TDataStd_Name`
Same crash with the same shape of call:
| attribute type | exit status |
| --- | --- |
| `TDataStd_Name` | 139 (SIGSEGV) |
| `TDataStd_Integer` | 139 (SIGSEGV) |
| `TDataStd_Real` | 139 (SIGSEGV) |
## Environment
- `cadquery-ocp-novtk` 7.9.3.1 (OCCT 7.9.3)
- Python 3.14.7
- macOS 15 (Darwin 25.6.0), arm64
## Safe alternatives
Both of these work on the exact label that crashes `FindAttribute`:
- `label.IsAttribute(guid)` returns `False` without crashing.
- `TDF_AttributeIterator(label)` enumerates the label's attributes normally. This is the
reimplementation suggested in #153 and it appears to be the reliable path today.
## Real-world impact
This is reachable from ordinary library code. `build123d`'s `import_step` calls `FindAttribute`
unguarded on every assembly component label to read its name, so any STEP file containing an
assembly component **without** a name attribute kills the interpreter. I hit it on the public NIST
MBE PMI conformance model `nist_ctc_02_asme1_ap242-e2.stp`, whose component label carries
`TNaming_NamedShape`, `TDataStd_UAttribute`, `TDF_TagSource` and `TDataStd_TreeNode` but no
`TDataStd_Name`. Because it is a segfault rather than an exception, a service cannot defend itself
against it with `try`/`except`.
## Note on cause
I have verified the behavioural boundary (absent → crash, present → fine, `IsAttribute` and
`TDF_AttributeIterator` safe) but not the underlying mechanism. Given #55 and #153 it looks like the
binding's handling of the `Handle(TDF_Attribute)&` out-parameter is wrong in a way that is merely
lossy when the attribute is found and memory-unsafe when it is not — but that is inference, not
something I have confirmed in the binding code.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.