1#!./perl 2 3BEGIN { 4 chdir 't' if -d 't'; 5 require './test.pl'; 6 set_up_inc('../lib'); 7} 8 9use Config; 10 11plan(tests => 78); 12 13my $exception_134139 = "Use of strings with code points over 0xFF as arguments to vec is forbidden"; 14 15is(vec($foo,0,1), 0); 16is(length($foo), undef); 17vec($foo,0,1) = 1; 18is(length($foo), 1); 19is(unpack('C',$foo), 1); 20is(vec($foo,0,1), 1); 21 22is(vec($foo,20,1), 0); 23vec($foo,20,1) = 1; 24is(vec($foo,20,1), 1); 25is(length($foo), 3); 26is(vec($foo,1,8), 0); 27vec($foo,1,8) = 0xf1; 28is(vec($foo,1,8), 0xf1); 29is((unpack('C',substr($foo,1,1)) & 255), 0xf1); 30is(vec($foo,2,4), 1);; 31is(vec($foo,3,4), 15); 32vec($Vec, 0, 32) = 0xbaddacab; 33is($Vec, "\xba\xdd\xac\xab"); 34is(vec($Vec, 0, 32), 3135089835); 35 36# ensure vec() handles numericalness correctly 37$foo = $bar = $baz = 0; 38vec($foo = 0,0,1) = 1; 39vec($bar = 0,1,1) = 1; 40$baz = $foo | $bar; 41ok($foo eq "1" && $foo == 1); 42ok($bar eq "2" && $bar == 2); 43ok("$foo $bar $baz" eq "1 2 3"); 44 45# error cases 46 47$x = eval { vec $foo, 0, 3 }; 48like($@, qr/^Illegal number of bits in vec/); 49$@ = undef; 50$x = eval { vec $foo, 0, 0 }; 51like($@, qr/^Illegal number of bits in vec/); 52$@ = undef; 53$x = eval { vec $foo, 0, -13 }; 54like($@, qr/^Illegal number of bits in vec/); 55$@ = undef; 56$x = eval { vec($foo, -1, 4) = 2 }; 57like($@, qr/^Negative offset to vec in lvalue context/); 58$@ = undef; 59ok(! vec('abcd', 7, 8)); 60 61# UTF8 62# N.B. currently curiously coded to circumvent bugs elswhere in UTF8 handling 63 64$foo = "\x{100}" . "\xff\xfe"; 65$x = substr $foo, 1; 66is(vec($x, 0, 8), 255); 67$@ = undef; 68{ 69 local $@; 70 eval { vec($foo, 1, 8) }; 71 like($@, qr/$exception_134139/, 72 "Caught exception: code point over 0xFF used as argument to vec"); 73 $@ = undef; 74 eval { vec($foo, 1, 8) = 13 }; 75 like($@, qr/$exception_134139/, 76 "Caught exception: code point over 0xFF used as argument to vec"); 77} 78$foo = "\x{100}" . "\xff\xfe"; 79$x = substr $foo, 1; 80vec($x, 2, 4) = 7; 81is($x, "\xff\xf7"); 82 83# mixed magic 84 85$foo = "\x61\x62\x63\x64\x65\x66"; 86is(vec(substr($foo, 2, 2), 0, 16), 25444); 87vec(substr($foo, 1,3), 5, 4) = 3; 88is($foo, "\x61\x62\x63\x34\x65\x66"); 89 90# A variation of [perl #20933] 91{ 92 my $s = ""; 93 vec($s, 0, 1) = 0; 94 vec($s, 1, 1) = 1; 95 my @r; 96 $r[$_] = \ vec $s, $_, 1 for (0, 1); 97 ok(!(${ $r[0] } != 0 || ${ $r[1] } != 1)); 98} 99 100 101my $destroyed; 102{ package Class; DESTROY { ++$destroyed; } } 103 104$destroyed = 0; 105{ 106 my $x = ''; 107 vec($x,0,1) = 0; 108 $x = bless({}, 'Class'); 109} 110is($destroyed, 1, 'Timely scalar destruction with lvalue vec'); 111 112use constant roref => \1; 113eval { for (roref) { vec($_,0,1) = 1 } }; 114like($@, qr/^Modification of a read-only value attempted at /, 115 'err msg when modifying read-only refs'); 116 117 118{ 119 # downgradeable utf8 strings should be downgraded before accessing 120 # the byte string. 121 # See the p5p thread with Message-ID: 122 # <CAMx+QJ6SAv05nmpnc7bmp0Wo+sjcx=ssxCcE-P_PZ8HDuCQd9A@mail.gmail.com> 123 124 125 my $x = substr "\x{100}\xff\xfe", 1; # a utf8 string with all ords < 256 126 my $v; 127 $v = vec($x, 0, 8); 128 is($v, 255, "downgraded utf8 try 1"); 129 $v = vec($x, 0, 8); 130 is($v, 255, "downgraded utf8 try 2"); 131} 132 133# [perl #128260] assertion failure with \vec %h, \vec @h 134{ 135 my %h = 1..100; 136 my @a = 1..100; 137 is ${\vec %h, 0, 1}, vec(scalar %h, 0, 1), '\vec %h'; 138 is ${\vec @a, 0, 1}, vec(scalar @a, 0, 1), '\vec @a'; 139} 140 141 142# [perl #130915] heap-buffer-overflow in Perl_do_vecget 143 144{ 145 # ensure that out-of-STRLEN-range offsets are handled correctly. This 146 # partially duplicates some tests above, but those cases are repeated 147 # here for completeness. 148 # 149 # Note that all the 'Out of memory!' errors trapped eval {} are 'fake' 150 # croaks generated by pp_vec() etc when they have detected something 151 # that would have otherwise overflowed. The real 'Out of memory!' 152 # error thrown by safesysrealloc() etc is not trappable. If it were 153 # accidentally triggered in this test script, the script would exit at 154 # that point. 155 156 157 my $s = "abcdefghijklmnopqrstuvwxyz"; 158 my $x; 159 160 # offset is SvIOK_UV 161 162 $x = vec($s, ~0, 8); 163 is($x, 0, "RT 130915: UV_MAX rval"); 164 eval { vec($s, ~0, 8) = 1 }; 165 like($@, qr/^Out of memory!/, "RT 130915: UV_MAX lval"); 166 167 # offset is negative 168 169 $x = vec($s, -1, 8); 170 is($x, 0, "RT 130915: -1 rval"); 171 eval { vec($s, -1, 8) = 1 }; 172 like($@, qr/^Negative offset to vec in lvalue context/, 173 "RT 130915: -1 lval"); 174 175 # offset positive but doesn't fit in a STRLEN 176 177 SKIP: { 178 skip 'IV is no longer than size_t', 2 179 if $Config{ivsize} <= $Config{sizesize}; 180 181 my $size_max = (1 << (8 *$Config{sizesize})) - 1; 182 my $sm2 = $size_max * 2; 183 184 $x = vec($s, $sm2, 8); 185 is($x, 0, "RT 130915: size_max*2 rval"); 186 eval { vec($s, $sm2, 8) = 1 }; 187 like($@, qr/^Out of memory!/, "RT 130915: size_max*2 lval"); 188 } 189 190 # (offset * num-bytes) could overflow 191 192 for my $power (1..3) { 193 my $bytes = (1 << $power); 194 my $biglog2 = $Config{sizesize} * 8 - $power; 195 for my $i (0..1) { 196 my $offset = (1 << $biglog2) - $i; 197 $x = vec($s, $offset, $bytes*8); 198 is($x, 0, "large offset: bytes=$bytes biglog2=$biglog2 i=$i: rval"); 199 eval { vec($s, $offset, $bytes*8) = 1; }; 200 like($@, qr/^Out of memory!/, 201 "large offset: bytes=$bytes biglog2=$biglog2 i=$i: rval"); 202 } 203 } 204} 205 206# Test multi-byte gets partially beyond the end of the string. 207# It's supposed to pretend there is a stream of \0's following the string. 208 209{ 210 my $s = "\x01\x02\x03\x04\x05\x06\x07"; 211 my $s0 = $s . ("\0" x 8); 212 213 for my $bytes (1, 2, 4, 8) { 214 for my $offset (0..$bytes) { 215 if ($Config{ivsize} < $bytes) { 216 pass("skipping multi-byte bytes=$bytes offset=$offset"); 217 next; 218 } 219 no warnings 'portable'; 220 is (vec($s, 8 - $offset, $bytes*8), 221 vec($s0, 8 - $offset, $bytes*8), 222 "multi-byte bytes=$bytes offset=$offset"); 223 } 224 } 225} 226 227# RT #131083 maybe-lvalue out of range should only croak if assigned to 228 229{ 230 sub RT131083 { if ($_[0]) { $_[1] = 1; } $_[1]; } 231 my $s = "abc"; 232 my $off = -1; 233 my $v = RT131083(0, vec($s, $off, 8)); 234 is($v, 0, "RT131083 rval -1"); 235 $v = eval { RT131083(1, vec($s, $off, 8)); }; 236 like($@, qr/Negative offset to vec in lvalue context/, "RT131083 lval -1"); 237 238 $off = ~0; 239 my $v = RT131083(0, vec($s, $off, 8)); 240 is($v, 0, "RT131083 rval ~0"); 241 $v = eval { RT131083(1, vec($s, $off, 8)); }; 242 like($@, qr/Out of memory!/, "RT131083 lval ~0"); 243} 244 245{ 246 # Adapting test formerly in t/lib/warnings/doop 247 248 local $@; 249 my $foo = "\x{100}" . "\xff\xfe"; 250 eval { vec($foo, 1, 8) }; 251 like($@, qr/$exception_134139/, 252 "RT 134139: Use of strings with code points over 0xFF as arguments to 'vec' is now forbidden"); 253} 254