Skip to content

ExtUtils::ParseXS: set fake filename for xs_handshake() - #24651

Merged
mauke merged 3 commits into
Perl:bleadfrom
mauke:fix-24646-eu-pxs-hack-file
Aug 4, 2026
Merged

ExtUtils::ParseXS: set fake filename for xs_handshake()#24651
mauke merged 3 commits into
Perl:bleadfrom
mauke:fix-24646-eu-pxs-hack-file

Conversation

@mauke

@mauke mauke commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

If a dynamically loaded library fails the XS handshake (because it was compiled for a binary incompatible perl), it reports the error from its own C file with no context except for __FILE__:

XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xed00080, needed 0xee00080)

This patch sets a synthetic (but more user friendly) __FILE__ value (including the module name) around the version check macros in the generated boot section. The error message is now:

XS.c in List::MoreUtils::XS: loadable library and perl binaries are mismatched (got first handshake key 0xed00080, needed 0xee00080)

Fixes #24646, #15861, #16654.


  • This set of changes does not require a perldelta entry. I think. A Changes entry for ExtUtils::ParseXS is included.

@mauke
mauke requested review from Leont and iabyn August 2, 2026 12:01
@jkeenan

jkeenan commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

If I take the block of new tests you've added to t/003-parse-file-scope-keywords.t and insert it into that same file in blead -- without any other changes to the source code -- and then run:

$ cd t;./perl harness -v ../dist/ExtUtils-ParseXS/t/003-parse-file-scope-keywords.t; cd -

... I get this output:

#   Failed test 'file name in XS handshake: includes correct module name'
#   at t/lib/TestMany.pm line 157.
#                   'XS_EXTERNAL(boot_Foo__Bar); /* prototype to pass -Wmissing-prototypes */
# XS_EXTERNAL(boot_Foo__Bar)
# {
# #if PERL_VERSION_LE(5, 21, 5)
#     dVAR; dXSARGS;
# #else
#     dVAR; dXSBOOTARGSXSAPIVERCHK;
# #endif
# 
#     PERL_UNUSED_VAR(cv); /* -W */
#     PERL_UNUSED_VAR(items); /* -W */
# #if PERL_VERSION_LE(5, 21, 5)
#     XS_VERSION_BOOTCHECK;
# #  ifdef XS_APIVERSION_BOOTCHECK
#     XS_APIVERSION_BOOTCHECK;
# #  endif
# #endif
# 
# #if PERL_VERSION_LE(5, 21, 5)
# #  if PERL_VERSION_GE(5, 9, 0)
#     if (PL_unitcheckav)
#         call_list(PL_scopestack_ix, PL_unitcheckav);
# #  endif
#     XSRETURN_YES;
# #else
#     Perl_xs_boot_epilog(aTHX_ ax);
# #endif
# }'
#     doesn't match '(?^m:^\s*#line \d+ \"\(output\)\ in\ Foo\:\:Bar\")'
ok 17 - overload: two packages: no errors expected
not ok 18 - file name in XS handshake: includes correct module name
ok 19 - file name in XS handshake: no errors expected
ok 20 - 1st MODULE PKG: got expected err msg

What's interesting here is that the second of the unit tests you've added in the branch ...

195 
196     test_many($preamble, 'boot_Foo', \@test_fns);
197 }

... already PASSes in blead.

ok 19 - file name in XS handshake: no errors expected

Is that what you would have expected?

@jkeenan

jkeenan commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Is there any way I could set up a situation on my disk that would generate this handshake error message so that I can see the before/after impact?

@mauke

mauke commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@jkeenan Short answer: Yes.

I only added one new test, really. The call to test_many() does two things: It verifies that the generated code matches the given pattern and that no errors were encountered. Without the other code changes, a boot function is still generated successfully, as before. Just the pattern won't match the generated code (because the expected module name is not there).

@mauke

mauke commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

As for reproducing the error, it involves loading an XS module built for one perl into another (binary incompatible) perl. There's probably a smarter way to set this up, but here's one way:

  1. Start with a clean source tree.
  2. Configure a threaded perl for installation somewhere:
     ./Configure -Dman{1,3}dir=none -Dusedevel -Dusethreads -Dprefix="/tmp/perlx-$(git describe @)-threads" -des
  3. Build and install:
    make -j4 install
  4. Install an XS module:
    /tmp/perlx-v5.45.1-101-g20642de849-threads/bin/cpan5.45.2 List::MoreUtils::XS
  5. Get a clean source tree again:
    make distclean
  6. Configure a binary incompatible perl (without threads):
    ./Configure -Dman{1,3}dir=none -Dusedevel -des
  7. Build:
    make -j4
  8. Try to load the XS module in an incompatible perl:
    ./perl -I "$PWD/lib" -I /tmp/perlx-v5.45.1-101-g20642de849-threads/lib/site_perl/5.45.2/* -e 'use List::MoreUtils::XS'

@jkeenan

jkeenan commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

I had two problems with these instructions:

First,

As for reproducing the error, it involves loading an XS module built for one perl into another (binary incompatible) perl. There's probably a smarter way to set this up, but here's one way:

[snip]

   ```

8. Try to load the XS module in an incompatible perl:
   ```
   ./perl -I "$PWD/lib" -I /tmp/perlx-v5.45.1-101-g20642de849-threads/lib/site_perl/5.45.2/* -e 'use List::MoreUtils::XS'
   ```

I think the path supplied to the second -I switch is incorrect. If for your /tmp/perlx-v5.45.1-101-g20642de849-threads I use my $TESTINGDIR/threaded_blead (solely for the purpose of reusing customized shell scripts I've used many times), then I had to use this command to attempt to build the threaded List::MoreUtils::XS against the unthreaded build.

$ ./perl -I "$PWD/lib" -I$TESTINGDIR/threaded_blead/lib/perl5/site_perl/5.45.2/x86_64-linux-thread-multi -e 'use List::MoreUtils::XS'
                                                    ^   ^     ^         ^      ^

Note the 5 lowest subdirectories in the path supplied to the second -I -- as well as the absence of /*.

Second,

Based on the discussion in this ticket and the older issues it references, I was expecting to get a different and, presumably, more informative error message when attempting to install the threaded build's List::MoreUtils::XS against the unthreaded perl.

To test this, on my laptop (Ubuntu Linux) I built from the branch in your pull request per your instructions. When I ran my spelling of the command in Step #8 above, I got:

$ ./perl -I "$PWD/lib" -I$TESTINGDIR/threaded_blead/lib/perl5/site_perl/5.45.2/x86_64-linux-thread-multi -e 'use List::MoreUtils::XS'
XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xed00080, needed 0xe500000)

However, on my Linode (Debian Linux), I re-ran this procedure only at a much earlier commit to blead -- the commit which happened to be 1 commit after v5.44.0 from last month:

commit f13f58bd9d4aff45f5ff409ff3b8f4dc2e6dbd2b
Author:     Leon Timmermans <fawaka@gmail.com>
AuthorDate: Wed Jul 15 20:25:50 2026
Commit:     Leon Timmermans <fawaka@gmail.com>
CommitDate: Wed Jul 15 20:52:41 2026

    Add epigraph for v5.44.0

Commands I issued (some of which, again, are shell scripts I've frequently used):

$ cd ~/gitwork/perl2
$ export THREADED_PERL_ARGS="-des -Dusedevel -Dusethreads" && \
  install_custom_branch_for_testing \
  f13f58bd9d \
  "$THREADED_PERL_ARGS" \
  f13f58bd9d

$ cd $TESTINGDIR/f13f58bd9d
$ ./bin/perl -v | head -2 | tail -1
This is perl 5, version 44, subversion 0 (v5.44.0-1-gf13f58bd9d) built for x86_64-linux-thread-multi

$ ./bin/perl -Ilib -V:config_args
config_args='-des -Dusedevel -Dusethreads -Dprefix=/home/jkeenan/testing/f13f58bd9d -Uversiononly -Dman1dir=none -Dman3dir=none';

$ ./bin/cpan List::MoreUtils::XS
# installed
$ ./bin/perl -Ilib -MList::MoreUtils::XS -E 'say $List::MoreUtils::XS::VERSION;'
0.430

# Now return to the checkout, clean it but don't change the commit, rebuild unthreaded

$ cd ~/gitwork/perl2
$ git clean -dfx
$ regular_configure && make test_prep
$ ./perl -v | head -2 | tail -1
This is perl 5, version 44, subversion 0 (v5.44.0-1-gf13f58bd9d) built for x86_64-linux

$ ./perl -I "$PWD/lib" -I$TESTINGDIR/f13f58bd9d/lib/perl5/site_perl/5.44.0/x86_64-linux-thread-multi -e 'use List::MoreUtils::XS'
XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xec00080, needed 0xe500000)

Note that I got exactly the same error message at a commit from last month as I did from your branch. Was my expectation that the message would be different incorrect?

@tonycoz

tonycoz commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
$ ./bin/perl -Ilib -V:config_args
config_args='-des -Dusedevel -Dusethreads -Dprefix=/home/jkeenan/testing/f13f58bd9d -Uversiononly -Dman1dir=none -Dman3dir=none';

$ ./bin/cpan List::MoreUtils::XS
# installed
$ ./bin/perl -Ilib -MList::MoreUtils::XS -E 'say $List::MoreUtils::XS::VERSION;'
0.430

You need to have installed List::MoreUtils::XS with the change from this PR in the old perl (ie. as if you'd updated EU::PXS from cpan after this change is released to CPAN).

You should be able to do that by checking out this branch, cd to the git checkout, and run:

/home/jkeenan/testing/f13f58bd9d/bin/perl Porting/test-dist-modules.pl -i ExtUtils-ParseXS

and only then install List::MoreUtils::XS.

Edit: fix :: to - in installation command

Comment thread dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Node.pm
mauke added 2 commits August 3, 2026 04:43
If a dynamically loaded library fails the XS handshake (because it was
compiled for a binary incompatible perl), it reports the error from its
own C file with no context except for __FILE__:

    XS.c: loadable library and perl binaries are mismatched (got first handshake key 0xed00080, needed 0xee00080)

This patch sets a synthetic (but more user friendly) __FILE__ value
(including the module name) around the version check macros in the
generated boot section. The error message is now:

    XS.c in List::MoreUtils::XS: loadable library and perl binaries are mismatched (got first handshake key 0xed00080, needed 0xee00080)

Fixes Perl#24646, Perl#15861, Perl#16654.
@mauke
mauke force-pushed the fix-24646-eu-pxs-hack-file branch from 20642de to 0d81eb4 Compare August 3, 2026 02:44
@mauke
mauke merged commit 1f53715 into Perl:blead Aug 4, 2026
33 checks passed
@mauke
mauke deleted the fix-24646-eu-pxs-hack-file branch August 4, 2026 13:44
mauke added a commit to mauke/perl5 that referenced this pull request Aug 4, 2026
We now always pipe our output through ExtUtils::ParseXS::CountLines (so
we can always get the current output line number), but this should make
no difference to normal output, which checks 'config_WantLineNumbers'
before actually switching to a different file with a custom '#line'
directive. Which is to say, the documented behavior of 'linenumbers =>
0' should remain unchanged.

Follow-up to PR Perl#24651.
mauke added a commit that referenced this pull request Aug 7, 2026
We now always pipe our output through ExtUtils::ParseXS::CountLines (so
we can always get the current output line number), but this should make
no difference to normal output, which checks 'config_WantLineNumbers'
before actually switching to a different file with a custom '#line'
directive. Which is to say, the documented behavior of 'linenumbers =>
0' should remain unchanged.

Follow-up to PR #24651.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unhelpful error message when loading mismatched XS modules

4 participants