Skip to content

engine: deep-copy ReversibleMeta in ResCopy#915

Open
karpfediem wants to merge 2 commits into
purpleidea:masterfrom
karpfediem:repro/reversible-meta-copy-mre
Open

engine: deep-copy ReversibleMeta in ResCopy#915
karpfediem wants to merge 2 commits into
purpleidea:masterfrom
karpfediem:repro/reversible-meta-copy-mre

Conversation

@karpfediem

Copy link
Copy Markdown
Contributor

Fixes a reversible-resource copy bug caused by aliasing *ReversibleMeta.

engine.ResCopy() was reusing the same reversible metadata pointer for the original resource and its copied/reversed form.
Reversal setup mutates that metadata (Disabled, Reversal), so those mutations could leak back into the original live resource.

MRE

First run
file "/tmp/reversible-meta-copy-mre/" {
      state => $const.res.file.state.exists,
}

# Step 1 of the runtime proof for the reversible meta aliasing bug.
#
# Run this file first, let it converge, and then run
# `test/shell/reversible-meta-copy-mre-cleanup.mcl` with the same `--prefix`.
#
# Example:
#   ./mgmt run --prefix /tmp/reversible-meta-copy-mre-prefix \
#     --converged-timeout=2 --no-pgp lang \
#     test/shell/reversible-meta-copy-mre.mcl
#
#   ./mgmt run --prefix /tmp/reversible-meta-copy-mre-prefix \
#     --converged-timeout=2 --no-pgp lang \
#     test/shell/reversible-meta-copy-mre-cleanup.mcl
#
# Expected on a correct engine:
# 1. This run creates `/tmp/reversible-meta-copy-mre/target`.
# 2. The cleanup run logs `adding 1 reversals...` and removes the target.
#
# Buggy engine behavior:
# 1. This run converges and then deletes its own pending reverse state during
#    shutdown cleanup.
# 2. The cleanup run has no stored reversal to add, so the target is left
#    behind.
file "/tmp/reversible-meta-copy-mre/target" {
      state => $const.res.file.state.exists,
      content => "proof\n",

      Meta:reverse => true,
}
Second run
file "/tmp/reversible-meta-copy-mre/" {
      state => $const.res.file.state.exists,
}

Impact

This could cause the original resource to be treated as if it were itself a reversal resource during cleanup, which in turn could delete the pending reverse state that should have been preserved for a later run.

In practice, that means a normal converged reversible resource can disappear from the graph, and the next run has
nothing left to reverse.

Fix

Add (*ReversibleMeta).Copy() and use it in engine.ResCopy() so reversible metadata is copied by value instead of
shared by pointer.

Verification

Added focused Go tests covering:

  • copy isolation for ReversibleMeta
  • Reversed() not mutating the original resource
  • ReversalInit() not mutating the original resource
  • ReversalCleanup() not deleting the original resource's pending reverse file

The MCL repro is a second commit, so feel free to cherry-pick.

@karpfediem karpfediem force-pushed the repro/reversible-meta-copy-mre branch 2 times, most recently from bda82ee to 462c065 Compare April 22, 2026 22:30
Comment thread engine/copy.go
// programming error
panic("reversible interfaces are illogical")
}
dst.SetReversibleMeta(x.ReversibleMeta()) // no need to copy atm

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This comment is so suspicious! haha

I will dig a bit further into this patch this week, thank you!

karpfediem and others added 2 commits April 26, 2026 17:37
Co-authored-by: Codex GPT 5.5 <noreply@openai.com>
Co-authored-by: Codex GPT 5.5 <noreply@openai.com>
@karpfediem karpfediem force-pushed the repro/reversible-meta-copy-mre branch from 462c065 to 625a524 Compare April 26, 2026 15:37
@purpleidea

purpleidea commented May 1, 2026

Copy link
Copy Markdown
Owner

Sorry for my delay here...

This run converges and then deletes its own pending reverse state during shutdown cleanup.

It should be deleting the created file on clean shutdown with ^C. Is that not occurring or it's not what you expected?

@purpleidea purpleidea force-pushed the master branch 2 times, most recently from b7ee313 to cb70565 Compare June 4, 2026 05:45
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