[comp.lang.perl] Function return type conversion bug

nwinton@iona.axion.bt.co.uk (Neil Winton) (02/28/90)

Ho hum, it's bug time again ...

This is a bit of a strange one.  Under certain circumstances, perl seems
to fail to convert an integer return value into a string.  I'm afraid
I haven't been able to narrow it down too closely, but attached is a
fairly small program that exercises the bug.

You feed it lines of the form `base#digits' and it translates `digits',
interpreted in base `base', to decimal -- for example `2#101010' gives
`42'.  The answer should come out as `The result is 42, ok?' but in
fact gives `The result is , ok?'.

(This is actually an excerpt from a much larger perl program which
implements a programmable RPN scientific calculator ... the
programming language looks rather like PostScript ... it was
originally written in nawk ... Perverse? Yes, I know ... I may post it
one day if anyone is interested ...)

You can force the result to be returned correctly by concatenating the
null string ('') to the result.

Over to you, Larry!

	Neil

E-Mail (UUCP)  NWinton@axion.bt.co.uk (...!uunet!mcsun!axion.bt.co.uk!nwinton)
Organisation   British Telecom Research Laboratories (RT3134)
Snail Mail     306 SSTF, BTRL, Martlesham Heath, IPSWICH IP5 7RE, UK
Telephone      +44 473 646079 (or +44 473 643210)
*** This line intentionally left justified ***
-------- Cut Here --------
#!/usr/local/bin/perl

$[ = 1;		# Spot the awk heritage!
$\ = "\n";

&InitDigitValue;

while (<>) {
    chop;

    print 'The result is ' . &BaseToDec($_) . ', ok?';
}

exit 0;

sub InitDigitValue {
    local($i, $str);
    $str =
      '00112233445566778899aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ';
    for ($i = 0; $i < 36; $i++) {
	$digitval{substr($str, 2 * $i + 1, 1)} = $i;
	$digitval{substr($str, 2 * $i + 2, 1)} = $i;
    }
}

sub BaseToDec {
    local($str) = @_;
    print "&BaseToDec($str)";
    local($base, @digits, $n, $i, $r);
    $base = $str;
    $base =~ s/#.*//;
    if ($base <= 0 || $base > 36) {
	&Error('Invalid input base: ' . $base);
	return;
    }
    $str =~ s/^[0-9]+#//;
    $str = &ExplodeString($str);
    $n = (@digits = split(' ', $str, 999));
    $i = 0;
    $r = 0;
    for ($i = 1; $i <= $n; $i++) {
	$r *= $base;
	if ($digitval{$digits[$i]} >= $base) {
	    &Error('Invalid base ' . $base . ' digit');
	    return 0;
	}
	$r += $digitval{$digits[$i]};
    }
    print "returns $r";
    $r;
    ### $r . '';	# Force to string by adding ''
}

sub ExplodeString {
    local($str) = @_;
    $str = join(' ', split(//, $str)); 
    $str;
}
------- Cut Here --------

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/01/90)

In article <1990Feb28.130139.2942@axion.bt.co.uk> nwinton@axion.bt.co.uk writes:
: This is a bit of a strange one.  Under certain circumstances, perl seems
: to fail to convert an integer return value into a string.  I'm afraid
: I haven't been able to narrow it down too closely, but attached is a
: fairly small program that exercises the bug.

Fixed.

Actually, it didn't have anything to do with whether the value was numeric,
but with whether the value was clobbered in restoring a local().  Since
the value for $r . '' is stored in a different place than the value of
$r itself, it didn't get clobbered on the return.

The bug was hidden before this because it didn't show up unless a routine
mixed returns and non-returns.  Say "return $r;" also worked around
the problem.

Larry