Package: speechd-up
Version: 0.5~20110719-9

SYMPTOMS

I ran into a failed assertion.  When pressing certain Unicode
characters like U+20AC (EURO SIGN) or U+2192 (RIGHTWARDS ARROW) on the
console via a keyboard, speechd-up exits suddenly.  The same happens
when moving the cursor over a Unicode character in a text editor or on
a readline prompt.  I first ran into this under Buster.

DIAGNOSIS

>From strace:

...
write(2, "speechd-up: speechd-up.c:457: parse_buf: Assertion `bytes <= 
BUF_SIZE' failed.\n", 79) = 79
...

WORKAROUND

The problem only manifests when speechd-up is started with the default
command line "speechd-up -l1".  Putting this into
/etc/default/speechd-up prevents the bug from being triggered:
DAEMON_OPTS="$DAEMON_OPTS -D/dev/softsynthu -cUTF-8"

ANALYSIS

The error is in speechd-up.c:main():

750 ...
751             chars_read = read(fd, buf, BUF_SIZE);
752             if (chars_read < 0) {
753 ...

chars_read is declared as size_t, but read() returns ssize_t, thus a
failed read returning -1 (errno==11/EAGAIN in my case) triggers the
assertion in parse_buf().

The patch fixes the error and also adds code to retry the read after a
short delay.
--- speechd-up-0.5~20110719/speechd-up.c	2020-09-02 21:05:47.357273940 +0200
+++ speechd-up-0.5~20110719/speechd-up.c	2020-09-02 21:07:45.929271575 +0200
@@ -631,6 +631,7 @@
 int main(int argc, char *argv[])
 {
 	size_t chars_read;
+	ssize_t chars_read_signed;
 	char buf[BUF_SIZE + 1];
 	int ret;

@@ -748,11 +749,20 @@
 			close(fd);
 			return -1;
 		}
-		chars_read = read(fd, buf, BUF_SIZE);
-		if (chars_read < 0) {
-			FATAL(5, "read() failed");
-			close(fd);
-			return -1;
+		chars_read_signed = read(fd, buf, BUF_SIZE);
+		if (chars_read_signed < 0) {
+			if (errno == EAGAIN) {
+				LOG(5, "read() failed with EAGAIN, retrying");
+				usleep(1000);
+				continue;
+			} else {
+				FATAL(5, "read() failed with %d,%s",
+				      errno, strerror(errno));
+				close(fd);
+				return -1;
+			}
+		} else {
+			chars_read = chars_read_signed;
 		}
 		buf[chars_read] = 0;
 		LOG(5, "Main loop characters read = %d : (%s)", chars_read,

Reply via email to