Skip to content

Drop animation targets that fall outside the binding's scope in resolveTargets.#3583

Open
ooLittlePanda wants to merge 1 commit into
mainfrom
bugfix/limit_node_scope
Open

Drop animation targets that fall outside the binding's scope in resolveTargets.#3583
ooLittlePanda wants to merge 1 commit into
mainfrom
bugfix/limit_node_scope

Conversation

@ooLittlePanda

@ooLittlePanda ooLittlePanda commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

PAGTimeline::resolveTargets 和 DataBindRuntime::bind之前通过 findNode 扁平查找 target,未按 binding 作用域过滤,document 级动画/数据绑定可能越界命中嵌套 Composition 内部节点。
修复:resolveTargets/bind 用 contains()提前过滤越界 target。

@codecov-commenter

codecov-commenter commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 30.00000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.28%. Comparing base (4d30d01) to head (2d70790).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/pagx/DataBindRuntime.cpp 0.00% 2 Missing and 1 partial ⚠️
src/pagx/PAGTimeline.cpp 40.00% 1 Missing and 2 partials ⚠️
src/renderer/LayerBuilder.h 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3583      +/-   ##
==========================================
+ Coverage   81.30%   82.28%   +0.98%     
==========================================
  Files         653      691      +38     
  Lines       77290    87963   +10673     
  Branches    21918    25283    +3365     
==========================================
+ Hits        62837    72383    +9546     
- Misses      10000    10300     +300     
- Partials     4453     5280     +827     

☔ 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.

@ooLittlePanda ooLittlePanda force-pushed the bugfix/limit_node_scope branch 2 times, most recently from 20f2e91 to c6176bf Compare July 14, 2026 11:17
…scope.

PAGTimeline::resolveTargets 和 DataBindRuntime::bind之前通过 findNode 扁平查找 target,未按 binding 作用域过滤,document 级动画/数据绑定可能越界命中嵌套 Composition 内部节点。
修复:resolveTargets/bind 用 contains()提前过滤越界 target。
@ooLittlePanda ooLittlePanda force-pushed the bugfix/limit_node_scope branch from c6176bf to 2d70790 Compare July 14, 2026 11:18
// Callers (PAGTimeline::resolveTargets, DataBindRuntime::bind) already drop out-of-scope
// targets via contains(), so a miss here means that scope contract was broken upstream. The
// return false below keeps release builds graceful.
DEBUG_ASSERT(false);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

【真实回归风险,建议移除该断言】此断言假设"miss 只可能因上游 scope 契约被破坏",但存在合法的缓存过期路径会触发 abort:top-level timeline 的 resolvedTargets 缓存仅在 timeline 节点(Animation/AnimationObject/Channel)变化时才重建(PAGScene.cpp timelineDirty)。当某 top-level animation 的 target 普通 Layer 被删除时,refreshNodes 会 binding->remove(node)(runtime/PAGComposition.cpp:340/402),但 timelineDirty=false,缓存不重建、仍持有已删节点。下一帧 apply()→ApplyResolved→binding->apply(deletedNode) 即 miss,DEBUG_ASSERT(false) 在 Debug 下展开为 ABORT 直接终止进程。该 miss 在改动前是静默 return false 的正常降级,本次把一条合法运行时路径变成了 Debug 崩溃。建议移除该断言,或修正缓存失效逻辑使 target 增删也触发 resetTimelines。

Comment thread src/pagx/PAGTimeline.cpp
}
if (!resolved) {
resolveTargets();
resolveTargets(effectiveBinding);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

【缓存与过滤 binding 潜在不一致】top-level timeline 首次 apply() 用当时的 effectiveBinding(root binding 内容)过滤并永久缓存 resolvedTargets,此后缓存仅在 timeline 节点脏时重建。但 root binding 内容可被增量刷新就地增删 target(runtime/PAGComposition.cpp refreshNodes)。若某合法 target 在首次 resolve 时尚未 build(时序),或过滤后才有新 target 加入,缓存都不会重建,导致合法 target 被永久丢弃或缓存陈旧。此问题与上一条 LayerBuilder.h 断言同源——本质是"target 增删未纳入缓存失效条件"。请确认 target 层增删是否一定伴随 timeline 脏;据 PAGScene.cpp 的 timelineDirty 判定看,并不成立。

Comment thread src/pagx/PAGTimeline.cpp
// Drop targets outside this binding's scope. findNode does a flat document-wide lookup, so it
// can resolve a node living inside a nested composition; that node is bound in the composition's
// own binding, not here, so applying to it would cross the composition boundary.
if (!binding->contains(targetNode)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

【新增 scope 过滤逻辑零测试覆盖】本次核心过滤分支(此处及 DataBindRuntime::bind 的 contains 过滤)没有任何测试覆盖:(a) 越界 target 被正确丢弃;(b) 同作用域合法 target 不被误丢弃;(c) 上面提到的删除 target 层后再渲染的 abort 场景。Codecov 显示补丁覆盖率仅 30%,PAGTimeline.cpp 补丁 40%、DataBindRuntime.cpp 0%。建议补充针对性测试,尤其覆盖跨 composition 边界的越界命中被正确拦截、以及删除 target 层的回归场景。

continue;
}
// Drop out-of-scope targets. findNode does a flat document-wide lookup, so it can resolve a node
// living inside a nested composition; that node is bound in the composition's own binding, not

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

【两处过滤对 binding==nullptr 的语义相反,建议统一】此处 bind() 用 binding != nullptr && !binding->contains(...),即 binding 为空时跳过过滤、退回越界风险;而 PAGTimeline::resolveTargets 中 binding 为空时直接 return(什么都不解析)。两处镜像逻辑对空 binding 的处理正好相反,容易误导后续维护者。虽然当前调用方均传 comp->binding.get() 保证非空,但建议统一空 binding 的防御语义(要么都视为无作用域直接跳过解析/绑定,要么都当作错误)。

Comment thread src/pagx/PAGTimeline.cpp
}

void PAGTimeline::resolveTargets() {
void PAGTimeline::resolveTargets(const RuntimeBinding* binding) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

【变量遮蔽,建议改名】新参数 binding 与成员 PAGTimeline::binding 同名,函数体内 binding 指参数、需 this->binding 才能访问成员,属变量遮蔽(shadowing),可读性差且易埋隐患(例如误以为过滤用的是成员 binding)。建议将参数改名为 scopeBinding 或 effectiveBinding,与调用处 apply() 传入的 effectiveBinding 保持一致。

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.

3 participants