> Date: Thu, 19 Feb 2026 21:10:35 +0200
> From: Eli Zaretskii <[email protected]>
> Cc: [email protected], [email protected]
> 
> > Date: Thu, 19 Feb 2026 17:40:11 +0100
> > From: [email protected]
> > Cc: [email protected], [email protected]
> > 
> > >    ./..//C/ctexi2any  --force --conf-dir ./../perl/t/init/ --conf-dir 
> > > ./../perl/init --conf-dir ./../perl/ext -I ./formatting -I formatting/ -I 
> > > ./ -I . -I built_input -I built_input/non_ascii --error-limit=1000 -c 
> > > TEST=1  --output formatting/out_parser/split_nocopying_split_dev_null/ 
> > > --info --split-size 1 -o /dev/null ./formatting/split_nocopying.texi > 
> > > formatting/out_parser/split_nocopying_split_dev_null/split_nocopying.1 
> > > 2>formatting/out_parser/split_nocopying_split_dev_null/split_nocopying.2
> > >   failed with status 5
> > > 
> > > "Status 5" means it crashed with the Windows equivalent of SIGSEGV.
> > > 
> > > It also crashes if I invoke the above command manually.  I thought I'd
> > > try to debug this, but ctexi2any is stripped of debug symbols.  Could
> > > you tell me how to prevent symbols from being stripped? which Makefile
> > > to change and where?
> > 
> > We do not do anything special regarding stripping debug symbols, as far
> > as I can tell.  When I want debugging symbols in the build, I set CFLAGS
> > and PERL_EXT_CFLAGS through configure at top level like that:
> > 
> > our_CFLAGS='-g'
> > ./configure ......  "CFLAGS=$our_CFLAGS" "PERL_EXT_CFLAGS=$our_CFLAGS"
> 
> OK, I will see what I can do with this.

Long story short: this doesn't work.

First, the -s comes from perl_conf_CFLAGS and perl_conf_LDFLAGS, so
it's what Perl suggests as the compilation and link switches (their
actual values are much longer, and -s is just one of the options
mentioned there).  Setting PERL_EXT_CFLAGS and PERL_EXT_LDFLAGS
doesn't override the -s in the switches, it just adds to them, so -s
is still there, and debug symbols are still being stripped.

I ended up hacking tta/C/Makefile by hand to replace -s with
debug-friendly options.  (It would be nice to have a cleaner way of
solving this, though, since these perl_conf_* variables are in every
Makefile under the tta/ directory, and modifying them all by hand is
no fun.)

Then it took me some time to understand why it crashes.  The crash is
here:

  Thread 1 received signal SIGSEGV, Segmentation fault.
  0x7660ef08 in strtok () from C:\WINDOWS\SysWOW64\msvcrt.dll
  (gdb) bt
  #0  0x7660ef08 in strtok () from C:\WINDOWS\SysWOW64\msvcrt.dll
  #1  0x00d51abd in push_include_directory (include_dirs_list=0x5ffb6c, 
text=0x0)
      at texi2any.c:404
  #2  0x00d537fd in main (argc=31, argv=0x1043208, env=0x1041808)
      at texi2any.c:1517
  (gdb) up
  #1  0x00d51abd in push_include_directory (include_dirs_list=0x5ffb6c, 
text=0x0)
      at texi2any.c:404
  404       char *dir = strtok (text, PATH_SEP);

strtok segfaults because its 1st argument, which comes from the 'text'
argument of push_include_directory, is a NULL pointer:

  static void
  push_include_directory (STRING_LIST *include_dirs_list, char *text)
  {
    char *dir = strtok (text, PATH_SEP);

Here is where things become interesting.  'text' is the value of
'optarg' which is supposed to be set by getopt_long:

        case CONF_DIR_OPT:
          push_include_directory (&conf_dirs, optarg);
          break;

And optarg is NULL:

  (gdb) p optarg
  $7 = 0x0

I don't fully understand why optarg is NULL.  The actual name of the
variable is rpl_optarg, because config.h does:

  /* Define to rpl_ if the getopt replacement functions and variables should be
     used. */
  #define __GETOPT_PREFIX rpl_

But for some reason, rpl_optarg in texi2any.c and in getopt.c resolve
to two different addresses.  Here's what I see while stepping through
the code:

  1320          option_character = getopt_long (argc, argv, 
"VhvFc:D:e:f:I:P:o:E:U:",
  (gdb) s
  rpl_getopt_long (argc=31, argv=0x1043208,
      options=0xd5e8b6 <format_names+1206> "VhvFc:D:e:f:I:P:o:E:U:",
      long_options=0xd5d200 <long_options>, opt_index=0x5ffc38) at getopt1.c:31
  31        return _getopt_internal (argc, (char **) argv, options, 
long_options,
  (gdb) s
  rpl_getopt_internal (argc=31, argv=0x1043208,
      optstring=0xd5e8b6 <format_names+1206> "VhvFc:D:e:f:I:P:o:E:U:",
      longopts=0xd5d200 <long_options>, longind=0x5ffc38, long_only=0,
      posixly_correct=0) at getopt.c:710
  710       getopt_data.optind = optind;
  (gdb) n
  711       getopt_data.opterr = opterr;
  (gdb) n
  713       int result = _getopt_internal_r (argc, argv, optstring, longopts,
  (gdb) n
  717       optind = getopt_data.optind;
  (gdb) n
  718       optarg = getopt_data.optarg;
  (gdb) n
  719       optopt = getopt_data.optopt;
  (gdb) p optarg
  $4 = 0x10429d8 "./../perl/t/init/"
  (gdb) p rpl_optarg
  $5 = 0x10429d8 "./../perl/t/init/"
  (gdb) info address rpl_optarg
  Symbol "rpl_optarg" is static storage at address 0x77676af8.
  (gdb) n
  721       return result;
  (gdb) n
  722     }
  (gdb) n
  rpl_getopt_long (argc=31, argv=0x1043208,
      options=0xd5e8b6 <format_names+1206> "VhvFc:D:e:f:I:P:o:E:U:",
      long_options=0xd5d200 <long_options>, opt_index=0x5ffc38) at getopt1.c:33
  33      }
  (gdb) p rpl_optarg
  $6 = 0x10429d8 "./../perl/t/init/"
  (gdb) n
  main (argc=31, argv=0x1043208, env=0x1041808) at texi2any.c:1324
  1324          if (option_character == -1)
  (gdb) p rpl_optarg
  $7 = 0x0
  (gdb) info address rpl_optarg
  Symbol "rpl_optarg" is static storage at address 0xd63114.

Note how optarg was computed correctly inside getopt.c, but "lost" its
value when control flow returned to the main function.  Also note that
GDB shows two different addresses for rpl_optarg in these two modules.
I presume this latter fact is the reason why I get NULL in main, but I
don't understand what snafu caused that.  Perhaps Bruno (CC'ed) could
suggest where to look.  It sounds like some linkage problem -- the
linker resolved rpl_optarg to an incorrect address for some reason.
But why?  It might be relevant that MinGW does have its own getopt.h
header, and that header does declare 'optarg'.  But then this Gnulib
trick with renaming was explicitly meant to avoid messing with the
system's getopt, so I'd expect that to work in my case.

And one other issue I found while looking for the root cause of the
crashes: the value of PATH_EXT is incorrect.  It should be ";" on
Windows, but is ":" instead.  The reason is that it is taken from the
PATH_SEPARATOR value, which is suitable for the Posix shell used to
build Texinfo, but not for running it after that natively on a Windows
system.  The value ":" will not work for parsing PATH-style lists of
directories (when the code will begin working).

Let me know if you need further details.

  • texi... Gavin Smith
    • ... Eli Zaretskii
      • ... Eli Zaretskii
        • ... pertusus
          • ... Eli Zaretskii
            • ... Eli Zaretskii
              • ... Bruno Haible via Bug reports for the GNU Texinfo documentation system
                • ... Eli Zaretskii
                • ... Eli Zaretskii
                • ... Gavin Smith
                • ... pertusus
                • ... Bruno Haible via Bug reports for the GNU Texinfo documentation system
                • ... pertusus
                • ... Bruno Haible via Bug reports for the GNU Texinfo documentation system
                • ... pertusus
              • ... pertusus

Reply via email to