Skip to content

fix: spd_set_notification must not always send NOTIFICATION ALL - #1116

Merged
sthibaul merged 1 commit into
brailcom:masterfrom
dylanpulver:fix-notification-mask
Sep 1, 2026
Merged

fix: spd_set_notification must not always send NOTIFICATION ALL#1116
sthibaul merged 1 commit into
brailcom:masterfrom
dylanpulver:fix-notification-mask

Conversation

@dylanpulver

Copy link
Copy Markdown
Contributor

NOTIFICATION_SET at src/api/c/libspeechd.c:1429-1434 tests one bit (notification & val), but the last of the seven uses at :1463 passes SPD_ALL, which include/speechd_types.h:83 defines as 0x3f — the union of the six event bits, not a bit of its own. So SET SELF NOTIFICATION ALL is emitted for any non-zero argument, and it is emitted last, and set_notification_self (src/server/set.c:502-508) applies all to all six events. The notification parameter has been a no-op since d6613243 (2010-09-27) added that line; SPD_ALL was already 0x3f at that commit.

Measured by compiling the unmodified src/api/c/libspeechd.c and driving the real spd_set_notification_on/off over a unix socket against a stub SSIP server that models set_notification_self. Same harness, same commands, before and after:

call server mask before after
spd_set_notification_on(conn, SPD_BEGIN) 0x3f all six 0x01 begin
spd_set_notification_on(conn, SPD_END) (what spd-say asks for) 0x3f 0x02 end
spd_set_notification_on(conn, SPD_END|SPD_CANCEL) (the manual's example) 0x3f 0x0a end, cancel
control: spd_set_notification_on(conn, SPD_ALL) 0x3f 0x3f unchanged
from all-on, spd_set_notification_off(conn, SPD_BEGIN) 0x00 all six off 0x3e begin off

The last row is the one that bites: a client that turns off a single event loses END and CANCEL too, and the pattern the manual documents at doc/speech-dispatcher.texi:2380-2400spd_set_notification_on(conn, SPD_END); spd_set_notification_on(conn, SPD_CANCEL); then sem_wait for one of them — has nothing left to wake it.

Authority: doc/speech-dispatcher.texi documents SPDNotification as six members with no SPD_ALL, says these functions "set the notification specified by the parameter notification", and notes | combinations are allowed. doc/ssip.texi:1377 documents SET SELF NOTIFICATION ALL as setting all event notifications, so emitting it is never a no-op. The Python binding does the same job correctly — src/api/python/speechd/client.py:613-619 sends the six names individually and never sends all.

Why nothing caught it: src/tests/spd_set_notifications_all.c:77 is the only test of this API and it passes SPD_ALL, the single input for which line 1463 is harmless. src/tests/clibrary2.c:95-96 uses SPD_END/SPD_CANCEL but never asserts that the other events stayed off, and nothing calls spd_set_notification_off.

The fix tests every bit of val rather than any. For the six single-bit values (n & val) == val and n & val are equivalent, so SPD_ALL is the only line whose behaviour changes — the control row above shows the SPD_ALL wire traffic is byte-for-byte what it is today.

Mutants against the same harness: reverting the macro reproduces every row above; the naive notification == val fixes the single-bit cases but makes SPD_END|SPD_CANCEL emit nothing at all (0x00); simply deleting the NOTIFICATION_SET(SPD_ALL, "all") line gives identical results in every row, and I did not choose it only because it stops sending ALL at all, whereas this keeps today's exact wire behaviour for SPD_ALL. Happy to switch if you prefer the deletion.

Not tested, stated rather than glossed: I could not build the project here. This is macOS; ./build.sh succeeds but ./configure fails on dotconf >= 1.3, which Homebrew does not carry, so make check and the autotest suite were never run and I have not exercised this against a live speech-dispatcher or Orca. Everything above is the real libspeechd.c compiled standalone against glib, with the server side modelled from set.c rather than executed. No new test is included because the existing test for this API needs a running server; glad to add one to src/tests/ if you want it, but I would not be able to verify it locally.

This change was prepared with AI assistance (Claude Opus 5).

NOTIFICATION_SET tests a single bit, but SPD_ALL is 0x3f, the union of
the six event bits (include/speechd_types.h:76-83). So
"SET SELF NOTIFICATION ALL" was emitted for any non-zero argument, and
last, and set_notification_self() (src/server/set.c:502-508) applies
"all" to all six events.

spd_set_notification_on(conn, SPD_END) therefore enabled every event,
and spd_set_notification_off(conn, SPD_BEGIN) disabled every event,
including the END and CANCEL a client may be waiting on.

Test every bit of val instead of any. For the six single-bit values the
two tests are equivalent, so only the SPD_ALL line changes behaviour.
@sthibaul
sthibaul merged commit 65b0fe9 into brailcom:master Sep 1, 2026
7 checks passed
@sthibaul

sthibaul commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks!

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