CadQuery / CadQuery/OCP

TDF_Label.FindAttribute segfaults when the attribute is absent

Open
#225 0 comments 0 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.