xref: /openbsd/gnu/usr.bin/perl/t/op/bop.t (revision 56d68f1e)
1#!./perl
2
3#
4# test the bit operators '&', '|', '^', '~', '<<', and '>>'
5#
6
7use warnings;
8
9BEGIN {
10    chdir 't' if -d 't';
11    require "./test.pl";
12    set_up_inc('../lib');
13    require "./charset_tools.pl";
14    require Config;
15}
16
17# Tests don't have names yet.
18# If you find tests are failing, please try adding names to tests to track
19# down where the failure is, and supply your new names as a patch.
20# (Just-in-time test naming)
21plan tests => 502;
22
23# numerics
24ok ((0xdead & 0xbeef) == 0x9ead);
25ok ((0xdead | 0xbeef) == 0xfeef);
26ok ((0xdead ^ 0xbeef) == 0x6042);
27ok ((~0xdead & 0xbeef) == 0x2042);
28
29# shifts
30ok ((257 << 7) == 32896);
31ok ((33023 >> 7) == 257);
32
33# signed vs. unsigned
34ok ((~0 > 0 && do { use integer; ~0 } == -1));
35
36my $bits = 0;
37for (my $i = ~0; $i; $i >>= 1) { ++$bits; }
38my $cusp = 1 << ($bits - 1);
39
40
41ok (($cusp & -1) > 0 && do { use integer; $cusp & -1 } < 0);
42ok (($cusp | 1) > 0 && do { use integer; $cusp | 1 } < 0);
43ok (($cusp ^ 1) > 0 && do { use integer; $cusp ^ 1 } < 0);
44ok ((1 << ($bits - 1)) == $cusp &&
45    do { use integer; 1 << ($bits - 1) } == -$cusp);
46ok (($cusp >> 1) == ($cusp / 2) &&
47    do { use integer; abs($cusp >> 1) } == ($cusp / 2));
48
49$Aaz = chr(ord("A") & ord("z"));
50$Aoz = chr(ord("A") | ord("z"));
51$Axz = chr(ord("A") ^ ord("z"));
52
53# short strings
54is (("AAAAA" & "zzzzz"), ($Aaz x 5));
55is (("AAAAA" | "zzzzz"), ($Aoz x 5));
56is (("AAAAA" ^ "zzzzz"), ($Axz x 5));
57
58# long strings
59$foo = "A" x 150;
60$bar = "z" x 75;
61$zap = "A" x 75;
62# & truncates
63is (($foo & $bar), ($Aaz x 75 ));
64# | does not truncate
65is (($foo | $bar), ($Aoz x 75 . $zap));
66# ^ does not truncate
67is (($foo ^ $bar), ($Axz x 75 . $zap));
68
69# string constants.  These tests expect the bit patterns of these strings in
70# ASCII, so convert to that.
71sub _and($) { $_[0] & native_to_uni("+0") }
72sub _oar($) { $_[0] | native_to_uni("+0") }
73sub _xor($) { $_[0] ^ native_to_uni("+0") }
74is _and native_to_uni("waf"), native_to_uni('# '),  'str var & const str'; # [perl #20661]
75is _and native_to_uni("waf"), native_to_uni('# '),  'str var & const str again'; # [perl #20661]
76is _oar native_to_uni("yit"), native_to_uni('{yt'), 'str var | const str';
77is _oar native_to_uni("yit"), native_to_uni('{yt'), 'str var | const str again';
78is _xor native_to_uni("yit"), native_to_uni('RYt'), 'str var ^ const str';
79is _xor native_to_uni("yit"), native_to_uni('RYt'), 'str var ^ const str again';
80
81SKIP: {
82    skip "Converting a numeric doesn't work with EBCDIC unlike the above tests",
83         3 if $::IS_EBCDIC;
84    is _and  0, '0',   'num var & const str';     # [perl #20661]
85    is _oar  0, '0',   'num var | const str';
86    is _xor  0, '0',   'num var ^ const str';
87}
88
89# But don’t mistake a COW for a constant when assigning to it
90%h=(150=>1);
91$i=(keys %h)[0];
92$i |= 105;
93is $i, 255, '[perl #108480] $cow |= number';
94$i=(keys %h)[0];
95$i &= 105;
96is $i, 0, '[perl #108480] $cow &= number';
97$i=(keys %h)[0];
98$i ^= 105;
99is $i, 255, '[perl #108480] $cow ^= number';
100
101#
102is ("ok \xFF\xFF\n" & "ok 19\n", "ok 19\n");
103is ("ok 20\n" | "ok \0\0\n", "ok 20\n");
104is ("o\000 \0001\000" ^ "\000k\0002\000\n", "ok 21\n");
105
106#
107is ("ok \x{FF}\x{FF}\n" & "ok 22\n", "ok 22\n");
108is ("ok 23\n" | "ok \x{0}\x{0}\n", "ok 23\n");
109is ("o\x{0} \x{0}4\x{0}" ^ "\x{0}k\x{0}2\x{0}\n", "ok 24\n");
110
111# More variations on 19 and 22.
112is ("ok \xFF\x{FF}\n" & "ok 41\n", "ok 41\n");
113is ("ok \x{FF}\xFF\n" & "ok 42\n", "ok 42\n");
114
115# Tests to see if you really can do casts negative floats to unsigned properly
116$neg1 = -1.0;
117ok (~ $neg1 == 0);
118$neg7 = -7.0;
119ok (~ $neg7 == 6);
120
121
122# double magic tests
123
124sub TIESCALAR { bless { value => $_[1], orig => $_[1] } }
125sub STORE { $_[0]{store}++; $_[0]{value} = $_[1] }
126sub FETCH { $_[0]{fetch}++; $_[0]{value} }
127sub stores { tied($_[0])->{value} = tied($_[0])->{orig};
128             delete(tied($_[0])->{store}) || 0 }
129sub fetches { delete(tied($_[0])->{fetch}) || 0 }
130
131# numeric double magic tests
132
133tie $x, "main", 1;
134tie $y, "main", 3;
135
136is(($x | $y), 3);
137is(fetches($x), 1);
138is(fetches($y), 1);
139is(stores($x), 0);
140is(stores($y), 0);
141
142is(($x & $y), 1);
143is(fetches($x), 1);
144is(fetches($y), 1);
145is(stores($x), 0);
146is(stores($y), 0);
147
148is(($x ^ $y), 2);
149is(fetches($x), 1);
150is(fetches($y), 1);
151is(stores($x), 0);
152is(stores($y), 0);
153
154is(($x |= $y), 3);
155is(fetches($x), 2);
156is(fetches($y), 1);
157is(stores($x), 1);
158is(stores($y), 0);
159
160is(($x &= $y), 1);
161is(fetches($x), 2);
162is(fetches($y), 1);
163is(stores($x), 1);
164is(stores($y), 0);
165
166is(($x ^= $y), 2);
167is(fetches($x), 2);
168is(fetches($y), 1);
169is(stores($x), 1);
170is(stores($y), 0);
171
172is(~~$y, 3);
173is(fetches($y), 1);
174is(stores($y), 0);
175
176{ use integer;
177
178is(($x | $y), 3);
179is(fetches($x), 1);
180is(fetches($y), 1);
181is(stores($x), 0);
182is(stores($y), 0);
183
184is(($x & $y), 1);
185is(fetches($x), 1);
186is(fetches($y), 1);
187is(stores($x), 0);
188is(stores($y), 0);
189
190is(($x ^ $y), 2);
191is(fetches($x), 1);
192is(fetches($y), 1);
193is(stores($x), 0);
194is(stores($y), 0);
195
196is(($x |= $y), 3);
197is(fetches($x), 2);
198is(fetches($y), 1);
199is(stores($x), 1);
200is(stores($y), 0);
201
202is(($x &= $y), 1);
203is(fetches($x), 2);
204is(fetches($y), 1);
205is(stores($x), 1);
206is(stores($y), 0);
207
208is(($x ^= $y), 2);
209is(fetches($x), 2);
210is(fetches($y), 1);
211is(stores($x), 1);
212is(stores($y), 0);
213
214is(~$y, -4);
215is(fetches($y), 1);
216is(stores($y), 0);
217
218} # end of use integer;
219
220# stringwise double magic tests
221
222tie $x, "main", "a";
223tie $y, "main", "c";
224
225is(($x | $y), ("a" | "c"));
226is(fetches($x), 1);
227is(fetches($y), 1);
228is(stores($x), 0);
229is(stores($y), 0);
230
231is(($x & $y), ("a" & "c"));
232is(fetches($x), 1);
233is(fetches($y), 1);
234is(stores($x), 0);
235is(stores($y), 0);
236
237is(($x ^ $y), ("a" ^ "c"));
238is(fetches($x), 1);
239is(fetches($y), 1);
240is(stores($x), 0);
241is(stores($y), 0);
242
243is(($x |= $y), ("a" | "c"));
244is(fetches($x), 2);
245is(fetches($y), 1);
246is(stores($x), 1);
247is(stores($y), 0);
248
249is(($x &= $y), ("a" & "c"));
250is(fetches($x), 2);
251is(fetches($y), 1);
252is(stores($x), 1);
253is(stores($y), 0);
254
255is(($x ^= $y), ("a" ^ "c"));
256is(fetches($x), 2);
257is(fetches($y), 1);
258is(stores($x), 1);
259is(stores($y), 0);
260
261is(~~$y, "c");
262is(fetches($y), 1);
263is(stores($y), 0);
264
265my $g;
266# Note: if the vec() reads are part of the is() calls it's treated as
267# in lvalue context, so we save it separately
268$g = vec($x, 0, 1);
269is($g, (ord("a") & 0x01), "check vec value");
270is(fetches($x), 1, "fetches for vec read");
271is(stores($x), 0, "stores for vec read");
272# similarly here, and code like:
273#   $g = (vec($x, 0, 1) = 0)
274# results in an extra fetch, since the inner assignment returns the LV
275vec($x, 0, 1) = 0;
276# one fetch in vec() another when the LV is assigned to
277is(fetches($x), 2, "fetches for vec write");
278is(stores($x), 1, "stores for vec write");
279
280{
281    my $a = "a";
282    utf8::upgrade($a);
283    tie $x, "main", $a;
284    $g = vec($x, 0, 1);
285    is($g, (ord("a") & 0x01), "check vec value (utf8)");
286    is(fetches($x), 1, "fetches for vec read (utf8)");
287    is(stores($x), 0, "stores for vec read (utf8)");
288    vec($x, 0, 1) = 0;
289    # one fetch in vec() another when the LV is assigned to
290    is(fetches($x), 2, "fetches for vec write (utf8)");
291    is(stores($x), 1, "stores for vec write (utf8)");
292}
293
294$a = "\0\x{100}"; chop($a);
295ok(utf8::is_utf8($a)); # make sure UTF8 flag is still there
296$a = ~$a;
297is($a, "\xFF", "~ works with utf-8");
298ok(! utf8::is_utf8($a), "    and turns off the UTF-8 flag");
299
300$a = "\0\x{100}"; chop($a);
301undef $b;
302$b = $a | "\xFF";
303ok(utf8::is_utf8($b), "Verify UTF-8 | non-UTF-8 retains UTF-8 flag");
304undef $b;
305$b = "\xFF" | $a;
306ok(utf8::is_utf8($b), "Verify non-UTF-8 | UTF-8 retains UTF-8 flag");
307undef $b;
308$b = $a & "\xFF";
309ok(utf8::is_utf8($b), "Verify UTF-8 & non-UTF-8 retains UTF-8 flag");
310undef $b;
311$b = "\xFF" & $a;
312ok(utf8::is_utf8($b), "Verify non-UTF-8 & UTF-8 retains UTF-8 flag");
313undef $b;
314$b = $a ^ "\xFF";
315ok(utf8::is_utf8($b), "Verify UTF-8 ^ non-UTF-8 retains UTF-8 flag");
316undef $b;
317$b = "\xFF" ^ $a;
318ok(utf8::is_utf8($b), "Verify non-UTF-8 ^ UTF-8 retains UTF-8 flag");
319
320
321# [rt.perl.org 33003]
322# This would cause a segfault without malloc wrap
323SKIP: {
324  skip "No malloc wrap checks" unless $Config::Config{usemallocwrap};
325  like( runperl(prog => 'eval q($#a>>=1); print 1'), qr/^1\n?/ );
326}
327
328# [perl #37616] Bug in &= (string) and/or m//
329{
330    $a = "aa";
331    $a &= "a";
332    ok($a =~ /a+$/, 'ASCII "a" is NUL-terminated');
333
334    $b = "bb\x{FF}";
335    utf8::upgrade($b);
336    $b &= "b";
337    ok($b =~ /b+$/, 'Unicode "b" is NUL-terminated');
338}
339
340# New string- and number-specific bitwise ops
341{
342  use feature "bitwise";
343  no warnings "experimental::bitwise";
344  is "22" & "66", 2,    'numeric & with strings';
345  is "22" | "66", 86,   'numeric | with strings';
346  is "22" ^ "66", 84,   'numeric ^ with strings';
347  is ~"22" & 0xff, 233, 'numeric ~ with string';
348  is 22 &. 66, 22,     '&. with numbers';
349  is 22 |. 66, 66,     '|. with numbers';
350  is 22 ^. 66, "\4\4", '^. with numbers';
351  if ($::IS_EBCDIC) {
352    # ord('2') is 0xF2 on EBCDIC
353    is ~.22, "\x0d\x0d", '~. with number';
354  }
355  else {
356    # ord('2') is 0x32 on ASCII
357    is ~.22, "\xcd\xcd", '~. with number';
358  }
359  $_ = "22";
360  is $_ &= "66", 2,  'numeric &= with strings';
361  $_ = "22";
362  is $_ |= "66", 86, 'numeric |= with strings';
363  $_ = "22";
364  is $_ ^= "66", 84, 'numeric ^= with strings';
365  $_ = 22;
366  is $_ &.= 66, 22,     '&.= with numbers';
367  $_ = 22;
368  is $_ |.= 66, 66,     '|.= with numbers';
369  $_ = 22;
370  is $_ ^.= 66, "\4\4", '^.= with numbers';
371
372 # signed vs. unsigned
373 ok ((~0 > 0 && do { use integer; ~0 } == -1));
374
375 my $bits = 0;
376 for (my $i = ~0; $i; $i >>= 1) { ++$bits; }
377 my $cusp = 1 << ($bits - 1);
378
379 ok (($cusp & -1) > 0 && do { use integer; $cusp & -1 } < 0);
380 ok (($cusp | 1) > 0 && do { use integer; $cusp | 1 } < 0);
381 ok (($cusp ^ 1) > 0 && do { use integer; $cusp ^ 1 } < 0);
382 ok ((1 << ($bits - 1)) == $cusp &&
383     do { use integer; 1 << ($bits - 1) } == -$cusp);
384 ok (($cusp >> 1) == ($cusp / 2) &&
385    do { use integer; abs($cusp >> 1) } == ($cusp / 2));
386}
387# Repeat some of those, with 'use v5.27'
388{
389  use v5.27;
390
391  is "22" & "66", 2,    'numeric & with strings';
392  is "22" | "66", 86,   'numeric | with strings';
393  is "22" ^ "66", 84,   'numeric ^ with strings';
394  is ~"22" & 0xff, 233, 'numeric ~ with string';
395  is 22 &. 66, 22,     '&. with numbers';
396  is 22 |. 66, 66,     '|. with numbers';
397  is 22 ^. 66, "\4\4", '^. with numbers';
398  if ($::IS_EBCDIC) {
399    # ord('2') is 0xF2 on EBCDIC
400    is ~.22, "\x0d\x0d", '~. with number';
401  }
402  else {
403    # ord('2') is 0x32 on ASCII
404    is ~.22, "\xcd\xcd", '~. with number';
405  }
406  $_ = "22";
407  is $_ &= "66", 2,  'numeric &= with strings';
408  $_ = "22";
409  is $_ |= "66", 86, 'numeric |= with strings';
410  $_ = "22";
411  is $_ ^= "66", 84, 'numeric ^= with strings';
412  $_ = 22;
413  is $_ &.= 66, 22,     '&.= with numbers';
414  $_ = 22;
415  is $_ |.= 66, 66,     '|.= with numbers';
416  $_ = 22;
417  is $_ ^.= 66, "\4\4", '^.= with numbers';
418}
419
420# ref tests
421
422my %res;
423
424for my $str ("x", "\x{B6}") {
425    utf8::upgrade($str) if $str !~ /x/;
426    for my $chr (qw/S A H G X ( * F/) {
427        for my $op (qw/| & ^/) {
428            my $co = ord $chr;
429            my $so = ord $str;
430            $res{"$chr$op$str"} = eval qq/chr($co $op $so)/;
431        }
432    }
433    $res{"undef|$str"} = $str;
434    $res{"undef&$str"} = "";
435    $res{"undef^$str"} = $str;
436}
437
438sub PVBM () { "X" }
4391 if index "foo", PVBM;
440
441my $warn = 0;
442local $^W = 1;
443local $SIG{__WARN__} = sub { $warn++ };
444
445sub is_first {
446    my ($got, $orig, $op, $str, $name) = @_;
447    is(substr($got, 0, 1), $res{"$orig$op$str"}, $name);
448}
449
450for (
451    # [object to test, first char of stringification, name]
452    [undef,             "undef",    "undef"         ],
453    [\1,                "S",        "scalar ref"    ],
454    [[],                "A",        "array ref"     ],
455    [{},                "H",        "hash ref"      ],
456    [qr/x/,             "(",        "qr//"          ],
457    [*foo,              "*",        "glob"          ],
458    [\*foo,             "G",        "glob ref"      ],
459    [PVBM,              "X",        "PVBM"          ],
460    [\PVBM,             "S",        "PVBM ref"      ],
461    [bless([], "Foo"),  "F",        "object"        ],
462) {
463    my ($val, $orig, $type) = @$_;
464
465    for (["x", "string"], ["\x{B6}", "utf8"]) {
466        my ($str, $desc) = @$_;
467        utf8::upgrade($str) if $desc =~ /utf8/;
468
469        $warn = 0;
470
471        is_first($val | $str, $orig, "|", $str, "$type | $desc");
472        is_first($val & $str, $orig, "&", $str, "$type & $desc");
473        is_first($val ^ $str, $orig, "^", $str, "$type ^ $desc");
474
475        is_first($str | $val, $orig, "|", $str, "$desc | $type");
476        is_first($str & $val, $orig, "&", $str, "$desc & $type");
477        is_first($str ^ $val, $orig, "^", $str, "$desc ^ $type");
478
479        my $new;
480        ($new = $val) |= $str;
481        is_first($new, $orig, "|", $str, "$type |= $desc");
482        ($new = $val) &= $str;
483        is_first($new, $orig, "&", $str, "$type &= $desc");
484        ($new = $val) ^= $str;
485        is_first($new, $orig, "^", $str, "$type ^= $desc");
486
487        ($new = $str) |= $val;
488        is_first($new, $orig, "|", $str, "$desc |= $type");
489        ($new = $str) &= $val;
490        is_first($new, $orig, "&", $str, "$desc &= $type");
491        ($new = $str) ^= $val;
492        is_first($new, $orig, "^", $str, "$desc ^= $type");
493
494        if ($orig eq "undef") {
495            # undef |= and undef ^= don't warn
496            is($warn, 10, "no duplicate warnings");
497        }
498        else {
499            is($warn, 0, "no warnings");
500        }
501    }
502}
503
504delete $SIG{__WARN__};
505
506my $strval;
507
508{
509    package Bar;
510    use overload q/""/ => sub { $strval };
511
512    package Baz;
513    use overload q/|/ => sub { "y" };
514}
515
516ok(!eval { 1 if bless([], "Bar") | "x"; 1 },"string overload can't use |");
517like($@, qr/no method found/,               "correct error");
518is(eval { bless([], "Baz") | "x" }, "y",    "| overload works");
519
520my $obj = bless [], "Bar";
521$strval = "x";
522eval { $obj |= "Q" };
523$strval = "z";
524is("$obj", "z", "|= doesn't break string overload");
525
526# [perl #29070]
527$^A .= new version ~$_ for eval sprintf('"\\x%02x"', 0xff - ord("1")),
528                           $::IS_EBCDIC ? v13 : v205, # 255 - ord('2')
529                           eval sprintf('"\\x%02x"', 0xff - ord("3"));
530is $^A, "123", '~v0 clears vstring magic on retval';
531
532{
533    my $w = $Config::Config{ivsize} * 8;
534
535    fail("unexpected w $w") unless $w == 32 || $w == 64;
536
537    is(1 << 1, 2, "UV 1 left shift 1");
538    is(1 >> 1, 0, "UV 1 right shift 1");
539
540    is(0x7b << -4, 0x007, "UV left negative shift == right shift");
541    is(0x7b >> -4, 0x7b0, "UV right negative shift == left shift");
542
543    is(0x7b <<  0, 0x07b, "UV left  zero shift == identity");
544    is(0x7b >>  0, 0x07b, "UV right zero shift == identity");
545
546    is(0x0 << -1, 0x0, "zero left  negative shift == zero");
547    is(0x0 >> -1, 0x0, "zero right negative shift == zero");
548
549    cmp_ok(1 << $w - 1, '==', 2 ** ($w - 1), # not is() because NV stringify.
550       "UV left $w - 1 shift == 2 ** ($w - 1)");
551    is(1 << $w,     0, "UV left shift $w     == zero");
552    is(1 << $w + 1, 0, "UV left shift $w + 1 == zero");
553
554    is(1 >> $w - 1, 0, "UV right shift $w - 1 == zero");
555    is(1 >> $w,     0, "UV right shift $w     == zero");
556    is(1 >> $w + 1, 0, "UV right shift $w + 1 == zero");
557
558    # Negative shiftees get promoted to UVs before shifting.  This is
559    # not necessarily the ideal behavior, but that is what is happening.
560    if ($w == 64) {
561        no warnings "portable";
562        no warnings "overflow"; # prevent compile-time warning for ivsize=4
563        is(-1 << 1, 0xFFFF_FFFF_FFFF_FFFE,
564           "neg UV (sic) left shift  = 0xFF..E");
565        is(-1 >> 1, 0x7FFF_FFFF_FFFF_FFFF,
566           "neg UV (sic) right shift = 0x7F..F");
567    } elsif ($w == 32) {
568        no warnings "portable";
569        is(-1 << 1, 0xFFFF_FFFE, "neg left shift  == 0xFF..E");
570        is(-1 >> 1, 0x7FFF_FFFF, "neg right shift == 0x7F..F");
571    }
572
573    {
574        # 'use integer' means use IVs instead of UVs.
575        use integer;
576
577        # No surprises here.
578        is(1 << 1, 2, "IV 1 left shift 1  == 2");
579        is(1 >> 1, 0, "IV 1 right shift 1 == 0");
580
581        # The left overshift should behave like without 'use integer',
582        # that is, return zero.
583        is(1 << $w,     0, "IV 1 left shift $w     == 0");
584        is(1 << $w + 1, 0, "IV 1 left shift $w + 1 == 0");
585        is(-1 << $w,     0, "IV -1 left shift $w     == 0");
586        is(-1 << $w + 1, 0, "IV -1 left shift $w + 1 == 0");
587
588        # Even for negative IVs, left shift is multiplication.
589        # But right shift should display the stuckiness to -1.
590        is(-1 <<      1, -2, "IV -1 left shift       1 == -2");
591        is(-1 >>      1, -1, "IV -1 right shift      1 == -1");
592
593        # As for UVs, negative shifting means the reverse shift.
594        is(-1 <<     -1, -1, "IV -1 left shift      -1 == -1");
595        is(-1 >>     -1, -2, "IV -1 right shift     -1 == -2");
596
597        # Test also at and around wordsize, expect stuckiness to -1.
598        is(-1 >> $w - 1, -1, "IV -1 right shift $w - 1 == -1");
599        is(-1 >> $w,     -1, "IV -1 right shift $w     == -1");
600        is(-1 >> $w + 1, -1, "IV -1 right shift $w + 1 == -1");
601    }
602}
603
604# [perl #129287] UTF8 & was not providing a trailing null byte.
605# This test is a bit convoluted, as we want to make sure that the string
606# allocated for &’s target contains memory initialised to something other
607# than a null byte.  Uninitialised memory does not make for a reliable
608# test.  So we do &. on a longer non-utf8 string first.
609for (["aaa","aaa"],[substr ("a\x{100}",0,1), "a"]) {
610    use feature "bitwise";
611    no warnings "experimental::bitwise", "pack";
612    $byte = substr unpack("P2", pack "P", $$_[0] &. $$_[1]), -1;
613}
614is $byte, "\0", "utf8 &. appends null byte";
615
616# only visible under sanitize
617fresh_perl_is('$x = "UUUUUUUV"; $y = "xxxxxxx"; $x |= $y; print $x',
618              ( $::IS_EBCDIC) ? 'XXXXXXXV' : '}}}}}}}V',
619              {}, "[perl #129995] access to freed memory");
620
621
622#
623# Using code points above 0xFF is fatal
624#
625foreach my $op_info ([and => "&"], [or => "|"], [xor => "^"]) {
626    my ($op_name, $op) = @$op_info;
627    local $@;
628    eval '$_ = "\xFF" ' . $op . ' "\x{100}";';
629    like $@, qr /^Use of strings with code points over 0xFF as arguments (?#
630                 )to bitwise $op_name \Q($op)\E operator is not allowed/,
631         "Use of code points above 0xFF as arguments to bitwise " .
632         "$op_name ($op) is not allowed";
633}
634
635{
636    local $@;
637    eval '$_ = ~ "\x{100}";';
638    like $@, qr /^Use of strings with code points over 0xFF as arguments (?#
639                 )to 1's complement \(~\) operator is not allowed/,
640         "Use of code points above 0xFF as argument to 1's complement " .
641         "(~) is not allowed";
642}
643
644{
645    # RT 134140 fatalizations
646    my %op_pairs = (
647        and => { low => 'and', high => '&', regex => qr/&/  },
648        or  => { low => 'or',  high => '|', regex => qr/\|/ },
649        xor => { low => 'xor', high => '^', regex => qr/\^/ },
650    );
651    my @combos = (
652        { string  => '"abc" & "abc\x{100}"',  op_pair => $op_pairs{and} },
653        { string  => '"abc" | "abc\x{100}"',  op_pair => $op_pairs{or}  },
654        { string  => '"abc" ^ "abc\x{100}"',  op_pair => $op_pairs{xor} },
655        { string  => '"abc\x{100}" & "abc"',  op_pair => $op_pairs{and} },
656        { string  => '"abc\x{100}" | "abc"',  op_pair => $op_pairs{or}  },
657        { string  => '"abc\x{100}" ^ "abc"',  op_pair => $op_pairs{xor} },
658
659    );
660
661    # Use of strings with code points over 0xFF as arguments to %s operator is not allowed
662    for my $h (@combos) {
663        my $s1 = "Use of strings with code points over 0xFF as arguments to bitwise";
664        my $s2 = "operator is not allowed";
665        my $expected  = qr/$s1 $h->{op_pair}->{low} \($h->{op_pair}->{regex}\) $s2/;
666        my $description = "$s1 $h->{op_pair}->{low} ($h->{op_pair}->{high}) operator is not allowed";
667        local $@;
668        eval $h->{string};
669        like $@, $expected, $description;
670    }
671}
672
673{
674    # perl #17844 - only visible with valgrind/ASAN
675    fresh_perl_is(<<'EOS',
676formline X000n^\\0,\\0^\\0for\0,0..10
677EOS
678                  '',
679                  {}, "[perl #17844] access beyond end of block");
680}
681