Skip to content

Commit 6ae4b43

Browse files
aykevldeadprogram
authored andcommitted
interp: fix recursive scanning
There were a few issues that made interp not perform as it should: * The scan was non-recursive due to a bug. * Recursive scanning would always return the severity level, which is not always the best strategy.
1 parent bece6b9 commit 6ae4b43

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

interp/scan.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ type sideEffectResult struct {
2424
// returns whether this function has side effects and if it does, which globals
2525
// it mentions anywhere in this function or any called functions.
2626
func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
27+
switch fn.Name() {
28+
case "runtime.alloc":
29+
// Cannot be scanned but can be interpreted.
30+
return &sideEffectResult{severity: sideEffectNone}
31+
case "runtime._panic":
32+
return &sideEffectResult{severity: sideEffectLimited}
33+
}
2734
if e.sideEffectFuncs == nil {
2835
e.sideEffectFuncs = make(map[llvm.Value]*sideEffectResult)
2936
}
@@ -73,25 +80,32 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
7380
result.updateSeverity(sideEffectAll)
7481
continue
7582
}
76-
name := child.Name()
7783
if child.IsDeclaration() {
78-
if name == "runtime.makeInterface" {
84+
switch child.Name() {
85+
case "runtime.makeInterface":
7986
// Can be interpreted so does not have side effects.
8087
continue
8188
}
8289
// External function call. Assume only limited side effects
8390
// (no affected globals, etc.).
84-
if result.hasLocalSideEffects(dirtyLocals, inst) {
91+
if e.hasLocalSideEffects(dirtyLocals, inst) {
8592
result.updateSeverity(sideEffectLimited)
8693
}
8794
continue
8895
}
89-
childSideEffects := e.hasSideEffects(fn)
96+
childSideEffects := e.hasSideEffects(child)
9097
switch childSideEffects.severity {
9198
case sideEffectInProgress, sideEffectNone:
9299
// no side effects or recursive function - continue scanning
100+
case sideEffectLimited:
101+
// The return value may be problematic.
102+
if e.hasLocalSideEffects(dirtyLocals, inst) {
103+
result.updateSeverity(sideEffectLimited)
104+
}
105+
case sideEffectAll:
106+
result.updateSeverity(sideEffectAll)
93107
default:
94-
result.update(childSideEffects)
108+
panic("unreachable")
95109
}
96110
case llvm.Load, llvm.Store:
97111
if inst.IsVolatile() {
@@ -118,7 +132,7 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
118132
// hasLocalSideEffects checks whether the given instruction flows into a branch
119133
// or return instruction, in which case the whole function must be marked as
120134
// having side effects and be called at runtime.
121-
func (r *sideEffectResult) hasLocalSideEffects(dirtyLocals map[llvm.Value]struct{}, inst llvm.Value) bool {
135+
func (e *Eval) hasLocalSideEffects(dirtyLocals map[llvm.Value]struct{}, inst llvm.Value) bool {
122136
if _, ok := dirtyLocals[inst]; ok {
123137
// It is already known that this local is dirty.
124138
return true
@@ -156,7 +170,7 @@ func (r *sideEffectResult) hasLocalSideEffects(dirtyLocals map[llvm.Value]struct
156170
// For a list:
157171
// https://godoc.org/github.com/llvm-mirror/llvm/bindings/go/llvm#Opcode
158172
dirtyLocals[user] = struct{}{}
159-
if r.hasLocalSideEffects(dirtyLocals, user) {
173+
if e.hasLocalSideEffects(dirtyLocals, user) {
160174
return true
161175
}
162176
}

0 commit comments

Comments
 (0)