Skip to content

Commit

Permalink
[mypp/examples] Repro GC crash bug
Browse files Browse the repository at this point in the history
This is issue #1986.

Our rooting logic for context managers is simply wrong (and has always
been wrong).  The bug is apparently triggered by:

- ctx_Foo() that has member variable that's a GC object
- Invoking GC with mylib.MaybeCollect() while the context manager is
  "live" (in scope)

In Oils, it is exposed by our Str => replace() implementation, which
calls ctx_Shvar().
  • Loading branch information
Andy C committed Jun 4, 2024
1 parent ab0256d commit cddb9f7
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
10 changes: 10 additions & 0 deletions mycpp/examples/scoped_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import sys

from mycpp import mylib
from mycpp.mylib import log
from typing import List, Optional, Any

Expand Down Expand Up @@ -48,13 +49,18 @@ def __init__(self, state, entry):
self.state = state
state.Push(entry)

# Bug #1986: add heap-allocated member of context manager
#self.restored = [] # type: List[str]
#self.restored.append('foo')

def __enter__(self):
# type: () -> None
"""no-op, but it has to exist to be used as context manager."""
pass

def __exit__(self, type, value, traceback):
# type: (Any, Any, Any) -> None
#self.restored.pop()
self.state.Pop()


Expand Down Expand Up @@ -182,8 +188,12 @@ def run_benchmarks():
# type: () -> None
d = DirStack()
for i in xrange(1000000):
# Does NOT trigger the bug!
#mylib.MaybeCollect()
try:
with ctx_DirStack(d, 'foo') as _:
# Bug #1986: add collection in this loop
mylib.MaybeCollect()
if i % 10000 == 0:
raise MyError()
except MyError:
Expand Down
73 changes: 73 additions & 0 deletions test/bug-1986.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
#
# Potentially Long-running stress tests
#
# Usage:
# test/stress.sh <function name>

# GC bug?

replace-ysh() {
#local ysh=_bin/cxx-opt/ysh
local ysh=_bin/cxx-dbg/ysh
#local ysh=_bin/cxx-asan/ysh
ninja $ysh

# gc_mylib.cc sets threshold to 50K
# it doesn't seem to matter!
#
# Oh does this have to do with recursively calling back into the interpreter?

#GDB='gdb --args '
GDB=''

OIL_GC_STATS=1 OILS_GC_VERBOSE=1 OILS_GC_THRESHOLD=100 $GDB $ysh -c '
var x = "z"
for i in (1 .. 1000) {
echo $i
# z -> zz creates exponential data
setvar x = x=>replace("z", "y")
setvar x = x=>replace("y", "z")
}
echo $x
'
}

replace-exp() {
local osh=_bin/cxx-opt/osh
ninja $osh

# 2.791 seconds for 19 iterations, up to 1 MB
SH=$osh

SH=bash
for sh in bash $osh; do
echo "=== $sh ==="
echo

time $sh -c '
x=z
for i in {1..19}; do
x=${x//z/zz}
echo len=${#x}
done
'
done
}

# Reduce this bug
# https://github.com/oilshell/oil/issues/1986

bug-1986() {
local ysh=_bin/cxx-dbg/ysh
#local ysh=_bin/cxx-asan/ysh
ninja $ysh

GDB="gdb --args $PWD/$ysh"
cd bug/code

set -x
$GDB src/amd-scripts/amd-test --select imperfect aomp-amd-staging.cfg 14
}

"$@"

0 comments on commit cddb9f7

Please sign in to comment.