Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package perl-Sys-Mmap for openSUSE:Factory checked in at 2026-06-09 14:26:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Sys-Mmap (Old) and /work/SRC/openSUSE:Factory/.perl-Sys-Mmap.new.2375 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Sys-Mmap" Tue Jun 9 14:26:10 2026 rev:2 rq:1358069 version:0.210.0 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Sys-Mmap/perl-Sys-Mmap.changes 2024-09-04 13:26:32.878595280 +0200 +++ /work/SRC/openSUSE:Factory/.perl-Sys-Mmap.new.2375/perl-Sys-Mmap.changes 2026-06-09 14:28:41.817399566 +0200 @@ -1,0 +2,27 @@ +Mon Mar 23 06:24:02 UTC 2026 - Tina Müller <[email protected]> + +- updated to 0.210.0 (0.21) + see /usr/share/doc/packages/perl-Sys-Mmap/Changes + + Todd Rinaldo, Mar 22 2026 v0.21 + Bug Fixes: + * Fix segfault with non-zero offset in mmap. When mmap() was called with + a non-zero offset, Perl's sv_clear would try to Safefree() the mmap'd + pointer on scope exit, causing a crash. Now uses Perl's magic system to + store unmap metadata safely. GH #1, PR #12 + * Fix len=0 with offset inferring wrong mapped size. When mmap() was + called with len=0 and a non-zero offset, the length was inferred as the + full file size rather than file_size - offset, causing the mapping to + extend past the end of the file. PR #14 + * Resolve tied interface DESTROY munmap failures. DESTROY receives a + blessed reference, not the mmap'd SV itself. Without dereferencing, + the magic lookup failed and tried to munmap a garbage pointer. PR #16 + Improvements: + * Document len=0 with offset behavior and caveats in POD. Clarify that + len=0 with offset infers remaining file size, document the + offset-beyond-EOF error, and add caveat about page alignment. PR #15 + Maintenance: + * Modernize CI: consolidate separate linux.yml and macos.yml into a + unified testsuite.yml with updated actions and containers. PR #13 + +------------------------------------------------------------------- Old: ---- Sys-Mmap-0.20.tar.gz New: ---- README.md Sys-Mmap-0.21.tar.gz _scmsync.obsinfo build.specials.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Sys-Mmap.spec ++++++ --- /var/tmp/diff_new_pack.Uue1dT/_old 2026-06-09 14:28:44.145496192 +0200 +++ /var/tmp/diff_new_pack.Uue1dT/_new 2026-06-09 14:28:44.145496192 +0200 @@ -1,7 +1,7 @@ # # spec file for package perl-Sys-Mmap # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,15 +18,16 @@ %define cpan_name Sys-Mmap Name: perl-Sys-Mmap -Version: 0.200.0 +Version: 0.210.0 Release: 0 -# 0.20 -> normalize -> 0.200.0 -%define cpan_version 0.20 +# 0.21 -> normalize -> 0.210.0 +%define cpan_version 0.21 License: Artistic-1.0 OR GPL-1.0-or-later Summary: Uses mmap to map in a file as a Perl variable URL: https://metacpan.org/release/%{cpan_name} Source0: https://cpan.metacpan.org/authors/id/T/TO/TODDR/%{cpan_name}-%{cpan_version}.tar.gz Source1: cpanspec.yml +Source100: README.md BuildRequires: perl BuildRequires: perl-macros Provides: perl(Sys::Mmap) = %{version} @@ -50,105 +51,8 @@ area, and sparse memory usage is handled optimally on most modern UNIX implementations. -Using the 'new()' method provides a 'tie()''d interface to 'mmap()' that -allows you to use the variable as a normal variable. If a filename is -provided, the file is opened and mapped in. If the file is smaller than the -length provided, the file is grown to that length. If no filename is -provided, anonymous shared inheritable memory is used. Assigning to the -variable will replace a section in the file corresponding to the length of -the variable, leaving the remainder of the file intact and unmodified. -Using 'substr()' allows you to access the file at an offset, and does not -place any requirements on the length argument to 'substr()' or the length -of the variable being inserted, provided it does not exceed the length of -the memory region. This protects you from the pathological cases involved -in using 'mmap()' directly, documented below. - -When calling 'mmap()' or 'hardwire()' directly, you need to be careful how -you use the variable. Some programming constructs may create copies of a -string which, while unimportant for smallish strings, are far less welcome -if you're mapping in a file which is a few gigabytes big. If you use -'PROT_WRITE' and attempt to write to the file via the variable you need to -be even more careful. One of the few ways in which you can safely write to -the string in-place is by using 'substr()' as an lvalue and ensuring that -the part of the string that you replace is exactly the same length. Other -functions will allocate other storage for the variable, and it will no -longer overlay the mapped in file. - -* Sys::Mmap->new( 'VARIABLE', 'LENGTH', 'OPTIONALFILENAME' ) - -Maps 'LENGTH' bytes of (the contents of) 'OPTIONALFILENAME' if -'OPTIONALFILENAME' is provided, otherwise uses anonymous, shared -inheritable memory. This memory region is inherited by any 'fork()'ed -children. 'VARIABLE' will now refer to the contents of that file. Any -change to 'VARIABLE' will make an identical change to the file. If 'LENGTH' -is zero and a file is specified, the current length of the file will be -used. If 'LENGTH' is larger then the file, and 'OPTIONALFILENAME' is -provided, the file is grown to that length before being mapped. This is the -preferred interface, as it requires much less caution in handling the -variable. 'VARIABLE' will be tied into the "Sys::Mmap" package, and -'mmap()' will be called for you. - -Assigning to 'VARIABLE' will overwrite the beginning of the file for a -length of the value being assigned in. The rest of the file or memory -region after that point will be left intact. You may use 'substr()' to -assign at a given position: - - substr(VARIABLE, POSITION, LENGTH) = NEWVALUE - -* mmap(VARIABLE, LENGTH, PROTECTION, FLAGS, FILEHANDLE, OFFSET) - -Maps 'LENGTH' bytes of (the underlying contents of) 'FILEHANDLE' into your -address space, starting at offset 'OFFSET' and makes 'VARIABLE' refer to -that memory. The 'OFFSET' argument can be omitted in which case it defaults -to zero. The 'LENGTH' argument can be zero in which case a stat is done on -'FILEHANDLE' and the size of the underlying file is used instead. - -The 'PROTECTION' argument should be some ORed combination of the constants -'PROT_READ', 'PROT_WRITE' and 'PROT_EXEC', or else 'PROT_NONE'. The -constants 'PROT_EXEC' and 'PROT_NONE' are unlikely to be useful here but -are included for completeness. - -The 'FLAGS' argument must include either 'MAP_SHARED' or 'MAP_PRIVATE' (the -latter is unlikely to be useful here). If your platform supports it, you -may also use 'MAP_ANON' or 'MAP_ANONYMOUS'. If your platform supplies -'MAP_FILE' as a non-zero constant (necessarily non-POSIX) then you should -also include that in 'FLAGS'. POSIX.1b does not specify 'MAP_FILE' as a -'FLAG' argument and most if not all versions of Unix have 'MAP_FILE' as -zero. - -mmap returns 'undef' on failure, and the address in memory where the -variable was mapped to on success. - -* munmap(VARIABLE) - -Unmaps the part of your address space which was previously mapped in with a -call to 'mmap(VARIABLE, ...)' and makes VARIABLE become undefined. - -munmap returns 1 on success and undef on failure. - -* hardwire(VARIABLE, ADDRESS, LENGTH) - -Specifies the address in memory of a variable, possibly within a region -you've 'mmap()'ed another variable to. You must use the same precautions to -keep the variable from being reallocated, and use 'substr()' with an exact -length. If you 'munmap()' a region that a 'hardwire()'ed variable lives in, -the 'hardwire()'ed variable will not automatically be 'undef'ed. You must -do this manually. - -* Constants - -The Sys::Mmap module exports the following constants into your namespace: - - MAP_SHARED MAP_PRIVATE MAP_ANON MAP_ANONYMOUS MAP_FILE - MAP_NORESERVE MAP_POPULATE - MAP_HUGETLB MAP_HUGE_2MB MAP_HUGE_1GB - PROT_EXEC PROT_NONE PROT_READ PROT_WRITE - -Of the constants beginning with 'MAP_', only 'MAP_SHARED' and 'MAP_PRIVATE' -are defined in POSIX.1b and only 'MAP_SHARED' is likely to be useful. - %prep -%autosetup -n %{cpan_name}-%{cpan_version} +%autosetup -n %{cpan_name}-%{cpan_version} -p1 %build perl Makefile.PL INSTALLDIRS=vendor OPTIMIZE="%{optflags}" ++++++ README.md ++++++ ## Build Results Current state of perl in openSUSE:Factory is  The current state of perl in the devel project build (devel:languages:perl)  ++++++ Sys-Mmap-0.20.tar.gz -> Sys-Mmap-0.21.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/Changes new/Sys-Mmap-0.21/Changes --- old/Sys-Mmap-0.20/Changes 2020-02-13 19:34:40.000000000 +0100 +++ new/Sys-Mmap-0.21/Changes 2026-03-22 22:33:29.000000000 +0100 @@ -1,3 +1,27 @@ +Todd Rinaldo, Mar 22 2026 v0.21 + +Bug Fixes: +* Fix segfault with non-zero offset in mmap. When mmap() was called with + a non-zero offset, Perl's sv_clear would try to Safefree() the mmap'd + pointer on scope exit, causing a crash. Now uses Perl's magic system to + store unmap metadata safely. GH #1, PR #12 +* Fix len=0 with offset inferring wrong mapped size. When mmap() was + called with len=0 and a non-zero offset, the length was inferred as the + full file size rather than file_size - offset, causing the mapping to + extend past the end of the file. PR #14 +* Resolve tied interface DESTROY munmap failures. DESTROY receives a + blessed reference, not the mmap'd SV itself. Without dereferencing, + the magic lookup failed and tried to munmap a garbage pointer. PR #16 + +Improvements: +* Document len=0 with offset behavior and caveats in POD. Clarify that + len=0 with offset infers remaining file size, document the + offset-beyond-EOF error, and add caveat about page alignment. PR #15 + +Maintenance: +* Modernize CI: consolidate separate linux.yml and macos.yml into a + unified testsuite.yml with updated actions and containers. PR #13 + Todd Rinaldo, Feb 13 2020 v0.20 * Add use warnings to improve kwalitee * Spelling error in manpage diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/MANIFEST new/Sys-Mmap-0.21/MANIFEST --- old/Sys-Mmap-0.20/MANIFEST 2020-02-13 19:35:17.000000000 +0100 +++ new/Sys-Mmap-0.21/MANIFEST 2026-03-22 22:35:05.000000000 +0100 @@ -7,8 +7,10 @@ Mmap.pm Mmap.xs README +t/comprehensive.t t/mmap.t t/munmap_errors.t +t/offset.t xt/author/pod.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/MANIFEST.SKIP new/Sys-Mmap-0.21/MANIFEST.SKIP --- old/Sys-Mmap-0.20/MANIFEST.SKIP 2020-02-13 19:34:15.000000000 +0100 +++ new/Sys-Mmap-0.21/MANIFEST.SKIP 2026-03-22 22:34:42.000000000 +0100 @@ -1,6 +1,4 @@ -^.github/ -^.git/.* -^MYMETA.* -^MANIFEST.bak -^Makefile -^.gitignore +^.git +^MYMETA\.* +^MANIFEST\.bak$ +^Makefile$ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/META.json new/Sys-Mmap-0.21/META.json --- old/Sys-Mmap-0.20/META.json 2020-02-13 19:35:17.000000000 +0100 +++ new/Sys-Mmap-0.21/META.json 2026-03-22 22:35:05.000000000 +0100 @@ -4,7 +4,7 @@ "Scott Walters <[email protected]>" ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], @@ -52,6 +52,6 @@ "url" : "http://github.com/toddr/Sys-Mmap/tree/master" } }, - "version" : "0.20", - "x_serialization_backend" : "JSON::PP version 4.02" + "version" : "0.21", + "x_serialization_backend" : "JSON::PP version 4.16" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/META.yml new/Sys-Mmap-0.21/META.yml --- old/Sys-Mmap-0.20/META.yml 2020-02-13 19:35:17.000000000 +0100 +++ new/Sys-Mmap-0.21/META.yml 2026-03-22 22:35:05.000000000 +0100 @@ -9,7 +9,7 @@ configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -27,5 +27,5 @@ bugtracker: https://github.com/toddr/Sys-Mmap/issues license: http://dev.perl.org/licenses/ repository: http://github.com/toddr/Sys-Mmap/tree/master -version: '0.20' -x_serialization_backend: 'CPAN::Meta::YAML version 0.018' +version: '0.21' +x_serialization_backend: 'CPAN::Meta::YAML version 0.020' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/Mmap.pm new/Sys-Mmap-0.21/Mmap.pm --- old/Sys-Mmap-0.20/Mmap.pm 2020-02-13 19:34:40.000000000 +0100 +++ new/Sys-Mmap-0.21/Mmap.pm 2026-03-22 22:33:35.000000000 +0100 @@ -72,7 +72,9 @@ memory. This memory region is inherited by any C<fork()>ed children. C<VARIABLE> will now refer to the contents of that file. Any change to C<VARIABLE> will make an identical change to the file. If C<LENGTH> is zero -and a file is specified, the current length of the file will be used. If +and a file is specified, the current length of the file will be used. (Note: +the tied interface does not support C<OFFSET>, so this always maps the full +file.) If C<LENGTH> is larger then the file, and C<OPTIONALFILENAME> is provided, the file is grown to that length before being mapped. This is the preferred interface, as it requires much less caution in handling the variable. @@ -92,7 +94,15 @@ address space, starting at offset C<OFFSET> and makes C<VARIABLE> refer to that memory. The C<OFFSET> argument can be omitted in which case it defaults to zero. The C<LENGTH> argument can be zero in which case a stat is done on -C<FILEHANDLE> and the size of the underlying file is used instead. +C<FILEHANDLE> and the file size is used to infer the mapping length. If +C<OFFSET> is also specified, the inferred length is C<file_size - OFFSET> +(i.e. the remainder of the file from C<OFFSET> onward). An exception is +thrown if C<OFFSET> is at or beyond the end of the file. + +B<Caveat>: the underlying C<mmap()> system call requires the offset to be a +multiple of the system page size (typically 4096 bytes). Sys::Mmap handles +non-page-aligned offsets internally by adjusting the mapping, but very large +non-aligned offsets may map slightly more memory than the requested region. The C<PROTECTION> argument should be some ORed combination of the constants C<PROT_READ>, C<PROT_WRITE> and C<PROT_EXEC>, or else C<PROT_NONE>. The @@ -179,7 +189,7 @@ use strict; use warnings; -our $VERSION = '0.20'; +our $VERSION = '0.21'; our $AUTOLOAD; # For sub AUTOLOAD diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/Mmap.xs new/Sys-Mmap-0.21/Mmap.xs --- old/Sys-Mmap-0.20/Mmap.xs 2020-02-13 19:34:40.000000000 +0100 +++ new/Sys-Mmap-0.21/Mmap.xs 2026-03-22 22:24:59.000000000 +0100 @@ -152,6 +152,49 @@ static size_t pagesize = 0; +/* Magic structure to track mmap info for proper cleanup */ +typedef struct { + void *base_addr; /* actual address returned by mmap() */ + size_t total_len; /* actual length passed to mmap() (len + slop) */ +} mmap_info_t; + +#define MMAP_MAGIC_TYPE PERL_MAGIC_ext + +static int mmap_magic_free(pTHX_ SV *sv, MAGIC *mg) { + mmap_info_t *info = (mmap_info_t *) mg->mg_ptr; + if (info) { + if (info->base_addr) { + munmap((MMAP_RETTYPE) info->base_addr, info->total_len); + info->base_addr = NULL; + } + Safefree(info); + mg->mg_ptr = NULL; + } + return 0; +} + +static MGVTBL mmap_magic_vtbl = { + 0, /* get */ + 0, /* set */ + 0, /* len */ + 0, /* clear */ + mmap_magic_free, /* free */ + 0, /* copy */ + 0, /* dup */ + 0 /* local */ +}; + +/* Find our mmap magic on an SV, or NULL if not present */ +static MAGIC *find_mmap_magic(SV *sv) { + MAGIC *mg; + if (SvTYPE(sv) >= SVt_PVMG) { + for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { + if (mg->mg_type == MMAP_MAGIC_TYPE && mg->mg_virtual == &mmap_magic_vtbl) + return mg; + } + } + return NULL; +} #if _FILE_OFFSET_BITS > 32 #define get_off(a) (atoll(a)) @@ -229,7 +272,10 @@ if (fstat(fd, &st) == -1) { croak("mmap: no len provided, fstat failed, unable to infer length"); } - len = st.st_size; + if (off >= st.st_size) { + croak("mmap: offset (%"IVdf") is at or beyond end of file (size %"IVdf")", (IV)off, (IV)st.st_size); + } + len = st.st_size - off; } } @@ -257,8 +303,21 @@ /* would sv_usepvn() be cleaner/better/different? would still try to realloc... */ SvPVX(var) = (char *) addr + slop; SvCUR_set(var, len); - SvLEN_set(var, slop); + SvLEN_set(var, 0); /* must be 0 so Perl won't Safefree() the mmap'd pointer */ SvPOK_only(var); + + /* Attach magic to handle munmap on cleanup */ + { + mmap_info_t *info; + MAGIC *mg; + Newxz(info, 1, mmap_info_t); + info->base_addr = (void *) addr; + info->total_len = len + slop; + mg = sv_magicext(var, NULL, MMAP_MAGIC_TYPE, &mmap_magic_vtbl, + (const char *) info, 0); + mg->mg_flags |= MGf_LOCAL; + } + ST(0) = sv_2mortal(newSVnv((IV) addr)); SV * @@ -277,9 +336,28 @@ return; } - if (munmap((MMAP_RETTYPE) SvPVX(var) - SvLEN(var), SvCUR(var) + SvLEN(var)) == -1) { - croak("munmap failed! errno %d %s\n", errno, strerror(errno)); - return; + { + MAGIC *mg = find_mmap_magic(var); + if (mg) { + mmap_info_t *info = (mmap_info_t *) mg->mg_ptr; + if (munmap((MMAP_RETTYPE) info->base_addr, info->total_len) == -1) { + croak("munmap failed! errno %d %s\n", errno, strerror(errno)); + return; + } + info->base_addr = NULL; /* prevent double munmap in magic free */ + } else { + /* fallback for hardwire'd or legacy variables without magic */ + /* SvLEN > 0 means this is a regular Perl string, not mmap'd */ + if (SvLEN(var) != 0) { + errno = EINVAL; + croak("munmap failed! errno %d %s\n", errno, strerror(errno)); + return; + } + if (munmap((MMAP_RETTYPE) SvPVX(var), SvCUR(var)) == -1) { + croak("munmap failed! errno %d %s\n", errno, strerror(errno)); + return; + } + } } SvREADONLY_off(var); SvPVX(var) = 0; @@ -289,14 +367,37 @@ ST(0) = &PL_sv_yes; void -DESTROY(var) +DESTROY(var) SV * var PROTOTYPE: $ CODE: /* XXX refrain from dumping core if this var wasnt previously mmap'd*/ - if (munmap((MMAP_RETTYPE) SvPVX(var), SvCUR(var)) == -1) { - croak("munmap failed! errno %d %s\n", errno, strerror(errno)); - return; + + /* For tied objects: DESTROY receives the blessed reference (\$mmap_sv), + * not the mmap'd SV itself. Dereference to reach the actual mapping. */ + if (SvROK(var)) + var = SvRV(var); + + { + MAGIC *mg = find_mmap_magic(var); + if (mg) { + mmap_info_t *info = (mmap_info_t *) mg->mg_ptr; + if (info->base_addr) { + if (munmap((MMAP_RETTYPE) info->base_addr, info->total_len) == -1) { + croak("munmap failed! errno %d %s\n", errno, strerror(errno)); + return; + } + info->base_addr = NULL; + } + } else { + /* SvLEN > 0 means this is a regular Perl string, not mmap'd */ + if (SvLEN(var) != 0) + return; + if (munmap((MMAP_RETTYPE) SvPVX(var), SvCUR(var)) == -1) { + croak("munmap failed! errno %d %s\n", errno, strerror(errno)); + return; + } + } } SvREADONLY_off(var); SvPVX(var) = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/t/comprehensive.t new/Sys-Mmap-0.21/t/comprehensive.t --- old/Sys-Mmap-0.20/t/comprehensive.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Sys-Mmap-0.21/t/comprehensive.t 2026-03-22 22:24:59.000000000 +0100 @@ -0,0 +1,220 @@ +#! perl + +use strict; +use warnings; + +use Test::More 'no_plan'; +use Sys::Mmap; +use Fcntl qw(O_WRONLY O_CREAT O_TRUNC O_RDONLY O_RDWR); + +my $temp_file = "comprehensive.tmp"; +my $file_size = 8192; + +# Create a test file with known content +sub create_test_file { + my ($size, $pattern) = @_; + $pattern = "ABCD1234" unless defined $pattern; + sysopen(my $fh, $temp_file, O_WRONLY|O_CREAT|O_TRUNC) or die "$temp_file: $!\n"; + my $content = ($pattern x int($size / length($pattern) + 1)); + $content = substr($content, 0, $size); + print $fh $content; + close $fh; + return $content; +} + +# ---- Tied interface tests (new / TIESCALAR) ---- + +{ + my $content = create_test_file(4096); + + # Collect any warnings during tied cleanup to verify no munmap failures + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, $_[0] }; + + { + my $var; + my $obj = Sys::Mmap->new($var, 4096, $temp_file); + ok(defined $obj, "tied file: new() returns a defined object"); + ok(tied($var), "tied file: variable is tied after new()"); + is(length($var), 4096, "tied file: tied variable has correct length"); + is($var, $content, "tied file: tied variable has correct content"); + + # Test STORE: writing through tied interface + my $new_data = "HELLO"; + $var = $new_data; + is(substr($var, 0, length($new_data)), $new_data, "tied file: STORE writes data at beginning"); + # Rest of mapping should be unchanged + is(substr($var, length($new_data), 4), substr($content, length($new_data), 4), "tied file: STORE preserves rest of data"); + # Let $var and $obj go out of scope together + } + pass("tied file: variable cleaned up without crash"); + + # The DESTROY fix should prevent munmap failures on the blessed reference + my @munmap_warns = grep { /munmap failed/ } @warnings; + is(scalar @munmap_warns, 0, "tied file: no munmap failures during DESTROY cleanup"); +} + +{ + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, $_[0] }; + + { + my $var; + my $obj = Sys::Mmap->new($var, 4096); + ok(defined $obj, "tied anon: new() with anonymous memory returns defined object"); + ok(tied($var), "tied anon: variable is tied for anonymous memory"); + is(length($var), 4096, "tied anon: anonymous tied variable has correct length"); + + $var = "test data"; + is(substr($var, 0, 9), "test data", "tied anon: STORE works on anonymous memory"); + } + pass("tied anon: anonymous memory cleaned up without crash"); + + my @munmap_warns = grep { /munmap failed/ } @warnings; + is(scalar @munmap_warns, 0, "tied anon: no munmap failures during DESTROY cleanup"); +} + +{ + my @warnings; + local $SIG{__WARN__} = sub { push @warnings, $_[0] }; + + # Create a tiny file + create_test_file(100); + is(-s $temp_file, 100, "tied grow: initial file is 100 bytes"); + + { + my $var; + Sys::Mmap->new($var, 4096, $temp_file); + ok(tied($var), "tied grow: tied to grown file"); + is(length($var), 4096, "tied grow: tied variable reflects grown size"); + } + + # File should have been grown to 4096 + ok(-s $temp_file >= 4096, "tied grow: file was grown to requested length"); + + my @munmap_warns = grep { /munmap failed/ } @warnings; + is(scalar @munmap_warns, 0, "tied grow: no munmap failures during DESTROY cleanup"); +} + +# ---- MAP_ANON tests ---- + +{ + my $data; + my $addr = mmap($data, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, *STDOUT); + ok(defined $addr, "MAP_ANON: mmap succeeds"); + is(length($data), 4096, "MAP_ANON: mapping has correct length"); + + # Anonymous memory should be zero-filled + is($data, "\0" x 4096, "MAP_ANON: memory is zero-filled"); + + # Write and read back + substr($data, 0, 5) = "Hello"; + is(substr($data, 0, 5), "Hello", "MAP_ANON: can write to region"); + + munmap($data); +} + +{ + my $data; + eval { mmap($data, 0, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, *STDOUT) }; + like($@, qr/MAP_ANON.*no length/i, "MAP_ANON: len=0 croaks"); +} + +# ---- len=0 with offset: inferred length should be file_size - offset ---- + +{ + my $content = create_test_file(8192); + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 0, PROT_READ, MAP_SHARED, $fh); + close $fh; + + is(length($data), 8192, "len=0: infers full file size"); + is($data, $content, "len=0: maps entire file content"); + munmap($data); +} + +{ + my $content = create_test_file(8192); + my $offset = 4096; + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 0, PROT_READ, MAP_SHARED, $fh, $offset); + close $fh; + + is(length($data), 8192 - $offset, "len=0 with offset: infers file_size - offset"); + is($data, substr($content, $offset), "len=0 with offset: content matches file from offset"); + munmap($data); +} + +{ + my $content = create_test_file(8192); + my $offset = 256; # likely not page-aligned + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 0, PROT_READ, MAP_SHARED, $fh, $offset); + close $fh; + + is(length($data), 8192 - $offset, "len=0 with non-aligned offset: infers correct remaining size"); + is($data, substr($content, $offset), "len=0 with non-aligned offset: content matches"); + munmap($data); +} + +{ + create_test_file(4096); + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + eval { mmap($data, 0, PROT_READ, MAP_SHARED, $fh, 4096) }; + close $fh; + like($@, qr/offset.*beyond end of file/i, "len=0: offset at EOF croaks"); +} + +{ + create_test_file(4096); + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + eval { mmap($data, 0, PROT_READ, MAP_SHARED, $fh, 8192) }; + close $fh; + like($@, qr/offset.*beyond end of file/i, "len=0: offset beyond EOF croaks"); +} + +# ---- Explicit offset with explicit length ---- + +{ + my $content = create_test_file(8192); + my $offset = 4096; + my $len = 1024; + + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, $len, PROT_READ, MAP_SHARED, $fh, $offset); + close $fh; + + is(length($data), $len, "explicit offset+length: correct length"); + is($data, substr($content, $offset, $len), "explicit offset+length: correct content"); + munmap($data); +} + +# ---- DESTROY cleanup (implicit munmap via scope exit) ---- + +{ + my $content = create_test_file(8192); + + { + my $data; + sysopen(my $fh, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 0, PROT_READ, MAP_SHARED, $fh); + close $fh; + is(length($data), 8192, "DESTROY: mmap succeeded before scope exit"); + # $data goes out of scope - DESTROY called implicitly + } + pass("DESTROY: survived without explicit munmap"); +} + +# Cleanup +unlink($temp_file); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Sys-Mmap-0.20/t/offset.t new/Sys-Mmap-0.21/t/offset.t --- old/Sys-Mmap-0.20/t/offset.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Sys-Mmap-0.21/t/offset.t 2026-03-22 22:24:59.000000000 +0100 @@ -0,0 +1,44 @@ +#! perl + +use strict; +use warnings; + +use Test::More tests => 4; + +use Sys::Mmap; +use Fcntl qw(O_WRONLY O_CREAT O_TRUNC O_RDONLY); + +my $temp_file = "offset.tmp"; +my $file_size = 8192; + +# Create a file large enough to map with an offset +sysopen(FOO, $temp_file, O_WRONLY|O_CREAT|O_TRUNC) or die "$temp_file: $!\n"; +print FOO "A" x $file_size; +close FOO; + +# Test 1: mmap with non-zero offset and explicit munmap +{ + my $data; + sysopen(FOO, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 256, PROT_READ, MAP_SHARED, FOO, 256); + close FOO; + is(length($data), 256, "mmap with offset returns correct length"); + is($data, "A" x 256, "mmap with offset returns correct data"); + munmap($data); +} + +# Test 2: mmap with non-zero offset, DESTROY cleanup (no explicit munmap) +# This is the crash from GitHub issue #1 - segfault on cleanup when offset != 0 +{ + my $data; + sysopen(FOO, $temp_file, O_RDONLY) or die "$temp_file: $!\n"; + mmap($data, 256, PROT_READ, MAP_SHARED, FOO, 256); + close FOO; + is(length($data), 256, "mmap with offset (DESTROY path) returns correct length"); + # $data goes out of scope here - DESTROY is called instead of explicit munmap + # Before the fix, this would segfault +} + +pass("Survived DESTROY with non-zero offset (no segfault)"); + +unlink($temp_file); ++++++ _scmsync.obsinfo ++++++ mtime: 1780844503 commit: 63b93509eec2f5031a2f343c3857d543e5287c2f85eb876636563b7f9cfa91a2 url: https://src.opensuse.org/perl/perl-Sys-Mmap revision: 63b93509eec2f5031a2f343c3857d543e5287c2f85eb876636563b7f9cfa91a2 projectscmsync: https://src.opensuse.org/perl/_ObsPrj ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-06-07 17:01:43.000000000 +0200 @@ -0,0 +1 @@ +.osc ++++++ cpanspec.yml ++++++ --- /var/tmp/diff_new_pack.Uue1dT/_old 2026-06-09 14:28:44.361505157 +0200 +++ /var/tmp/diff_new_pack.Uue1dT/_new 2026-06-09 14:28:44.369505488 +0200 @@ -1,5 +1,5 @@ --- -#description_paragraphs: 3 +description_paragraphs: 3 #description: |- # override description from CPAN #summary: override summary from CPAN
