atom feed15 messages in org.perl.perl5-portersScalar flags pollution
FromSent OnAttachments
madd...@free.frAug 4, 2011 5:53 am 
Nicholas ClarkAug 4, 2011 6:09 am 
madd...@free.frAug 4, 2011 6:44 am 
Sébastien Aperghis-TramoniAug 4, 2011 8:38 am 
Dave MitchellAug 5, 2011 2:56 am 
Nicholas ClarkAug 8, 2011 3:11 am 
Sébastien Aperghis-TramoniAug 8, 2011 3:21 pm 
Jan DuboisAug 8, 2011 4:04 pm 
Dave MitchellAug 11, 2011 1:37 am 
Chas. OwensAug 11, 2011 8:31 am 
Jesse LuehrsAug 11, 2011 8:40 am 
Chas. OwensAug 11, 2011 11:34 am 
Jan DuboisAug 11, 2011 12:24 pm 
Nicholas ClarkAug 11, 2011 12:58 pm 
Jan DuboisAug 11, 2011 3:24 pm 
Subject:Scalar flags pollution
From:madd...@free.fr (madd@free.fr)
Date:Aug 4, 2011 5:53:35 am
List:org.perl.perl5-porters

Hello all,

I'm pretty sure this is a well-known caveat, but I don't know where to find more information about this. Maybe I'm using the wrong terms as well.

The problem can be exposed with the following example:

use strict; use Devel::Peek;

my @values = ( 42, 3.1415, "oh hai", 2.618, 56 );

for my $i (0..$#values) { my $v = $values[$i]; Dump $v; }

Let's run it:

$ perl5.14.0 bug-flags-pollution SV = IV(0x674b80) at 0x674b90 REFCNT = 1 FLAGS = (PADMY,IOK,pIOK) IV = 42

so far, so good

SV = PVNV(0x651570) at 0x674b90 REFCNT = 1 FLAGS = (PADMY,NOK,pNOK) IV = 42 NV = 3.1415 PV = 0

uh, now it has become a kind of dual-var with both IV and NV

SV = PVNV(0x651570) at 0x674b90 REFCNT = 1 FLAGS = (PADMY,POK,pPOK) IV = 42 NV = 3.1415 PV = 0x671100 "oh hai"\0 CUR = 6 LEN = 16

and now, a triple-var, with the PV as well

SV = PVNV(0x651570) at 0x674b90 REFCNT = 1 FLAGS = (PADMY,NOK,pNOK) IV = 42 NV = 2.618 PV = 0x671100 "oh hai"\0 CUR = 6 LEN = 16

here, the new NV replaces the old one, keeping the rest untouched

SV = PVNV(0x651570) at 0x674b90 REFCNT = 1 FLAGS = (PADMY,IOK,pIOK) IV = 56 NV = 2.618 PV = 0x671100 "oh hai"\0 CUR = 6 LEN = 16

and the same for the last IV

I guess that the problem is because $v is at each loop recreated at the same memory address, with no zeroing, hence being filled with the flags and values from the previous loop.

This behaviour exists and is consistent since at least 5.6.0

With usual Perl code, in Perl land, this is usually transparent because Perl DTRT of converting between the different values to give the user the good one.

However, this flags pollution becomes a problem with XS code, or at the very least with NetSNMP::agent, the module which exposed the issue. The relevant parts of its XS code are:

/* We want an integer here */ if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG) || SvIOK(value)) { /* Good - got a real one (or a blessed object that we hope will turn
out OK) */ ltmp = SvIV(value); /* ... */ } else if (SvPOKp(value)) { /* Might be OK - got a string, so try to convert it, allowing base 10,
octal, and hex forms */ /* ... */ } else { snmp_log(LOG_ERR, "Non-integer value passed to setValue with
ASN_INTEGER: type was %d\n", SvTYPE(value)); /* ... */ }

If I understand correctly, this code is subtly wrong in that it doesn't take into account SVt_PVIV, which is what Perl gives it because of the flags pollution bug.

I will send a patch to Net-SNMP maintainers in order to improve this part, but this won't be of any help except in a very distant future, because I work with production versions (IOW, old and packaged). Hence this mail to see if anyone would have an idea of a workaround.

Currently, the only one I found with NetSNMP::agent is to stringify everything. A bit unstatisfaying. I would prefer to have scalars with the correct flags.

Note: I saw that writing the code this way:

for my $v (@values) { ... }

doesn't expose the issue, but it doesn't fit my need, which is the module POE::Component::NetSNMP::agent

Thanks in advance.

Close the world, txEn eht nepO.