[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] vec() & unpack() 5.0.6r1m



On Fri, 23 Feb 1996, Paul Duda wrote:

> PowerMac 7100/66 System 7.5.1
> Macperl v5.0.6r1m
> 
> Why does the following script only produce the expected results the first time
> the script is run?
> 
> for ($i = 0;$i < 5;$i++) {
>     vec($vector, $i, 1) = 1;
>     print $i, '. Setbits are: ', unpack("%32b*", $vector), "\n";
> }
> print '$vector is: "', $vector, '" or ', unpack("b*", $vector), "\n";
> 
> Expected results and the actual results of the first run
> --------------------------------------------------------
> 0. Setbits are: 1
> 1. Setbits are: 2
> 2. Setbits are: 3
> 3. Setbits are: 4
> 4. Setbits are: 5
> $vector is: "#031#" or 11111000
> 
> Results of subsequent runs without quitting and relaunching MacPerl
> -------------------------------------------------------------------
> 0. Setbits are: 0
> 1. Setbits are: 48
> 2. Setbits are: 112
> 3. Setbits are: 0
> 4. Setbits are: 5
> $vector is: "#031#" or 11111000
> 
> A work around for this problem is to quit and relaunch MacPerl after running
> a script that uses vec() and unpack(). Can I be sure that the results will
> really be correct the first time the script is run?
> 
> Has anyone else noticed this and thought it was a problem?

The relevent code from pp.c is:

...
    static char* bitcount = 0;
...
                if (!bitcount) {
                    Newz(601, bitcount, 256, char);
                    for (bits = 1; bits < 256; bits++) {
                        if (bits & 1)   bitcount[bits]++;
                        if (bits & 2)   bitcount[bits]++;
                        if (bits & 4)   bitcount[bits]++;
                        if (bits & 8)   bitcount[bits]++;
                        if (bits & 16)  bitcount[bits]++;
                        if (bits & 32)  bitcount[bits]++;
                        if (bits & 64)  bitcount[bits]++;
                        if (bits & 128) bitcount[bits]++;
                    }
...

This allocates a 256 byte array then sets it up with the corrects number
of bits for each os the 256 possible values of a byte.  The pointer is
declared static, so it retains it's value (pointing to the array) on
subsequent calls to the same routine. 

However, when a script ends, the CleanupPerl routine (in MPScript.c) calls:

...
        free_pool_memory('PERL');
...

which frees the memory allocated to the array.  The pointer bitcount then
becomes a stale pointer to unallocated memory which is written over when the 
next script runs.  Ouch.

One relatively easy way to fix this would be to declare bitcount as a static 
array with the values already defined, like this:

static char bitcount[256] =
              { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
                1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
                1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
                1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
                2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 
                3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
                3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 
                4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 } 

...which I just created with the following PERL script (look familiar?):

for $i (0..255) {
        $bitcount = 0;
        if ($i & 1)   { $bitcount++ }
        if ($i & 2)   { $bitcount++ }
        if ($i & 4)   { $bitcount++ }
        if ($i & 8)   { $bitcount++ }
        if ($i & 16)  { $bitcount++ }
        if ($i & 32)  { $bitcount++ }
        if ($i & 64)  { $bitcount++ }
        if ($i & 128) { $bitcount++ }

        unless ($i % 16) { print "\n                " }
        print "$bitcount, ";
}

Of course, Matthias would have to incorporate this (or a different fix) into 
his code for you.

John Peterson -- University Networking Services -- Brigham Young University
Internet: John_Peterson@byu.edu                       Phone: (801) 378-5007