Drop animation targets that fall outside the binding's scope in resolveTargets.#3583
Drop animation targets that fall outside the binding's scope in resolveTargets.#3583ooLittlePanda wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is 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. 🚀 New features to boost your workflow:
|
20f2e91 to
c6176bf
Compare
…scope. PAGTimeline::resolveTargets 和 DataBindRuntime::bind之前通过 findNode 扁平查找 target,未按 binding 作用域过滤,document 级动画/数据绑定可能越界命中嵌套 Composition 内部节点。 修复:resolveTargets/bind 用 contains()提前过滤越界 target。
c6176bf to
2d70790
Compare
| // 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); |
There was a problem hiding this comment.
【真实回归风险,建议移除该断言】此断言假设"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。
| } | ||
| if (!resolved) { | ||
| resolveTargets(); | ||
| resolveTargets(effectiveBinding); |
There was a problem hiding this comment.
【缓存与过滤 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 判定看,并不成立。
| // 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)) { |
There was a problem hiding this comment.
【新增 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 |
There was a problem hiding this comment.
【两处过滤对 binding==nullptr 的语义相反,建议统一】此处 bind() 用 binding != nullptr && !binding->contains(...),即 binding 为空时跳过过滤、退回越界风险;而 PAGTimeline::resolveTargets 中 binding 为空时直接 return(什么都不解析)。两处镜像逻辑对空 binding 的处理正好相反,容易误导后续维护者。虽然当前调用方均传 comp->binding.get() 保证非空,但建议统一空 binding 的防御语义(要么都视为无作用域直接跳过解析/绑定,要么都当作错误)。
| } | ||
|
|
||
| void PAGTimeline::resolveTargets() { | ||
| void PAGTimeline::resolveTargets(const RuntimeBinding* binding) { |
There was a problem hiding this comment.
【变量遮蔽,建议改名】新参数 binding 与成员 PAGTimeline::binding 同名,函数体内 binding 指参数、需 this->binding 才能访问成员,属变量遮蔽(shadowing),可读性差且易埋隐患(例如误以为过滤用的是成员 binding)。建议将参数改名为 scopeBinding 或 effectiveBinding,与调用处 apply() 传入的 effectiveBinding 保持一致。
PAGTimeline::resolveTargets 和 DataBindRuntime::bind之前通过 findNode 扁平查找 target,未按 binding 作用域过滤,document 级动画/数据绑定可能越界命中嵌套 Composition 内部节点。
修复:resolveTargets/bind 用 contains()提前过滤越界 target。