Skip to content

Commit 7eef54f

Browse files
committed
fix a bug in the ReleaseDevirtualizer pass
The release-devirtualizer must not run on the same alloc_ref twice. This is a very rare case, but if it happens it's a very bad thing, because it results in a double-free crash. The fix is to detect that a dealloc_ref instruction (although it isn't "releasing"), does a memory deallocation. Found by doing some unrelated experiments.
1 parent 048e41e commit 7eef54f

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ReleaseDevirtualizer.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,15 @@ let releaseDevirtualizerPass = FunctionPass(
4949
}
5050
}
5151

52-
if instruction is ReleaseValueInst || instruction is StrongReleaseInst {
53-
lastRelease = instruction as? RefCountingInst
54-
} else if instruction.mayRelease {
55-
lastRelease = nil
52+
switch instruction {
53+
case is ReleaseValueInst, is StrongReleaseInst:
54+
lastRelease = instruction as? RefCountingInst
55+
case is DeallocRefInst, is SetDeallocatingInst:
56+
lastRelease = nil
57+
default:
58+
if instruction.mayRelease {
59+
lastRelease = nil
60+
}
5661
}
5762
}
5863
}

test/SILOptimizer/devirt_release.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// on the same platform at the same time.
44
// RUN: %target-sil-opt -enable-sil-verify-all %s -release-devirtualizer -module-name=test | %FileCheck %s
55

6+
// REQUIRES: swift_in_compiler
7+
68
sil_stage canonical
79

810
import Builtin
@@ -43,6 +45,27 @@ bb0:
4345
return %r : $()
4446
}
4547

48+
// CHECK-LABEL: sil @dont_devirtualize_devirtualized
49+
// CHECK: alloc_ref
50+
// CHECK-NEXT: strong_retain
51+
// CHECK-NEXT: strong_release
52+
// CHECK-NEXT: set_deallocating
53+
// CHECK-NEXT: dealloc_ref
54+
// CHECK-NEXT: dealloc_stack_ref
55+
// CHECK-NEXT: tuple
56+
// CHECK: } // end sil function 'dont_devirtualize_devirtualized'
57+
sil @dont_devirtualize_devirtualized : $@convention(thin) () -> () {
58+
bb0:
59+
%1 = alloc_ref [stack] $B
60+
strong_retain %1 : $B
61+
strong_release %1 : $B
62+
set_deallocating %1 : $B
63+
dealloc_ref %1 : $B
64+
dealloc_stack_ref %1 : $B
65+
%r = tuple ()
66+
return %r : $()
67+
}
68+
4669
// CHECK-LABEL: sil @dont_devirtualize_wrong_release
4770
// CHECK: alloc_ref
4871
// CHECK-NEXT: strong_release

0 commit comments

Comments
 (0)