EvanK has asked for the wisdom of the Perl Monks concerning the following question:

I'm getting a troubling (but non-fatal) warning when trying to use the File::Copy module to copy files. I asked about this earlier in the chatterbox and tried advice I got there, but to no avail...

I've tested this first on my own desktop under Windows 2000 Professional, running ActivePerl v5.8.7 (ActiveState build 813), and as well on our win32 server under Windows 2003 Server, running ActivePerl v5.8.8 (ActiveState build 817).

The problem occurs within the following code:

print "Copying $src_path\\$upc\\$tracknum.mp3 to $dst_path\\$upc\\$tra +cknum.mp3\n"; copy("$src_path\\$upc\\$tracknum.mp3","$dst_path\\$upc\\$tracknum.mp3" +) or warn "Couldn't copy $src_path\\$upc\\$realtracknum.mp3: $!";
I get the following output (this occurs in a loop, so the same output w/ warning repeats with 02.mp3, 03.mp3, etc):
Copying m:\music\tracks\685506213212\01.mp3 to m:\music\tagged\6855062 +13212\01.mp3 Attempt to free unreferenced scalar: SV 0x1e77330, Perl interpreter: 0 +x15d45fc at C:/Perl/lib/File/Copy.pm line 91.
The copy actually succeeds, so my warn() is never called. But a different warning seems to be generated by the File::Copy module itself. I've even tried using forward-slashes in the paths instead of backslashes, with the same result. I could just use a backticked system command, but I'd like to keep it portable in case we move this to one of our linux servers later on.

I've found messages from assorted mailing lists and forums that leads me to believe this is an error internal to the perl interpreter and is rather rare, could this be the case?



UPDATE: thanks to imp, it seems to be some kind of conflict between DBI and File::Copy, when running on ActiveState's build of perl. I'm going to report this to ActiveState as a bug, and use Win32::CopyFile() directly in the meantime. Thanks for the help, everyone!

__________
Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
- Terry Pratchett

Replies are listed 'Best First'.
Re: Attempt to free unreferenced scalar in File::Copy (ActivePerl)
by imp (Priest) on Aug 15, 2006 at 23:09 UTC
    This code demonstrates the bug:
    use strict; use warnings; use DBI; use File::Copy qw(copy); my $dsn = 'DBI:ODBC:somedb'; my $db_user = ''; my $db_pass = ''; my $dbh = DBI->connect($dsn,$db_user,$db_pass ) or die $DBI::errstr; if (1) { # This causes the warning my $loh = $dbh->selectall_hashref('select 1 as a, 2 as b','a'); } if (0) { # This causes the warning my $sth = $dbh->prepare('select 1 as a, 2 as b'); $sth->execute(); my $loh = $sth->fetchall_hashref('a'); $sth->finish; } if (0) { # This does not cause the warning my $aoa = $dbh->selectall_arrayref('select 1 as a, 2 as b'); } if (0) { # This does not cause the warning my $sth = $dbh->prepare('select 1 as a, 2 as b'); $sth->execute(); my $hash = $sth->fetchrow_hashref(); $sth->finish; } copy('a','b') or die "Failed to copy a to b. $!\n"; $dbh->disconnect;
    Note that the error only occurs when selectall_hashref or fetchall_hashref are called, and none of the others.

    Run with the following versions:

    * activestate perl 5.8.8
    * Win32 0.2601
    * DBI 1.50
    * File::Copy 2.09
    

      ++imp, it is DBI! more specifically, its the combination of DBI and File::Copy. And it doesnt reproduce on my debian or gentoo servers either, so, I'd assume its activestate specific.

      __________
      Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
      - Terry Pratchett

        Are you using DBD::ODBC or a different driver?

        I'm still investigating the issue but it's slow going as I learn more about perl internals.

Re: Attempt to free unreferenced scalar in File::Copy (ActivePerl)
by ikegami (Patriarch) on Aug 15, 2006 at 18:28 UTC
    File::Copy is a pure perl module, so it's unlikely the direct source of the problem. I wonder if the error is really in Win32, an XS module. File::Copy uses Win32's CopyFile function.
      After reading your post, I tried directly calling Win32::CopyFile(), and it worked with no warning:
      use Win32; Win32::CopyFile( "$src_path/$upc/$realtracknum.mp3", "$dst_path/$upc/$realtracknum.mp3", 1 ) or warn "couldnt File::Copy $src_path/$upc/$realtracknum.mp3: $!";
      And the actual call to Win32::CopyFile() in File/Copy.pm (nested within a large, unwieldy if..else chain) uses the same syntax:
      return 0 unless @_ == 2; return Win32::CopyFile(@_, 1);
      So the problem seems to be with File/Copy.pm calling Win32::CopyFile(). Whatever that seems to indicate, though, I'm not quite sure.


      Addendum: I also tried passing an actual array, to see if that somehow pooched the XS code, but this still works without any warnings:

      my @copy_args = ( "$src_path/$upc/$realtracknum.mp3", "$dst_path/$upc/$realtracknum.mp3" ); Win32::CopyFile(@copy_args, 1) or warn "couldnt File::Copy $src_path/$upc/$realtracknum.mp3: $!";

      __________
      Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
      - Terry Pratchett

Re: Attempt to free unreferenced scalar in File::Copy (ActivePerl)
by BrowserUk (Patriarch) on Aug 15, 2006 at 20:25 UTC

    Are you using threads?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I'm not using threads in my program, and I don't think ActiveState even compiles in threading support...Not 100% certain about that, though.

      __________
      Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
      - Terry Pratchett

        I don't think ActiveState even compiles in threading support

        They do, and have since 5.6.1. Maybe before.

        Characteristics of this binary (from libperl): Compile-time options: MULTIPLICITY USE_ITHREADS USE_LARGE_FILES PERL +_IMPLICIT_CONTEXT PERL_IMPLICIT_SYS Locally applied patches: ActivePerl Build 811 21540 Fix backward-compatibility issues in if.pm 23565 Wrong MANIFEST.SKIP Built under MSWin32 Compiled at Dec 13 2004 09:52:01

        Are you using fork?

        Why these questions. The error message

        Attempt to free unreferenced scalar: SV 0x1e77330, Perl interpreter: 0 +x15d45fc ...

        Is telling you that during garbage collection (sorry, Reference Counting Automated Memory Management Cleanup! Hereafter referred to as GC :), the Perl interpreter represented by the handle 0x15d45fc, attempted to free the scalar at location 0x1e77330 and discovered that it didn't own that piece of memory.

        To my knowledge, this can only occur when a reference is passed between two separate instances of the Perl Interpreter running within the same process. And that, (to my knowledge), can only occur if you are using threads. Either explicitly through the use of threads, or (whatever that word is that means the opposite of explicitly that simply won't form in my head just now), through the use of ActivePerl's fork emulation, which uses threads.

        In general, as the warning occurs during cleanup of a variable, if it happens when the program is exiting, then you can usually safely ignore it as your program is exiting anyway. If you are using a very recent version of perl, 5.8.8 or later from memory, then you can disable the warning using no warnings 'threads';. But if it occurs at some other time in the code, and particulary if you get the same message (with different scalars), repeatedly, it probably represents and memory leak.

        It's also possible that the cross-interpreter-passed scalar has (silently), caused other problems that have not been detected, so it usually worth tracking the problem down to the source. To do that, you would need to post more code, preferably a minimal testcase.

        Most of the above is based upon my own investigations of the problem--I've seen it a lot in my threaded code, though much less recently. I've never seen the title error occur outside of either threaded, or pseudo-forked code. By implication, there would need to be multiple interpreters involved for one of them to discover a scalar it did not own. The only way I know of to have multiple interpreters is via threads, though theoretically, if you were embedding Perl into a C program, you could create multiple interpreters without using threads. There may be other situations in which the message could occur that I am unaware of.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Attempt to free unreferenced scalar in File::Copy (ActivePerl) - problem is between Config and DBI
by imp (Priest) on Aug 16, 2006 at 19:31 UTC
    Isolated the problem further. File::Copy is not involved at all actually, it was a Config lookup that did it.
    use strict; use warnings; use Config; use DBI; my $dsn = 'DBI:ODBC:somedb'; my $db_user = ''; my $db_pass = ''; my $dbh = DBI->connect($dsn,$db_user,$db_pass ) or die $DBI::errstr; my $loh = $dbh->selectall_hashref('select 1 as a, 2 as b','a'); print "checking d_symlink\n"; print "found\n" if ($Config{d_symlink}); print "checking d_readlink\n"; print "found\n" if ($Config{d_readlink}); print "checking d_link\n"; print "found\n" if ($Config{d_link}); print "checking d_symlink && d_readlink\n"; print "found\n" if (($Config{d_symlink} && $Config{d_readlink})); print "checking (d_symlink && d_readlink) || d_link)\n"; print "found\n" if (($Config{d_symlink} && $Config{d_readlink}) || $Co +nfig{d_link}); print "All done.\n"; $dbh->disconnect;
    Output is:
    checking d_symlink checking d_readlink checking d_link found checking d_symlink && d_readlink checking (d_symlink && d_readlink) || d_link) found Attempt to free unreferenced scalar: SV 0x1a61cdc, Perl interpreter: 0 +x223ecc at copytest.pl line 26. All done.
Re: Attempt to free unreferenced scalar in File::Copy (ActivePerl)
by syphilis (Archbishop) on Aug 16, 2006 at 08:51 UTC
    I can't reproduce the problem (with AS build 817) based on the description of the problem:
    use warnings; use File::Copy; # The files 't1.txt', 't2.txt', 't3.txt', # 't4.txt', and 't5.txt' all exist in the cwd. for(1..5) { if (copy("t${_}.txt", "u${_}.txt")) { print "copied t${_}.txt to u${_}.txt\n"; } else {print "$_: Copy failed\n"} } __END__ Outputs: copied t1.txt to u1.txt copied t2.txt to u2.txt copied t3.txt to u3.txt copied t4.txt to u4.txt copied t5.txt to u5.txt

    What does line 91 of Copy.pm contain ? For me, it marks the middle of a block of code that won't even be executed on Win32.

    Cheers,
    Rob