Skip to content

Asan fix#7

Merged
tupek2 merged 4 commits into
mainfrom
asan_fix
Apr 13, 2026
Merged

Asan fix#7
tupek2 merged 4 commits into
mainfrom
asan_fix

Conversation

@tupek2

@tupek2 tupek2 commented Apr 9, 2026

Copy link
Copy Markdown
Collaborator

The original bug was a teardown use-after-free.

A State object keeps a raw pointer to its DataStore. Normally that is fine because the DataStore is still alive when the State destructor runs. But ASan found a case where a copied State outlived the last owner of the DataStore. When that late-destroyed State ran its destructor, it called back into DataStore::try_to_free() through a dangling pointer. That is the crash.

The first fix added a lifetime token so a State could tell whether its DataStore was already gone. That part was correct. But the first version also changed the destructor path so it stopped calling try_to_free() in normal cases. That avoided the crash, but it also broke one of gretl's important behaviors: freeing state memory once a step is inactive and no external handles are keeping it alive.

The final fix keeps the lifetime token, but narrows the logic:

  • when a State is destroyed or reassigned, it first saves the old datastore pointer, old step, and old lifetime token
  • then it clears or rebinds the State
  • then it only calls try_to_free() if the saved token says the old DataStore is still alive

This gives both required behaviors:

  • if the DataStore is already destroyed, the State destructor does nothing dangerous
  • if the DataStore is still alive, normal try_to_free() logic still runs, so gretl can evict inactive state data from memory

The added tests check both sides:

  • the ASan regression test proves we no longer touch a dead DataStore
  • the new eviction tests prove state payloads are still actually dropped when the last external handle goes away

@tupek2 tupek2 requested review from btalamini and chapman39 April 9, 2026 18:54
Comment thread src/gretl/state_base.hpp
: dataStore_(dataStore), lifetimeToken_(std::move(lifetimeToken)), primal_(primal)
{
}
DataStore* dataStore_; ///< datastore

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why not store dataStore_itself as a weak_ptr? which eliminates the use of a raw pointer and may solve this lifetime issue as well.

@chapman39 chapman39 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

i tested this and can confirm it eliminates the heap use after free issue

@tupek2 tupek2 merged commit c682642 into main Apr 13, 2026
13 checks passed
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