Skip to content

Commit a4d659e

Browse files
Merge pull request #112 from preactjs/unmark-guard
Fix internal API able to unmark non-marked signals
2 parents cd562d1 + 32abe07 commit a4d659e

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

.changeset/neat-dingos-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@preact/signals-core": patch
3+
---
4+
5+
Fix internal API functions being able to unmark non-invalidated signals

packages/core/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,11 @@ function unmark(signal: Signal<any>) {
162162
// wasn't flagged as needing an update by someone else. This is
163163
// done to make the sweeping logic independent of the order
164164
// in which a dependency tries to unmark a subtree.
165-
if (!signal._requiresUpdate && --signal._pending === 0) {
165+
if (
166+
!signal._requiresUpdate &&
167+
signal._pending > 0 &&
168+
--signal._pending === 0
169+
) {
166170
signal._subs.forEach(unmark);
167171
}
168172
}

packages/core/test/signal.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,21 @@ describe("computed()", () => {
470470
a.value = "aa";
471471
expect(spy).to.returned("aa c d");
472472
});
473+
474+
it("should prevent invalid unmark state when called on a source signal", () => {
475+
// Don't allow our internal logic to get in an invalid state, even through
476+
// our own internal API. The bug this tests for is that a source signal
477+
// will be unmarked, leading to all its subscribers `_pending` value to become
478+
// negative. This is invalid and breaks further updates.
479+
const a = signal("a");
480+
const b = computed(() => a.value);
481+
effect(() => b.value);
482+
483+
a._setCurrent()(true, true);
484+
485+
a.value = "aa";
486+
expect(b.value).to.equal("aa");
487+
});
473488
});
474489

475490
describe("error handling", () => {

0 commit comments

Comments
 (0)