mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: musl@lists.openwall.com
Cc: bug-gnulib@gnu.org
Subject: test-getopt-posix fails on musl
Date: Sat, 24 Feb 2018 10:31:55 +0100	[thread overview]
Message-ID: <1714550.SfedhZ9LKS@omega> (raw)

[-- Attachment #1: Type: text/plain, Size: 416 bytes --]

Hi,

On Alpine Linux 3.7.0, which uses musl libc, the gnulib test 'test-getopt-posix'
fails. To me, this looks like a POSIX compliance bug of musl.
Find attached a reduced test case.

$ gcc foo.c -Wall
$ ./a.ou	t
foo.c:134: assertion 'options[0] == ':' || ((options[0] == '-' || options[0] == '+') && options[1] == ':')' failed

Reference: POSIX
http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html

[-- Attachment #2: foo.c --]
[-- Type: text/x-csrc, Size: 5278 bytes --]

/* POSIX and glibc provide the getopt() function in <unistd.h>, see
   http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
   https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html
   But gnulib provides the getopt() function in <getopt.h>, not in <unistd.h>.
   Nevertheless the getopt() function should also be found in <unistd.h>.  */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define TEST_GETOPT_TMP_NAME "test-getopt-posix.tmp"

/* This test intentionally remaps stderr.  So, we arrange to have fd 10
   (outside the range of interesting fd's during the test) set up to
   duplicate the original stderr.  */

#define BACKUP_STDERR_FILENO 10
#define ASSERT_STREAM myerr

#ifndef FALLTHROUGH
# if __GNUC__ < 7
#  define FALLTHROUGH ((void) 0)
# else
#  define FALLTHROUGH __attribute__ ((__fallthrough__))
# endif
#endif

/* Define ASSERT_STREAM before including this file if ASSERT must
   target a stream other than stderr.  */
#ifndef ASSERT_STREAM
# define ASSERT_STREAM stderr
#endif

/* ASSERT (condition);
   verifies that the specified condition is fulfilled.  If not, a message
   is printed to ASSERT_STREAM if defined (defaulting to stderr if
   undefined) and the program is terminated with an error code.

   This macro has the following properties:
     - The programmer specifies the expected condition, not the failure
       condition.  This simplifies thinking.
     - The condition is tested always, regardless of compilation flags.
       (Unlike the macro from <assert.h>.)
     - On Unix platforms, the tester can debug the test program with a
       debugger (provided core dumps are enabled: "ulimit -c unlimited").
     - For the sake of platforms where no debugger is available (such as
       some mingw systems), an error message is printed on the error
       stream that includes the source location of the ASSERT invocation.
 */
#define ASSERT(expr) \
  do                                                                         \
    {                                                                        \
      if (!(expr))                                                           \
        {                                                                    \
          fprintf (ASSERT_STREAM, "%s:%d: assertion '%s' failed\n",     \
                   __FILE__, __LINE__, #expr);                          \
          fflush (ASSERT_STREAM);                                            \
          abort ();                                                          \
        }                                                                    \
    }                                                                        \
  while (0)

static FILE *myerr;

int
main (void)
{
   /* This test validates that stderr is used correctly, so move the
      original into fd 10.  */
  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
    return 2;

  ASSERT (freopen (TEST_GETOPT_TMP_NAME, "w", stderr) == stderr);

  /* These default values are required by POSIX.  */
  ASSERT (optind == 1);
  ASSERT (opterr != 0);

  setenv ("POSIXLY_CORRECT", "1", 1);
  int start = 1;

    {
      int a_seen = 0;
      int b_seen = 0;
      const char *p_value = NULL;
      const char *q_value = NULL;
      int non_options_count = 0;
      int unrecognized = 0;
      bool output;
      int argc = 0;
      const char *argv[10];

      argv[argc++] = "program";
      argv[argc++] = "-p";
      argv[argc++] = "foo";
      argv[argc++] = "-:";
      argv[argc++] = "-a";
      argv[argc++] = "bar";
      argv[argc] = NULL;
      optind = start;
      opterr = 42;
      {
        const char *options = "abp:q:";
        int c;
        int pos = ftell (stderr);

        while ((c = getopt (argc, (char **) argv, options)) != -1)
         {
          switch (c)
          {
          case 'a':
            a_seen++;
            break;
          case 'b':
            b_seen++;
            break;
          case 'p':
            p_value = optarg;
            break;
          case 'q':
            q_value = optarg;
            break;
          case '\1':
            /* Must only happen with option '-' at the beginning.  */
            ASSERT (options[0] == '-');
            non_options_count++;
            break;
          case ':':
            /* Must only happen with option ':' at the beginning.  */
            ASSERT (options[0] == ':'
                    || ((options[0] == '-' || options[0] == '+')
                        && options[1] == ':'));
            FALLTHROUGH;
          case '?':
            unrecognized = optopt;
            break;
          default:
            unrecognized = c;
            break;
          }
         }

        output = pos < ftell (stderr);
      }
      ASSERT (a_seen == 1);
      ASSERT (b_seen == 0);
      ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
      ASSERT (q_value == NULL);
      ASSERT (non_options_count == 0);
      ASSERT (unrecognized == ':');
      ASSERT (optind == 5);
      ASSERT (output);
    }

  ASSERT (fclose (stderr) == 0);
  ASSERT (remove (TEST_GETOPT_TMP_NAME) == 0);

  return 0;
}

             reply	other threads:[~2018-02-24  9:31 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-24  9:31 Bruno Haible [this message]
2018-02-24 15:09 ` Rich Felker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1714550.SfedhZ9LKS@omega \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).