Skip to content

[core] Fix TDataMember::GetOffsetCint interference with GetOffset - #23844

Open
ravindra-RKB wants to merge 1 commit into
root-project:masterfrom
ravindra-RKB:fix-tdatamember-getoffsetcint
Open

ravindra-RKB wants to merge 1 commit into
root-project:masterfrom
ravindra-RKB:fix-tdatamember-getoffsetcint

Conversation

@ravindra-RKB

Copy link
Copy Markdown
Contributor

Description

Fixes #23777

TDataMember::GetOffsetCint() previously returned early if fOffset >= 0. However, when TDataMember::GetOffset() is invoked first on a data member (such as an enum constant or members where fOffset is computed as 0), it caches fOffset = 0. Consequently, subsequent calls to GetOffsetCint() would return the cached 0 instead of querying the Cling interpreter for the actual offset/address.

This change updates GetOffsetCint() to prefer gCling->DataMemberInfo_Offset(dm->fInfo) whenever fInfo is available and valid, and only fall back to fOffset when fInfo is not available. A regression unit test covering #23777 has also been added to roottest/root/meta/unit/datamem.cxx.

Checklist

  • Changes are minimal and focused
  • Added regression unit test verifying the fix
  • Follows ROOT coding conventions

@pcanal pcanal self-assigned this Oct 26, 2026
Comment on lines +501 to +505
if (dm->IsValid()) {
if (dm->fInfo) return gCling->DataMemberInfo_Offset(dm->fInfo);
if (fOffset >= 0) return fOffset;
}
return -1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am not sure this is the right solution. A priori the value can be as well cached for these call as for the previous call. It is not clear whether there is really a need for both functions to be distinct. However this need a deep analysis of the usage pattern in ROOT and in user codes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @pcanal. Should we cache this into a dedicated fOffsetCint member instead, or do you prefer consolidating both functions? Happy to adapt based on what fits best.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The firsts step is to do an analysis of whether it makes sense or not to merge the 2 or to protect them from being called in the wrong context.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking through the codebase usages:

  • GetOffset() is used for instance byte offsets (TStreamerInfo, RFieldMeta, TTree). For non-static data members, both functions yield the same offset.
  • For static variables and enum constants, GetOffset() returns 0 because BuildRealData() does not track them, whereas GetOffsetCint() queries Cling, which returns the address/value.
  • If called on an enum or static member, GetOffset() is technically the "wrong context" (no instance offset exists) and erroneously caches 0 into fOffset.

Would it make sense to protect GetOffset() so it returns -1 (or avoids setting fOffset = 0) when Property() & (kIsStatic | kIsEnum), or should GetOffset() delegate to Cling for static/enum members as well?

@github-actions

Copy link
Copy Markdown

Test Results

    23 files      23 suites   3d 17h 15m 4s ⏱️
 3 896 tests  3 896 ✅ 0 💤 0 ❌
79 903 runs  79 903 ✅ 0 💤 0 ❌

Results for commit 5538730.

This branch has not been deployed

No deployments
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.

TDataMember::GetOffset interfers to TDataMember::GetOffsetCint

2 participants