Skip to content

openbsd: ensure we link to the built libperl.a, not the system libperl.a #23265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: blead
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ Adp |SV * |amagic_deref_call \
p |bool |amagic_is_enabled \
|int method

CTdp |void |api_version_assert \
|size_t interp_size \
|NULLOK void *v_my_perl \
|NN const char *api_version
ETXip |void |append_utf8_from_native_byte \
|const U8 byte \
|NN U8 **dest
Expand Down
1 change: 1 addition & 0 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
# define _to_utf8_upper_flags(a,b,c,d,e) Perl__to_utf8_upper_flags(aTHX_ a,b,c,d,e)
# define amagic_call(a,b,c,d) Perl_amagic_call(aTHX_ a,b,c,d)
# define amagic_deref_call(a,b) Perl_amagic_deref_call(aTHX_ a,b)
# define api_version_assert Perl_api_version_assert
# define apply_attrs_string(a,b,c,d) Perl_apply_attrs_string(aTHX_ a,b,c,d)
# define apply_builtin_cv_attributes(a,b) Perl_apply_builtin_cv_attributes(aTHX_ a,b)
# define atfork_lock Perl_atfork_lock
Expand Down
19 changes: 17 additions & 2 deletions lib/ExtUtils/t/Embed.t
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,26 @@ if ($^O eq 'VMS') {
elsif ($^O eq 'os390' && $Config{usedl}) {
push(@cmd,"-L$lib", ldopts());
} else { # Not MSWin32 or OS/390 (z/OS) dynamic.
push(@cmd,"-L$lib",'-lperl');
my $ldopts = ldopts();
if ($^O eq 'openbsd' && $Config{useshrplib} eq "false") {
# see github #22125
# with OpenBSD, the packaged gcc (tries to) link
# against the system libperl, this will be fine once
# this perl gets installed, but that's not so good when
# testing against the uninstalled perl.
# This also matches how Makefile.SH links the perl executable
push @cmd, "$lib/libperl.a";
$ldopts =~ s/ -lperl\b//;
}
else {
push(@cmd,"-L$lib",'-lperl');
}
local $SIG{__WARN__} = sub {
warn $_[0] unless $_[0] =~ /No library found for .*perl/
};
push(@cmd, '-Zlinker', '/PM:VIO') # Otherwise puts a warning to STDOUT!
if $^O eq 'os2' and $Config{ldflags} =~ /(?<!\S)-Zomf\b/;
push(@cmd,ldopts());
push(@cmd, $ldopts);
}

if ($^O eq 'aix') { # AIX needs an explicit symbol export list.
Expand Down Expand Up @@ -196,6 +209,8 @@ int main(int argc, char **argv, char **env) {
perl_construct(my_perl);
PL_exit_flags |= PERL_EXIT_WARN;

PERL_API_VERSION_ASSERT;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not move PERL_API_VERSION_ASSERT; to right below my_perl = perl_alloc();. me knowing various permutatoins of crashing ancient modern perl5xx.dll permutations, this test code/demo code already segved or caused heap corruption before reaching the PERL_API_VERSION_ASSERT; statement.

PL_exit_flags |= PERL_EXIT_WARN;

What is grammar token/src code ascii string PL_exit_flags in machine code view?

Is PL_exit_flags a Perl 5.6/5.8/5.10 symbian/win32/win16/cray style
extern "C" int * Perl_Isolation_PL_exit_flags(void);
is it?
extern "C" int * Perl_Isolation_PL_exit_flags(my_perl);

is it? IIRC below is AKA dVAR; macro,
extern "C" int * Perl_Isolation_PL_exit_flags(my_env, my_perl);

is it?
extern "C" int PL_exit_flags;

is it?
extern int __@@C$PLUS$__PLUSSS$666@_QWERTY@_PL_exit_flags@__;

is it?
*(int*)( ((char*)my_perl) + 0x47c)

is it?
extern "C" int __$SONAME@PL_exit_flags$libperl.so.5.40.1.0083.6798;

What did the end user C dev really write (hex dump wise) with ascii string PL_exit_flags |= PERL_EXIT_WARN; ?

Lets do our best to print in english to STDERR before LD_LAZY_LINK insta-KILL the process and fills the users console with unreadable CPU GPR and FP register hex dumps and leaves a 30MB core dump file of gibberish on the end users machine.

my_puts("ok 3");

perl_parse(my_perl, NULL, (sizeof(cmds)/sizeof(char *))-1, (char **)cmds, env);
Expand Down
8 changes: 8 additions & 0 deletions perl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9264,6 +9264,14 @@ END_EXTERN_C
# define PERL_STACK_REALIGN
#endif

#ifdef MULTIPLICITY
# define PERL_API_VERSION_ASSERT \
Perl_api_version_assert(sizeof(PerlInterpreter), aTHX, PERL_API_VERSION_STRING)
#else
# define PERL_API_VERSION_ASSERT \
Perl_api_version_assert(sizeof(PerlInterpreter), NULL, PERL_API_VERSION_STRING)
#endif

/*

(KEEP THIS LAST IN perl.h!)
Expand Down
10 changes: 10 additions & 0 deletions pod/perldelta.pod
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,11 @@ Added testing of the perl headers against the C++ compiler
corresponding to the C compiler perl is being built with.
[L<GH #22232|https://github.com/Perl/perl5/issues/22232>]

=item *

When testing embedding, add a sanity check to ensure the C<libperl> we
link against matches the perl we are building. [GH #22125]

=back

=head1 Platform Support
Expand Down Expand Up @@ -978,6 +983,11 @@ C<-Accflags=-DNO_LOCALE_COLLATE> option to your invocation of C<./Configure>,
or just C<-DNO_LOCALE_COLLATE> to the C<ccflags> and C<cppflags>
variables in F<config.sh>.

=item OpenBSD

When testing embedding, ensure we link against the correct static
libperl. [GH #22125]

=back

=head1 Internal Changes
Expand Down
5 changes: 5 additions & 0 deletions pod/perldiag.pod
Original file line number Diff line number Diff line change
Expand Up @@ -4020,6 +4020,11 @@ See L</500 Server error>.
by a missing delimiter on a string or pattern, because it eventually
ended earlier on the current line.

=item Mismatch between expected and libperl %s

(F) For an embedded perl, the perl headers and configuration you built
your binary against don't match the library you've linked with.

=item Mismatched brackets in template

(F) A pack template could not be parsed because pairs of C<[...]> or
Expand Down
5 changes: 5 additions & 0 deletions proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5739,6 +5739,52 @@ S_xs_version_bootcheck(pTHX_ SSize_t items, SSize_t ax, const char *xs_p,
}
}

/*
=for apidoc api_version_assert

Used by the PERL_API_VERSION_CHECK macro to compare the perl the
object was built with and the perl that C<libperl> was built with.

This can be used to ensure that these match and produces a more
diagnosable than random crashes and mis-behaviour.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a word or two missing after diagnosable. diagnosable behavior, perhaps?


=cut
*/

void
Perl_api_version_assert(size_t interp_size, void *v_my_perl,
const char *api_version) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not switch const char *api_version to PERL_BCDVERSION which is an integer? The only reason xs_handshake() uses a const char *api_version is hysterical raisins with pre-existing EU::PXS code gen behavior and hysterical raisins over string equality method of operation in the IEEE vs W3C vs WHATWG vs IETF version.pm standards war (example: fb79428 ).

Since my TLDR understanding of v-strings and version string equality and comparison logical operations is, v-str and ver.pm == > < logical operations, should just be labeled abstract undefined behavior <=> operator if your writing code for CPAN or writing PP code that will execute on more than 1 build number of libperl.so. Or will execute on any /bin/perl other than your employer's official corporate "Perl on Docker" image.

So b/c there is so much soap drama with non-floating point version numbers, and PERL_API_VERSION, is a 3 '.' dots thing, which means is part of the standards war, I decided to keep the const char * null_term_perl_api_ver parameter for xs_handshake. The drama with 3 '.' dots and v prefix was quite active 10 years ago. And xs_handshake() was supposed to be "low impact" or "not invasive" or minimalist in design.

using const char * null_term_perl_api_ver instead of a U32 aka PERL_BCDVERSION, in the prototype of xs_handshake() would've allowed macro PERL_API_VERSION_STRING to be string "5.40.0-armbe-hurd-newlib-no_rms-lgbtqabi" or "5.40.0-mipsle-muscl-no_afferoabi". P5P would never modify the PERL_API_VERSION_STRING macro to be "5.40.0-mipsle-muscl-no_afferoabi", but P5P can't send lawyers and SWAT/GIGN to force random Linux/BSD distros projects to reverse their patches to Perl on their published .isos.

So that was reason # 2 why I left it as a char * and not a U32. Minimalist, most flexible for the future, wait and see what happens, dont do an over engineered forklift refactor.

AFAIK the ELF spec is mostly written where all the behaviors are "optional" to implement, but if the feature/constant/bit in a bitfield/C struct/member in a struct, is implemented by a vendor, then the feature/constant/bit in a bitfield/C struct/member in a struct has "defined behavior" in ELF. ELF isn't like Windows and its PE format, where there is ONE WAY TO DO IT, NO EXCEPTIONS! B/c Windows and PE mandate forever backwards ABI compatibility to the "i386 pre-release SDK" from Oct 1992.

I don't believe ELF binaries compiled in the 1980s for i386 are copy+paste+double click executable on Ubuntu/Freebsd/Fedora in 2025. besides, the Linux kernel doesn't even know what an ELF file is, and isn't aware that the ELF spec exists.

From Linux's viewpoint, ELF is just a random 3rd party kernel driver someone wrote a while back. You can disable ELF support in Linux if you prefer Windows PE .exes/.dlls or MachO files more than the ELF format.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/binfmt_elf_fdpic.c#n92

https://docs.kernel.org/admin-guide/binfmt-misc.html

So yeah, I have no clue if some Unix OS will add a dozen random tokens/identifiers/english lang words, to the PERL_API_VERSION_STRING "5.40.0" macro. I don't think any Linux/BSD distro has randomly decided to start patching PERL_API_VERSION_STRING in their system perls, in the last couple of years, so at this point in 2025, I would say to use PERL_BCDVERSION U32 instead here. Also this code is the REVERSE of xs_handshake(), the consumer and producer were flipped around. This is a .bin file under full end user control compiled by the end user, loading a random unknown libperl.so file into address space. The end user is using the cryptographic-ally secure P5P code base (aka git + SSL + github.com), the end user didn't checkout the patched system perl and its exact Configure settings from their Distro vendor (canonical)'s RCS. So P5P codebase and the end user's fork of the P5P repo, have no reason to change macro PERL_API_VERSION_STRING to "5.40.0-mipsle-muscl-no_afferoabi" for some real or imaginary engineering reason.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yeah, I have no clue if some Unix OS will add a dozen random tokens/identifiers/english lang words, to the PERL_API_VERSION_STRING "5.40.0" macro. I don't think any Linux/BSD distro has randomly decided to start patching PERL_API_VERSION_STRING in their system perls, in the last couple of years, so at this point in 2025, I would say to use PERL_BCDVERSION U32 instead here. Also this code is the REVERSE of xs_handshake(), the consumer and producer were flipped around. This is a .bin file under full end user control compiled by the end user, loading a random unknown libperl.so file into address space. The end user is using the cryptographic-ally secure P5P code base (aka git + SSL + github.com), the end user didn't checkout the patched system perl and its exact Configure settings from their Distro vendor (canonical)'s RCS. So P5P codebase and the end user's fork of the P5P repo, have no reason to change macro PERL_API_VERSION_STRING to "5.40.0-mipsle-muscl-no_afferoabi" for some real or imaginary engineering reason.

15 minutes after I speak of the devil, and the devil himself appears in production perl code. See this ticket.

#23355

Someone was NOT USING the cryptographically signed .git P5P's Perl code base, but their vendor's [Fedora 501(c)(3) LLC] cryptographically signed .git repo that is a fork of P5P codebase, to do their own personal Perl interp core hacking adventures. And then they ran into problems using the code base of Fedora's fork of Perl 5 code base, then came to this GH, looking for help, for a fork of Perl that P5P isn't responsible for. Out of civility, P5P volunteers will obviously offer advice to that person, even though P5P is not legally responsible for a Linux Distro's vendor patches to mainline Perl 5 VM. But still, 15 mins ago I said nobody will ever do that, and someone just did that.

dTHX;

PERL_ARGS_ASSERT_API_VERSION_ASSERT;

if (interp_size != sizeof(PerlInterpreter)) {
/* detects various types of configuration mismatches */
/* diag_listed_as: Mismatch between expected and libperl %s */
Perl_croak(aTHX_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use a croak_nocontext(), this fn is max run 1x a process. the croak branches are 0 Kelvin code and will never execute w/o C dev user error, the performance of executing while (1) { eval { croak("heap corruption"); }; } is illogical. smaller machine code is the correct goal.

"Mismatch between expected and libperl interpreter structure size %zd vs %zd",
interp_size, sizeof(PerlInterpreter));
}
if (
#ifdef MULTIPLICITY
v_my_perl != my_perl
#else
v_my_perl != NULL
#endif
) {
/* detect threads vs non-threads mismatch */
/* diag_listed_as: Mismatch between expected and libperl %s */
Perl_croak(aTHX_
"Mismatch between expected and libperl interpreter pointer");
}
if (strNE(api_version, PERL_API_VERSION_STRING)) {
/* diag_listed_as: Mismatch between expected and libperl %s */
Perl_croak(aTHX_
"Mismatch between expected and libperl API versions %s vs %s",
api_version, PERL_API_VERSION_STRING);
}
}

PERL_STATIC_INLINE bool
S_gv_has_usable_name(pTHX_ GV *gv)
{
Expand Down
Loading