https://bz.apache.org/SpamAssassin/show_bug.cgi?id=8470

            Bug ID: 8470
           Summary: r1939572 regresses zip extraction to require non-core
                    IO::String; previously used core IO::Uncompress::Unzip
           Product: Spamassassin
           Version: 4.0.3
          Hardware: PC
                OS: Mac OS X
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Libraries
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: Undefined

Created attachment 6162
  --> https://bz.apache.org/SpamAssassin/attachment.cgi?id=6162&action=edit
proposed patch

r1939572 ("New size-limited unzipping utility functions that other code now
uses to unzip and unrar") introduced Mail::SpamAssassin::Util::Zip and reworked
Handler::Archive (and Plugin::OLEVBMacro) to read zip archives through it.

The new utility reads archives with Archive::Zip + IO::String, gating zip
support on both being installed:

    # lib/Mail/SpamAssassin/Util/Zip.pm
    use constant HAS_ARCHIVE_ZIP => eval { require Archive::Zip; 1 };
    use constant HAS_IO_STRING   => eval { require IO::String; 1 };
    ...
    sub open_zip {
      my ($dataref) = @_;
      return unless HAS_ARCHIVE_ZIP && HAS_IO_STRING;

Before r1939572, Handler::Archive extracted zips with IO::Uncompress::Unzip,
which is part of core Perl (via IO::Compress) and needs no CPAN install:

    -use constant HAS_UNZIP => eval { require IO::Uncompress::Unzip; 1 };
    ...
    -  my $u = IO::Uncompress::Unzip->new(\$data, MultiStream => 0);

So the change swaps a core-only zip path for one that depends on the non-core
IO::String. On any installation that has Archive::Zip but not IO::String, zip
extraction is now silently disabled -- the handler only emits the startup
warning:

    archive: zip archives not supported, required module Archive::Zip or
IO::String missing

IO::String is the only newly-required piece; it is used solely to wrap the
in-memory archive bytes as a filehandle for Archive::Zip->readFromFileHandle().
Perl has provided an in-core equivalent since 5.8 (open my $fh, '<', \$scalar),
so the dependency is avoidable.


Impact

- Zip extraction (and anything downstream of it) stops working wherever
  IO::String is absent, even though Archive::Zip is installed -- a regression
  from the prior core-only behavior.

- t/handler_javascript_utf16.t fails on such hosts, because it relies on the
  Archive handler extracting an inner UTF-16 .js from a zip fixture:

      Not found: utf16le_bom_js_normalized =  1.0 JS_UTF16
      Not found: utf16be_nobom_js_normalized =  1.0 JS_UTF16
      ...
      t/handler_javascript_utf16.t (Wstat: 512) Tests: 7 Failed: 2  (tests 3,
5)

- t/handler_archive.t and t/olevbmacro.t do not fail but skip entirely
  (skip_all => 'Need IO::String for this test'), so the regression is otherwise
  invisible in `make test` on these hosts.

- r1939572 also added IO::String to Makefile.PL PREREQ_PM and
  DependencyInfo.pm, so fresh installs now pull in a dependency that core Perl
  already satisfied.


Steps to reproduce

On a host with Archive::Zip installed but not IO::String:

    perl -MArchive::Zip -e1               # ok
    perl -MIO::String -e1                 # Can't locate IO/String.pm
    prove t/handler_javascript_utf16.t    # FAIL (2/7)


Environment where observed

- SVN trunk at/after r1939572; Mail::SpamAssassin 4.000003
- Perl v5.36.0
- Archive::Zip 1.68 present; IO::String absent; IO::Uncompress::Unzip (core)
  present


Proposed fix

Keep Archive::Zip (it provides the new size-limited, joined-archive reading
that r1939572 intends) but drop the IO::String requirement, reading the
in-memory archive via an in-core scalar filehandle instead:

    sub _read_zip {
      my ($dataref) = @_;
      open(my $fh, '<', $dataref) or return;
      binmode $fh;
      my $old_handler = Archive::Zip::setErrorHandler(\&_zip_error);
      my $zip = Archive::Zip->new();
      my $status = $zip->readFromFileHandle($fh);
      Archive::Zip::setErrorHandler($old_handler);
      return unless $status == Archive::Zip::AZ_OK();
      return $zip;
    }

and remove the HAS_IO_STRING gate from Util::Zip, Handler::Archive, and
Plugin::OLEVBMacro, the IO::String entry from Makefile.PL and
DependencyInfo.pm,
and the IO::String skip guards in t/handler_archive.t and t/olevbmacro.t.

With this change all three tests pass (no longer skipped), and zip extraction
no
longer requires any non-core module beyond Archive::Zip.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to