[BRLTTY] Crash when sending char é

Samuel Thibault samuel.thibault at ens-lyon.org
Thu Sep 28 20:34:45 EDT 2017


Samuel Thibault, on jeu. 28 sept. 2017 15:00:08 +0200, wrote:
> Quartel, Eric de, on jeu. 28 sept. 2017 11:37:03 +0000, wrote:
> > Unfortunate when the é (e with acute accent) is send - brlapi_writeText(0,"my
> > string with é in it") - my program crashes.
> 
> Did you initialize locales (using setlocale) according to the encoding
> you use for é?
> 
> Normally it shouldn't crash, but perhaps that's the underlying issue.

I still don't see why it could crash, so following Sébastien's advice
would help in that regard.

That being said, we can make libbrlapi actually automatically get the
user's default charset without disturbing the application's locale
management, thanks to newlocale, the attached patch does this.

Samuel
-------------- next part --------------
diff --git a/Programs/brlapi.h.in b/Programs/brlapi.h.in
index c6d2c4d4c..9e85219c4 100644
--- a/Programs/brlapi.h.in
+++ b/Programs/brlapi.h.in
@@ -452,8 +452,8 @@ int BRLAPI_STDCALL brlapi__setFocus(brlapi_handle_t *handle, int tty);
  *
  * If the string is too long, it is truncated. If it's too short,
  * it is padded with spaces. The text is assumed to be in the current
- * locale charset, or latin1 if locales have not been initialized.
- * To initialize locales, use setlocale(3).
+ * locale charset set by setlocale(3) if it was called, or the locale charset
+ * from the locale environment variables if setlocale(3) was not called.
  *
  * \param cursor gives the cursor position; if equal to ::BRLAPI_CURSOR_OFF, no cursor is shown at
  * all; if cursor==::BRLAPI_CURSOR_LEAVE, the cursor is left where it is
diff --git a/Programs/brlapi_client.c b/Programs/brlapi_client.c
index bb209d5b7..914748c33 100644
--- a/Programs/brlapi_client.c
+++ b/Programs/brlapi_client.c
@@ -224,6 +224,9 @@ struct brlapi_handle_t { /* Connection-specific information */
   sem_t *altSem;
   int state;
   pthread_mutex_t state_mutex;
+#ifdef HAVE_NEWLOCALE
+  locale_t default_locale;
+#endif /* HAVE_NEWLOCALE */
   /* key presses buffer, for when key presses are received instead of
    * acknowledgements for instance
    *
@@ -266,6 +269,9 @@ static void brlapi_initializeHandle(brlapi_handle_t *handle)
   handle->altSem = NULL;
   handle->state = 0;
   pthread_mutex_init(&handle->state_mutex, NULL);
+#ifdef HAVE_NEWLOCALE
+  handle->default_locale = LC_GLOBAL_LOCALE;
+#endif /* HAVE_NEWLOCALE */
   memset(handle->keybuf, 0, sizeof(handle->keybuf));
   handle->keybuf_next = 0;
   handle->keybuf_nb = 0;
@@ -780,6 +786,10 @@ void BRLAPI_STDCALL brlapi__closeConnection(brlapi_handle_t *handle)
   closeFileDescriptor(handle->fileDescriptor);
   handle->fileDescriptor = INVALID_FILE_DESCRIPTOR;
   pthread_mutex_unlock(&handle->fileDescriptor_mutex);
+#ifdef HAVE_NEWLOCALE
+  if (handle->default_locale != LC_GLOBAL_LOCALE)
+    freelocale(handle->default_locale);
+#endif /* HAVE_NEWLOCALE */
 #ifdef __MINGW32__
   WSACleanup();
 #endif /* __MINGW32__ */
@@ -1102,6 +1112,17 @@ int BRLAPI_STDCALL brlapi__enterTtyModeWithPath(brlapi_handle_t *handle, int *tt
   if ((res=brlapi__writePacketWaitForAck(handle,BRLAPI_PACKET_ENTERTTYMODE,&packet,(p-(unsigned char *)&packet))) == 0)
     handle->state |= STCONTROLLINGTTY;
   pthread_mutex_unlock(&handle->state_mutex);
+
+  /* Determine default charset if application did not call setlocale.  */
+#ifdef HAVE_NEWLOCALE
+  const char *locale = setlocale(LC_CTYPE, NULL);
+  if (!locale || !strcmp(locale, "C")) {
+    /* Application did not call setlocale, try to load the current locale.  */
+    locale_t default_locale = newlocale(LC_CTYPE_MASK, "", 0);
+    if (default_locale) handle->default_locale = default_locale;
+  }
+#endif /* HAVE_NEWLOCALE */
+
   return res;
 }
 
@@ -1152,7 +1173,7 @@ int BRLAPI_STDCALL brlapi_setFocus(int tty)
   return brlapi__setFocus(&defaultHandle, tty);
 }
 
-static size_t getCharset(void *buffer, int wide) {
+static size_t getCharset(brlapi_handle_t *handle, void *buffer, int wide) {
   char *p = buffer;
   const char *start = p;
   const char *locale = setlocale(LC_CTYPE, NULL);
@@ -1165,7 +1186,11 @@ static size_t getCharset(void *buffer, int wide) {
     size_t length = strlen(WCHAR_CHARSET);
     *p++ = length;
     p = mempcpy(p, WCHAR_CHARSET, length);
-  } else if (locale && strcmp(locale, "C")) {
+  } else if ((locale && strcmp(locale, "C"))
+#ifdef HAVE_NEWLOCALE
+             || handle->default_locale != LC_GLOBAL_LOCALE
+#endif /* HAVE_NEWLOCALE */
+            ) {
     /* not default locale, tell charset to server */
 #ifdef WINDOWS
     UINT CP = GetACP();
@@ -1200,7 +1225,15 @@ static int brlapi___writeText(brlapi_handle_t *handle, int cursor, const void *s
   char *locale;
   int res;
   size_t len;
+#ifdef HAVE_NEWLOCALE
+  locale_t old_locale = 0;
+  if (handle->default_locale != LC_GLOBAL_LOCALE)
+    /* Temporarily load the default locale.  */
+    old_locale = uselocale(handle->default_locale);
+  locale = "default locale";
+#else /* HAVE_NEWLOCALE */
   locale = setlocale(LC_CTYPE,NULL);
+#endif /* HAVE_NEWLOCALE */
   wa->flags = BRLAPI_WF_REGION;
   *((uint32_t *) p) = htonl(1); p += sizeof(uint32_t);
   *((uint32_t *) p) = htonl(dispSize); p += sizeof(uint32_t);
@@ -1235,6 +1268,11 @@ static int brlapi___writeText(brlapi_handle_t *handle, int cursor, const void *s
 	    brlapi_libcerrno = errno;
 	    brlapi_errfun = "mbrlen";
 	    brlapi_errno = BRLAPI_ERROR_LIBCERR;
+#ifdef HAVE_NEWLOCALE
+	    if (handle->default_locale != LC_GLOBAL_LOCALE)
+	      /* Restore application locale */
+	      uselocale(old_locale);
+#endif /* HAVE_NEWLOCALE */
 	    return -1;
 	  case 0:
 	    goto endcount;
@@ -1269,7 +1307,7 @@ endcount:
     p += sizeof(uint32_t);
   }
 
-  if ((len = getCharset(p , wide))) {
+  if ((len = getCharset(handle, p , wide))) {
     wa->flags |= BRLAPI_WF_CHARSET;
     p += len;
   }
@@ -1278,6 +1316,11 @@ endcount:
   pthread_mutex_lock(&handle->fileDescriptor_mutex);
   res = brlapi_writePacket(handle->fileDescriptor,BRLAPI_PACKET_WRITE,&packet,sizeof(wa->flags)+(p-&wa->data));
   pthread_mutex_unlock(&handle->fileDescriptor_mutex);
+#ifdef HAVE_NEWLOCALE
+  if (handle->default_locale != LC_GLOBAL_LOCALE)
+    /* Restore application locale */
+    uselocale(old_locale);
+#endif /* HAVE_NEWLOCALE */
   return res;
 }
 
@@ -1433,10 +1476,21 @@ int brlapi__write(brlapi_handle_t *handle, const brlapi_writeArguments_t *s)
   }
   if (s->charset) {
     if (!*s->charset) {
-      if ((strLen = getCharset(p, wide))) {
+#ifdef HAVE_NEWLOCALE
+      locale_t old_locale = 0;
+      if (handle->default_locale != LC_GLOBAL_LOCALE)
+	/* Temporarily load the default locale.  */
+	old_locale = uselocale(handle->default_locale);
+#endif /* HAVE_NEWLOCALE */
+      if ((strLen = getCharset(handle, p, wide))) {
 	wa->flags |= BRLAPI_WF_CHARSET;
 	p += strLen;
       }
+#ifdef HAVE_NEWLOCALE
+      if (handle->default_locale != LC_GLOBAL_LOCALE)
+	/* Restore application locale */
+	uselocale(old_locale);
+#endif /* HAVE_NEWLOCALE */
     } else {
       strLen = strlen(s->charset);
       *p++ = strLen;
diff --git a/config.h.in b/config.h.in
index 67dab5375..a3cf4d12c 100644
--- a/config.h.in
+++ b/config.h.in
@@ -62,6 +62,9 @@ extern "C" {
 /* Define this if the header file langinfo.h exists. */
 #undef HAVE_LANGINFO_H
 
+/* Define this if the function newlocale exists. */
+#undef HAVE_NEWLOCALE
+
 /* Define this if the header file grp.h exists. */
 #undef HAVE_GRP_H
 
diff --git a/configure.ac b/configure.ac
index c3d0bb2e2..61d6c3bfb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -805,6 +805,7 @@ AC_CHECK_HEADERS([signal.h sys/signalfd.h])
 AC_CHECK_FUNCS([sigaction])
 
 AC_CHECK_HEADERS([alloca.h getopt.h glob.h langinfo.h regex.h])
+AC_CHECK_FUNCS([newlocale])
 AC_CHECK_HEADERS([syslog.h execinfo.h])
 AC_CHECK_HEADERS([sys/file.h sys/socket.h])
 AC_CHECK_HEADERS([pwd.h grp.h])


More information about the BRLTTY mailing list