xref: /openbsd-src/gnu/usr.bin/perl/t/bigmem/stack.t (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
1#!perl
2BEGIN {
3    chdir 't' if -d 't';
4    @INC = "../lib";
5    require './test.pl';
6}
7
8use strict;
9use Config qw(%Config);
10use XS::APItest;
11
12# memory usage checked with top
13$ENV{PERL_TEST_MEMORY} >= 60
14    or skip_all("Need ~60GB for this test");
15$Config{ptrsize} >= 8
16    or skip_all("Need 64-bit pointers for this test");
17XS::APItest::wide_marks()
18    or skip_all("Not configured for SSize_t marks");
19
20my @x;
21$x[0x8000_0000] = "Hello";
22
23my $arg_count;
24
25my @tests =
26  (
27      [ mark => sub
28        {
29            # unlike the grep example this avoids the mark manipulation done by grep
30            # so it's more of a pure mark type test
31            # it also fails/succeeds a lot faster
32            my $count = () =  (x(), z());
33            is($count, 0x8000_0002, "got expected (large) list size");
34        },
35      ],
36      [ xssize => sub
37        {
38            # check XS gets the right numbers in our predefined variables
39            # returned ~ -2G before fix
40            my $count = XS::APItest::xs_items(x(), z());
41            is($count, 0x8000_0002, "got expected XS list size");
42        }
43      ],
44      [ listsub => sub
45        {
46            my $last = ( x() )[-1];
47            is($last, "Hello", "list subscripting");
48
49            my ($first, $last2, $last1) = ( "first", x(), "Goodbye" )[0, -2, -1];
50            is($first, "first", "list subscripting in list context (0)");
51            is($last2, "Hello", "list subscripting in list context (-2)");
52            is($last1, "Goodbye", "list subscripting in list context (-1)");
53        }
54      ],
55      [ iterctx => sub
56        {
57            # the iter context had an I32 stack offset
58            my $last = ( x(), iter() )[-1];
59            is($last, "abc", "check iteration not confused");
60        }
61      ],
62      [ split => sub
63        {
64            # split had an I32 base offset
65            # this paniced with "Split loop"
66            my $count = () = ( x(), do_split("ABC") );
67            is($count, 0x8000_0004, "split base index");
68            # it would be nice to test split returning >2G (or >4G) items, but
69            # I don't have the memory needed
70        }
71      ],
72      [ xsload => sub
73        {
74            # I expect this to crash if buggy
75            my $count = () = (x(), loader());
76            is($count, 0x8000_0001, "check loading XS with large stack");
77        }
78      ],
79      [ pp_list => sub
80        {
81            my $l = ( x(), list2() )[-1];
82            is($l, 2, "pp_list mark handling");
83        }
84       ],
85      [
86          chomp_av => sub {
87              # not really stack related, but is 32-bit related
88              local $x[-1] = "Hello\n";
89              chomp(@x);
90              is($x[-1], "Hello", "chomp on a large array");
91          }
92         ],
93      [
94          grepwhile => sub {
95            SKIP: {
96                  skip "This test is even slower - define PERL_RUN_SLOW_TESTS to run me", 1
97                    unless $ENV{PERL_RUN_SLOW_TESTS};
98                  # grep ..., @x used too much memory
99                  my $count = grep 1, ( (undef) x 0x7FFF_FFFF, 1, 1 );
100                  is($count, 0x8000_0001, "grepwhile item count");
101              }
102          }
103      ],
104      [
105          repeat => sub {
106            SKIP:
107              {
108                  $ENV{PERL_TEST_MEMORY} >= 70
109                       or skip "repeat test needs 70GB", 2;
110                  # pp_repeat would throw an unable to allocate error
111                  my ($lastm1, $middle) = ( ( x() ) x 2 )[-1, @x-1];
112                  is($lastm1, "Hello", "repeat lastm1");
113                  is($middle, "Hello", "repeat middle");
114              }
115          },
116      ],
117      [
118          tiescalar => sub {
119            SKIP:
120              {
121                  # this swaps unless you have actually 80GB RAM, since
122                  # most of the memory is touched
123                  $ENV{PERL_TEST_MEMORY} >= 80
124                    or skip "tiescalar second test needs 80GB", 2;
125                  my $x;
126                  ok(ref( ( x(), tie($x, "ScalarTie", 1..5))[-1]),
127                     "tied with deep stack");
128                  is($x, 6, "check arguments received");
129                  untie $x;
130                  ok(tie($x, "ScalarTie", x()), "tie scalar with long argument list");
131                  is($x, 1+scalar(@x), "check arguments received");
132                  untie $x;
133                SKIP:
134                  {
135                      skip "This test is even slower - define PERL_RUN_SLOW_TESTS to run me", 1
136                        unless $ENV{PERL_RUN_SLOW_TESTS};
137                      my $o = bless {}, "ScalarTie";
138                      # this was news to me
139                      ok(tie($x, $o, x(), 1), "tie scalar via object with long argument list");
140                      is($x, 2+scalar(@x), "check arguments received");
141                      untie $x;
142                  }
143              }
144          }
145      ],
146      [
147          apply => sub {
148            SKIP:
149              {
150                  skip "2**31 system calls take a very long time - define PERL_RUN_SLOW_TESTS to run me", 1
151                    unless $ENV{PERL_RUN_SLOW_TESTS};
152                  my $mode = (stat $0)[2];
153                  my $tries = 0x8000_0001;
154                  my $count = chmod $mode, ( $0 ) x $tries;
155                  is($count, $tries, "chmod with 2G files");
156              }
157          }
158      ],
159      [
160          join => sub {
161              no warnings 'uninitialized';
162              my $joined = join "", @x, "!";
163              is($joined, "Hello!", "join");
164          },
165      ],
166      [
167          class_construct => sub {
168              use experimental 'class';
169              class Foo {
170                  field $x :param;
171              };
172              my $y = Foo->new((x => 1) x 0x4000_0001);
173              ok($y, "construct class based object with 2G parameters");
174          },
175      ],
176      [
177          eval_sv_count => sub {
178            SKIP:
179              {
180                  $ENV{PERL_TEST_MEMORY} >= 70
181                    or skip "eval_sv_count test needs 70GB", 2;
182
183                  my $count = ( @x, XS::APItest::eval_sv('@x', G_LIST) )[-1];
184                  is($count, scalar @x, "check eval_sv result/mark handling");
185              }
186          }
187      ],
188      [
189          call_sv_args => sub {
190              undef $arg_count;
191              my $ret_count = XS::APItest::call_sv(\&arg_count, G_LIST, x());
192              is($ret_count, 0, "call_sv with 2G args - arg_count() returns nothing");
193              is($arg_count, scalar @x, "check call_sv argument handling - argument count");
194          },
195      ],
196      [
197          call_sv_mark => sub {
198              my $ret_count = ( x(), XS::APItest::call_sv(\&list, G_LIST) )[-1];
199              is($ret_count, 2, "call_sv with deep stack - returned value count");
200          },
201      ],
202     );
203
204# these tests are slow, let someone debug them one at a time
205my %enabled = map { $_ => 1 } @ARGV;
206for my $test (@tests) {
207    my ($id, $code) = @$test;
208    if (!@ARGV || $enabled{$id}) {
209        note($id);
210        $code->();
211    }
212}
213
214done_testing();
215
216sub x { @x }
217
218sub z { 1 }
219
220sub iter {
221    my $result = '';
222    my $count = 0;
223    for my $item (qw(a b c)) {
224        $result .= $item;
225        die "iteration bug" if ++$count > 5;
226    }
227    $result;
228}
229
230sub do_split {
231    return split //, $_[0];
232}
233
234sub loader {
235    require Cwd;
236    ();
237}
238
239sub list2 {
240    scalar list(1);
241}
242
243sub list {
244    # ensure this continues to use a pp_list op
245    # if you change it.
246    return shift() ? (1, 2) : (2, 1);
247}
248
249sub arg_count {
250    $arg_count = @_;
251    ();
252}
253
254package ScalarTie;
255
256sub TIESCALAR {
257    ::note("TIESCALAR $_[0]");
258    bless { count => scalar @_ }, __PACKAGE__;
259}
260
261sub FETCH {
262    $_[0]{count};
263}
264