Skip to content

docs: what nrn_sectionlist_iterator_next does with a deleted section - #3949

Open
ec1dev wants to merge 6 commits into
neuronsimulator:masterfrom
ec1dev:sectionlist-iterator-docs
Open

ec1dev wants to merge 6 commits into
neuronsimulator:masterfrom
ec1dev:sectionlist-iterator-docs

Conversation

@ec1dev

@ec1dev ec1dev commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #3947, which merged before I pushed this.

nrn_sectionlist_iterator_next now drops a deleted section's item and the list's reference to it. If that was the last reference the Section is freed, so a caller that keeps a Section* across passes needs nrn_section_ref. It can also return NULL when only deleted sections were left, which the test already handles but the docs didn't say.

Since nrn_sectionlist_iterator_next returns NULL at the end of the list as well, the examples now loop on its result alone, and the docs say nrn_sectionlist_iterator_done isn't needed for a loop (it stays for existing code). The api tests use that loop too. The docs also say a loop must not delete or remove a section it hasn't reached yet: in nrn_allsec()'s list delete_section frees the item right away, and SectionList.remove() frees it in a SectionList, so the iterator can read freed memory. That was already the case before.

@codecov

codecov Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.68%. Comparing base (ef8f20d) to head (a81be98).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3949   +/-   ##
=======================================
  Coverage   68.67%   68.68%           
=======================================
  Files         714      716    +2     
  Lines      115483   115555   +72     
=======================================
+ Hits        79311    79367   +56     
- Misses      36172    36188   +16     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread docs/capi.rst Outdated

:param sl: Pointer to the SectionListIterator.
:returns: Pointer to the next Section.
:returns: Pointer to the next Section, or NULL if only deleted sections were left.

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.

what if there were never sections in the list? Would it be more accurate to say "or NULL if no active sections are left"?

In any case, I think this should be in the present tense.

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.

Yes, that's more accurate: it returns NULL whenever it reaches the end, including an empty list, so I used your wording in the present tense (45d48f3).

nrn_sectionlist_iterator_done does not skip deleted sections, so with only
deleted sections left it returns 0 and next returns NULL.
Comment thread docs/capi.rst Outdated
@@ -2000,6 +2009,9 @@ Miscellaneous
SectionListIterator* iter = nrn_sectionlist_iterator_new(section_list);
while (!nrn_sectionlist_iterator_done(iter)) {

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.

Do we still need the nrn_sectionlist_iterator_done call? It's not great if we have to do TWO checks for valid sections

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.

No, it isn't needed. nrn_sectionlist_iterator_next returns NULL at the end of the list too, not only when the sections left are deleted, so checking its result is enough. 168ef64 changes the nrn_allsec example to that loop and drops the example under nrn_sectionlist_iterator_done, which now says a loop doesn't need it (it stays for existing code). The api tests use the same loop now, and sectionlist_iterator_deleted.cpp also checks that done is non-zero once next returns NULL.

While checking this I found that a loop must not delete or remove a section it hasn't reached yet. In nrn_allsec()'s list delete_section frees the item right away, and SectionList.remove() does the same in a SectionList, so if that section is the next one the iterator reads freed memory (valgrind shows it). That was already true with the old loop. a427371 says so in the docs. Deleting or removing the section just returned is fine.

nrn_sectionlist_iterator_next returns NULL at the end of the list as well
as when only deleted sections are left, so the examples check only its
result. The iterator test uses that loop and checks that
nrn_sectionlist_iterator_done is non-zero once next returns NULL.
… tests

Deleting a section during an nrn_allsec() loop frees its list item at
once, and SectionList.remove() frees one in a SectionList, so a loop must
not delete or remove a section it has not reached yet (valgrind shows the
iterator reading the freed item). The section just returned is fine.
The skip-and-drop sentence applies to SectionLists. sections.cpp and
sectionlist_to_array.cpp use the one-check loop too.
Comment thread docs/capi.rst Outdated
break; // only deleted sections were left
}
Section* sec;
while ((sec = nrn_sectionlist_iterator_next(iter))) {

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.

one more set of parentheses than needed

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.

The inner pair was there because gcc -Wall warns about a bare assignment as the condition ("suggest parentheses around assignment used as truth value"). a81be98 compares with NULL instead, which needs no extra pair.

Comment thread docs/capi.rst
// Process Section
}
nrn_sectionlist_iterator_free(iter);
It does not look past deleted sections, so when only deleted sections are

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.

so is this still useful? I don't think we can get rid of it, unfortunately, but I think we can have the docs point to the way to loop without doing this

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.

It isn't needed for a loop, but it stays for existing code. a81be98 starts its docs with a note that points to the one-check loop in nrn_allsec.

… need it

Lead its docs with a note that points to the one-check loop in nrn_allsec.
The nrn_allsec example compares with NULL instead of doubling the
parentheses (gcc -Wall warns about a bare assignment as the condition).
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants