mailing list of musl libc
 help / color / mirror / code / Atom feed
* test-getopt-posix fails on musl
@ 2018-02-24  9:31 Bruno Haible
  2018-02-24 15:09 ` Rich Felker
  0 siblings, 1 reply; 2+ messages in thread
From: Bruno Haible @ 2018-02-24  9:31 UTC (permalink / raw)
  To: musl; +Cc: bug-gnulib

[-- 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;
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: test-getopt-posix fails on musl
  2018-02-24  9:31 test-getopt-posix fails on musl Bruno Haible
@ 2018-02-24 15:09 ` Rich Felker
  0 siblings, 0 replies; 2+ messages in thread
From: Rich Felker @ 2018-02-24 15:09 UTC (permalink / raw)
  To: musl

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

On Sat, Feb 24, 2018 at 10:31:55AM +0100, Bruno Haible wrote:
> 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

It seems like the behavior you're claiming is wrong is that getopt is
treating ':' in the optstring as a valid option rather than just a
modifier to the option character before it or the special flag at the
beginning of optstring. The likely reason the bug exists is that the
spec isn't clear that colons can't be option characters (maybe they
could be, especially if they're not initial or immediately following
another option character?) but it is clear that characters outside
class alnum are not required to be supported as options, and I think
it's clear that accepting -: is not the right thing to do here.

Attached patch should fix it; if nobody objects right away I'll apply.

Thanks!

Rich


[-- Attachment #2: getopt-colon.diff --]
[-- Type: text/plain, Size: 430 bytes --]

diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index e9bab41..e921a60 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -77,7 +77,7 @@ int getopt(int argc, char * const argv[], const char *optstring)
 		if (l>0) i+=l; else i++;
 	} while (l && d != c);
 
-	if (d != c) {
+	if (d != c || c == ':') {
 		optopt = c;
 		if (optstring[0] != ':' && opterr)
 			__getopt_msg(argv[0], ": unrecognized option: ", optchar, k);

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-02-24 15:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-24  9:31 test-getopt-posix fails on musl Bruno Haible
2018-02-24 15:09 ` Rich Felker

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).