Skip to content

Commit

Permalink
temp - defer mess (holy shit)
Browse files Browse the repository at this point in the history
  • Loading branch information
aarzilli committed May 24, 2024
1 parent e81f08c commit eca2688
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 6 deletions.
28 changes: 28 additions & 0 deletions _fixtures/rangeoverfunc.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,33 @@ func TestPanickyIterator2() {
}
}

func TestPanickyIteratorWithNewDefer() {
var result []int
defer func() {
r := recover()
fmt.Println("Recovering ", r)
}()
for _, x := range OfSliceIndex([]int{100, 200}) {
result = append(result, x)
Y:
// swallows panics and iterates to end BUT `break Y` disables the body, so--> 10, 1, 2
for _, y := range VeryBadOfSliceIndex([]int{10, 20}) {
defer func() {
fmt.Println("y loop defer")
}()
result = append(result, y)

// converts early exit into a panic --> 1, 2
for k, z := range PanickyOfSliceIndex([]int{1, 2}) { // iterator panics
result = append(result, z)
if k == 1 {
break Y
}
}
}
}
}

func main() {
TestTrickyIterAll()
TestTrickyIterAll2()
Expand All @@ -154,6 +181,7 @@ func main() {
TestMultiCont0()
TestPanickyIterator1()
TestPanickyIterator2()
TestPanickyIteratorWithNewDefer()
}

type Seq[T any] func(yield func(T) bool)
Expand Down
33 changes: 33 additions & 0 deletions pkg/proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6548,6 +6548,39 @@ func TestRangeOverFuncNext(t *testing.T) {
nx(141), // if k == 1
nx(142), // break Y
nx(128), // defer func()
nx(129), // r := recover()
nx(130), // fmt.Println
})
})

t.Run("TestPanickyIteratorWithNewDefer", func(t *testing.T) {
testseq2intl(t, fixture, grp, p, nil, []seqTest{
funcBreak(t, "main.TestPanickyIteratorWithNewDefer"),
{contContinue, 149},
nx(150),
nx(151),
nx(155), // for _, x := range (x == 100)
nx(155),
nx(156),
nx(157),
nx(159), // for _, y := range (y == 10)
nx(159),
nx(160),
nx(163), // result = append(result, y)
nx(166), // for k, z := range (k == 0, z == 1)
nx(166),
nx(167), // result = append(result, z)
nx(168), // if k == 1
nx(171),

nx(166), // for k, z := range (k == 0, z == 1)
nx(167), // result = append(result, z)
nx(168), // if k == 1
nx(169), // break Y
nx(159),
nx(172),
nx(160), // defer func()
nx(161), // fmt.Println
})
})
})
Expand Down
48 changes: 44 additions & 4 deletions pkg/proc/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,8 @@ type Defer struct {
link *Defer // Next deferred function
argSz int64 // Always 0 in Go >=1.17

rangefunc []*Defer // See explanation in $GOROOT/src/runtime/panic.go, comment to function runtime.deferrangefunc (this is the equivalent of the rangefunc variable and head fields, combined)

variable *Variable
Unreadable error
}
Expand All @@ -657,7 +659,7 @@ func (g *G) readDefers(frames []Stackframe) {
}

if frames[i].TopmostDefer == nil {
frames[i].TopmostDefer = curdefer
frames[i].TopmostDefer = curdefer.topdefer()
}

if frames[i].SystemStack || curdefer.SP >= uint64(frames[i].Regs.CFA) {
Expand All @@ -673,13 +675,17 @@ func (g *G) readDefers(frames []Stackframe) {
// compared with deferred frames.
i++
} else {
frames[i].Defers = append(frames[i].Defers, curdefer)
if len(curdefer.rangefunc) > 0 {
frames[i].Defers = append(frames[i].Defers, curdefer.rangefunc...)
} else {
frames[i].Defers = append(frames[i].Defers, curdefer)
}
curdefer = curdefer.Next()
}
}
}

func (d *Defer) load() {
func (d *Defer) load(canrecur bool) {
v := d.variable // +rtype _defer
v.loadValue(LoadConfig{false, 1, 0, 0, -1, 0})
if v.Unreadable != nil {
Expand Down Expand Up @@ -714,6 +720,33 @@ func (d *Defer) load() {
if linkvar.Addr != 0 {
d.link = &Defer{variable: linkvar}
}

if canrecur {
h := v
for _, fieldname := range []string{"head", "u", "value"} {
if h == nil {
return
}
h = h.loadFieldNamed(fieldname)
}
if h != nil {
h := h.newVariable("", h.Addr, pointerTo(linkvar.DwarfType, h.bi.Arch), h.mem).maybeDereference()
if h.Addr != 0 {
hd := &Defer{variable: h}
for {
hd.load(false)
d.rangefunc = append(d.rangefunc, hd)
if hd.link == nil {
break
}
if hd.link.SP < hd.SP {
hd.link.Unreadable = errSPDecreased
}
hd = hd.link
}
}
}
}
}

// errSPDecreased is used when (*Defer).Next detects a corrupted linked
Expand All @@ -728,13 +761,20 @@ func (d *Defer) Next() *Defer {
if d.link == nil {
return nil
}
d.link.load()
d.link.load(true)
if d.link.SP < d.SP {
d.link.Unreadable = errSPDecreased
}
return d.link
}

func (d *Defer) topdefer() *Defer {
if len(d.rangefunc) > 0 {
return d.rangefunc[0]
}
return d
}

// EvalScope returns an EvalScope relative to the argument frame of this deferred call.
// The argument frame of a deferred call is stored in memory immediately
// after the deferred header.
Expand Down
2 changes: 1 addition & 1 deletion pkg/proc/target_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ func next(dbp *Target, stepInto, inlinedStepOut bool) error {

if !backward && !topframe.Current.Fn.cu.image.Stripped() {
fr := topframe
if len(rangeFrames) != 0 {
if len(rangeFrames) != 0 && !stepInto {
fr = rangeFrames[len(rangeFrames)-2]
}
_, err = setDeferBreakpoint(dbp, text, fr, sameGCond, stepInto)
Expand Down
2 changes: 1 addition & 1 deletion pkg/proc/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ func (g *G) Defer() *Defer {
return nil
}
d := &Defer{variable: dvar}
d.load()
d.load(true)
return d
}

Expand Down

0 comments on commit eca2688

Please sign in to comment.