Skip to content

Commit 0441359

Browse files
committed
TypeLowering: assume that C unions can contain a pointer
C unions are imported as opaque types. Therefore we have to assume that a union contains a pointer. This is important for alias analysis to catch escaping pointers via C unions. Fixes a miscompile. rdar://141555290
1 parent 0a9ab41 commit 0441359

File tree

5 files changed

+69
-0
lines changed

5 files changed

+69
-0
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ class TypeLowering {
280280
}
281281

282282
void setNonTrivial() { Flags |= NonTrivialFlag; }
283+
void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; }
284+
283285
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
284286
void setAddressOnly() { Flags |= AddressOnlyFlag; }
285287
void setTypeExpansionSensitive(

lib/SIL/IR/TypeLowering.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "swift/SIL/SILModule.h"
4545
#include "swift/SIL/Test.h"
4646
#include "clang/AST/Type.h"
47+
#include "clang/AST/Decl.h"
4748
#include "llvm/Support/Compiler.h"
4849
#include "llvm/Support/Debug.h"
4950

@@ -2508,6 +2509,15 @@ namespace {
25082509
properties.setLexical(IsLexical);
25092510
}
25102511

2512+
if (auto *clangDecl = D->getClangDecl()) {
2513+
if (auto *recordDecl = dyn_cast<clang::RecordDecl>(clangDecl)) {
2514+
// C unions are imported as opaque types. Therefore we have to assume
2515+
// that a union contains a pointer.
2516+
if (recordDecl->isOrContainsUnion())
2517+
properties.setIsOrContainsRawPointer();
2518+
}
2519+
}
2520+
25112521
// [is_or_contains_pack_unsubstituted] Visit the fields of the
25122522
// unsubstituted type to find pack types which would be substituted away.
25132523
for (auto field : D->getStoredProperties()) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
struct S {
3+
int i;
4+
};
5+
6+
union U {
7+
struct S *p;
8+
};
9+

test/SILOptimizer/Inputs/include/module.modulemap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@ module gizmo {
22
header "Gizmo.h"
33
export *
44
}
5+
6+
module CUnion {
7+
header "cunion.h"
8+
export *
9+
}
10+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %target-sil-opt %s -dead-store-elimination -I %S/Inputs/include | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
import SwiftShims
8+
import CUnion
9+
10+
11+
sil [noinline] @modify_U : $@convention(thin) (@inout U) -> () {
12+
[%0: read v**]
13+
[global: read,write,copy,destroy,allocate,deinit_barrier]
14+
}
15+
16+
// CHECK-LABEL: sil @pointer_escape_via_c_union :
17+
// CHECK: store %0 to %1
18+
// CHECK: } // end sil function 'pointer_escape_via_c_union'
19+
sil @pointer_escape_via_c_union : $@convention(thin) (S) -> () {
20+
[global: read,write,copy,destroy,allocate,deinit_barrier]
21+
bb0(%0 : $S):
22+
%1 = alloc_stack [var_decl] $S, var, name "vs"
23+
store %0 to %1
24+
%3 = address_to_pointer [stack_protection] %1 to $Builtin.RawPointer
25+
%4 = struct $UnsafeMutablePointer<S> (%3)
26+
%5 = alloc_stack [var_decl] $U, var, name "u"
27+
%6 = enum $Optional<UnsafeMutablePointer<S>>, #Optional.some!enumelt, %4
28+
%7 = alloc_stack [var_decl] $U
29+
%8 = address_to_pointer %7 to $Builtin.RawPointer
30+
%9 = pointer_to_address %8 to [strict] $*Optional<UnsafeMutablePointer<S>>
31+
store %6 to %9
32+
%11 = load %7
33+
dealloc_stack %7
34+
store %11 to %5
35+
%14 = function_ref @modify_U : $@convention(thin) (@inout U) -> ()
36+
%15 = apply %14(%5) : $@convention(thin) (@inout U) -> ()
37+
dealloc_stack %5
38+
dealloc_stack %1
39+
%18 = tuple ()
40+
return %18
41+
}
42+

0 commit comments

Comments
 (0)