Skip to content

[cling] Fix infinite recursion when printing self-referencing containers#21072

Merged
dpiparo merged 1 commit into
root-project:masterfrom
devajithvs:nlohmann_fix
Jan 30, 2026
Merged

[cling] Fix infinite recursion when printing self-referencing containers#21072
dpiparo merged 1 commit into
root-project:masterfrom
devajithvs:nlohmann_fix

Conversation

@devajithvs
Copy link
Copy Markdown
Contributor

Some container types (e.g., nlohmann::json scalar values) have iterators that dereference to the container itself, causing infinite recursion in printValue_impl.

This Pull request:

Changes or fixes:

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

This PR fixes #21058

Comment thread interpreter/cling/test/Prompt/ValuePrinter/Recursion.C
Comment on lines +214 to +215
// If the dereferenced iterator points to the container itself, we have
// infinite recursion. This occurs with scalar values in nlohmann::json
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 confused. In the example, the 'points to the container itself' happens only if the container is empty and thus this line should not be reached (see line 208).

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.

This is probably related to the odd implementation mentioned at https://github.com/root-project/root/pull/21072/changes#r2742975180

Copy link
Copy Markdown
Contributor Author

@devajithvs devajithvs Jan 30, 2026

Choose a reason for hiding this comment

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

This is a problem in nlohmann::json, scalar values are iterable and can dereference to themselves.

root [0] nlohmann::json j;
root [1] j[0] = 1;
root [2] auto it = j.begin();
root [3] bool(it == j.end())
(bool) false
root [4] auto& elem = *it;
root [5] auto elem_it = elem.begin();
root [6] bool(elem_it == elem.end()) // line 208 check
(bool) false
root [7] bool(&elem == &(*elem_it)) // iterator dereferences to itself and infinite recursion
(bool) true

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.

I was trying to somewhat mimic what scalar values does in nlohmann::json, I have simplified the test case to avoid this confusion.


// When empty (scalar), iterate over self
auto begin() const { return data.empty() ? this : &data[0]; }
auto end() const { return data.empty() ? this + 1 : &data[0] + data.size(); }
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.

Suggested change
auto end() const { return data.empty() ? this + 1 : &data[0] + data.size(); }
auto end() const { return data.empty() ? this : &data[0] + data.size(); }

Otherwise we don't seem to have the invariant

object->empty() == ( object->begin() == object->end() );

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 29, 2026

Test Results

    22 files      22 suites   3d 16h 9m 35s ⏱️
 3 775 tests  3 775 ✅ 0 💤 0 ❌
75 972 runs  75 972 ✅ 0 💤 0 ❌

Results for commit fe20f93.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Member

@dpiparo dpiparo left a comment

Choose a reason for hiding this comment

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

lgtm once this comment is addressed.

Some container types (e.g., nlohmann::json scalar values) have iterators
that dereference to the container itself, causing infinite recursion in
`printValue_impl`.
@dpiparo dpiparo merged commit c8a3d6a into root-project:master Jan 30, 2026
30 checks passed
public:
RecursionTest() = default;
auto begin() const { return this; } // iterate over self
auto end() const { return this + 1; } // just to make sure begin() != end()
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.

Suggested change
auto end() const { return this + 1; } // just to make sure begin() != end()
auto end() const { return this + 1; } // Hard code the size of the collection to be exactly one and it 'just' contains this object.

@ferdymercury
Copy link
Copy Markdown
Collaborator

Thanks!! Question: does this PR also fix by chance the infinite loop seen in #10140 (comment) ?

@pcanal
Copy link
Copy Markdown
Member

pcanal commented Jan 30, 2026

Question: does this PR also fix by chance the infinite loop seen in #10140 (comment) ?

That is very unlikely.

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.

ROOT interpreter crashes when using nlohmann::json

5 participants