[Bug 272218] mbsinit returns true for a state that is not in the initial state

From: <bugzilla-noreply_at_freebsd.org>
Date: Mon, 26 Jun 2023 07:34:43 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=272218

            Bug ID: 272218
           Summary: mbsinit returns true for a state that is not in the
                    initial state
           Product: Base System
           Version: 13.2-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: standards
          Assignee: standards@FreeBSD.org
          Reporter: bruno@clisp.org
 Attachment #243004 text/plain
         mime type:

Created attachment 243004
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=243004&action=edit
test case foo.c

The following program makes 3 calls to the mbrtoc16 function and each time
prints the results, including whether the mbstate_t in then in the initial
state or not.

Then it makes a second round, clearing the mbstate_t after the first call.

================================= foo.c =================================
#include <stdio.h>
#include <string.h>
#include <uchar.h>
#include <wchar.h>
int main ()
{
  if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
    return 1;

  for (int round = 1; round <= 2; round++) {
    printf ("=== Round %d ===\n", round);
    mbstate_t state = { 0 };
    char input[4] = { (char) 0xF0, (char) 0x9F, (char) 0x99, (char) 0x82 }; /*
U+1F642 */
    char16_t wc = (char16_t) 0xDEADBEEF;
    int ret = mbrtoc16 (&wc, input, 4, &state);
    printf ("ret = %d, wc = 0x%04X, back_to_initial=%d\n", ret, (unsigned int)
wc, mbsinit(&state) != 0);
    if (round == 2)
      memset (&state, '\0', sizeof(state));
    if (ret == 4) {
      wc = (char16_t) 0xDEADBEEF;
      ret = mbrtoc16 (&wc, input+4, 0, &state);
      printf ("ret = %d, wc = 0x%04X, back_to_initial=%d\n", ret, (unsigned
int) wc, mbsinit(&state) != 0);
      if (ret == -2 || ret == -3) {
        wc = (char16_t) 0xDEADBEEF;
        ret = mbrtoc16 (&wc, "", 0, &state);
        printf ("ret = %d, wc = 0x%04X, back_to_initial=%d\n", ret, (unsigned
int) wc, mbsinit(&state) != 0);
      }
    }
  }

  return 0;
}
/* Expected output (seen on glibc, musl  libc):

=== Round 1 ===
ret = 4, wc = 0xD83D, back_to_initial=0
ret = -3, wc = 0xDE42, back_to_initial=1
ret = -2, wc = 0xBEEF, back_to_initial=1
=== Round 2 ===
ret = 4, wc = 0xD83D, back_to_initial=0
ret = -2, wc = 0xBEEF, back_to_initial=1
ret = -2, wc = 0xBEEF, back_to_initial=1

*/
=========================================================================

$ cc -Wall foo.c
$ ./a.out
=== Round 1 ===
ret = 4, wc = 0xD83D, back_to_initial=1
ret = -3, wc = 0xDE42, back_to_initial=1
ret = -2, wc = 0xBEEF, back_to_initial=1
=== Round 2 ===
ret = 4, wc = 0xD83D, back_to_initial=1
ret = -2, wc = 0xBEEF, back_to_initial=1
ret = -2, wc = 0xBEEF, back_to_initial=1

Since, after the first call, mbsinit() reports that the mbstate_t is in the
initial state, it should make no difference if the program clears it (= forces
it into the initial state) or not. But in FreeBSD 13.2, it makes a difference:
The output of round 2 is different from the output of round 1. This proves that
the mbstate_t was not in the initial state. That is, in the first line,
mbsinit() should have returned zero instead of non-zero.

Reference:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/mbsinit.html

-- 
You are receiving this mail because:
You are the assignee for the bug.