chapel
chapel copied to clipboard
[Bug]:Ternary Operator in return statement causes (subsequent) stack corruption
The following routine, without the ternary operator used in the return statement, works.
inline proc positive(z : string)
{
param EMPTY = '';
/*
* THIS WORKS
*/
if z == '~' then
return ' ';
else if z == '+' then
return z;
else
return EMPTY;
/*
* THIS IS BROKEN
return if z == '~' then ' ' else (if z == '+' then z else EMPTY);
*/
}
If the BROKEN return statement is enabled (and the earlier code disabled), it must do naughty things to the stack because subsequent assignment to a freshly allocated array of strings gets corrupted. Or am I using strings the wrong way?
Sample file (suitably trimmed of excess functionality) appears here:
inline proc positive(z : string)
{
param EMPTY = '';
/*
* THIS WORKS
*/
if z == '~' then
return ' ';
else if z == '+' then
return z;
else
return EMPTY;
/*
* THIS IS BROKEN
return if z == '~' then ' ' else (if z == '+' then z else EMPTY);
*/
}
proc itoa(a : int, p = '', s = '', g = 0, b = 10)
{
// capture the sign of the argument and if negative, use a minus sign
// if positive, decide on whether to use plus sign, blank, or nothing
const sign = if a < 0 then '-' else positive(p);
// compute |a| safely if a == 2^-31
var n = if a == min(int) then 1:uint + max(int):uint else abs(a):uint;
// cast base 'b' to an unsigned nteger
const _b = b:uint;
// decode |a| into digits
var m = 0;
var t : [0..#20] uint(8);
do
{
const j = n / _b;
t[m] = (n - _b * j):uint(8); n = j; m += 1;
}
while n > 0;
// writeln("digits ", t[0..#m]);
// reverse the order
{
param NUL = '';
const digit = "0123456789abcdef";
var rt : [0..m] string;
rt[0] = sign;
// BETWEEN HERE and the JOIN below, parts of rt[0] get clobbered
// writeln("rt[0] prior to assembly ", rt[0..#1]);
// sometime during this loop, rt[0] is sometimes overwritten
for i in 1..m
{
rt[i] = digit[t[m - i]];
}
// writeln("rt[0] after an assembly ", rt[0..#1]);
// NORMALLY THIS is ''.join(rt)
return '|'.join(rt);
}
}
const _2p32 = (1 << 32):real(64);
// writeln(_2p32 * _2p32);
writeln(itoa(1234567, "+"));
writeln(itoa(-1234567, "+"));
writeln(itoa(max(int), "+"), " <--- MAXINT");
writeln(itoa(min(int), "+"));
writeln(itoa(max(int), "+", "_", 6), " <--- +MAXINT - not quite!!");
writeln(itoa(-max(int), "+", "_", 6), " <--- -MAXINT - not quite!!");
// writeln(itoa(0));
// writeln(itoa(0, "+"));
// writeln(itoa(1234567, "+", ",", 3));
// writeln(itoa(0x1234567f, s = "_", g = 2, b = 16));
// writeln(itoa(min(int), s = "_", g = 2, b = 16));
exit(0);
Tagging @mppf and @vasslitvinov. Thanks.
The above code is supposed to encode an integer in base 10 or base 16. The functionality removed for purposes here is related to handling grouping separators, e.g. a comma every three digits or an underscore every two digits in a hexadecimal number.