From 0441359b37d9fb9b063f5ef2d3e7f76777066758 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 16 Dec 2024 19:37:14 +0100 Subject: [PATCH] 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 --- include/swift/SIL/TypeLowering.h | 2 + lib/SIL/IR/TypeLowering.cpp | 10 +++++ test/SILOptimizer/Inputs/include/cunion.h | 9 ++++ .../Inputs/include/module.modulemap | 6 +++ test/SILOptimizer/dead_store_elim_c.sil | 42 +++++++++++++++++++ 5 files changed, 69 insertions(+) create mode 100644 test/SILOptimizer/Inputs/include/cunion.h create mode 100644 test/SILOptimizer/dead_store_elim_c.sil diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index cb59d041fc907..8c1dfa3b98795 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -280,6 +280,8 @@ class TypeLowering { } void setNonTrivial() { Flags |= NonTrivialFlag; } + void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; } + void setNonFixedABI() { Flags |= NonFixedABIFlag; } void setAddressOnly() { Flags |= AddressOnlyFlag; } void setTypeExpansionSensitive( diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 53d15836642f7..194f6f6e11779 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -44,6 +44,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/Test.h" #include "clang/AST/Type.h" +#include "clang/AST/Decl.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" @@ -2508,6 +2509,15 @@ namespace { properties.setLexical(IsLexical); } + if (auto *clangDecl = D->getClangDecl()) { + if (auto *recordDecl = dyn_cast(clangDecl)) { + // C unions are imported as opaque types. Therefore we have to assume + // that a union contains a pointer. + if (recordDecl->isOrContainsUnion()) + properties.setIsOrContainsRawPointer(); + } + } + // [is_or_contains_pack_unsubstituted] Visit the fields of the // unsubstituted type to find pack types which would be substituted away. for (auto field : D->getStoredProperties()) { diff --git a/test/SILOptimizer/Inputs/include/cunion.h b/test/SILOptimizer/Inputs/include/cunion.h new file mode 100644 index 0000000000000..0b083c0219cf2 --- /dev/null +++ b/test/SILOptimizer/Inputs/include/cunion.h @@ -0,0 +1,9 @@ + +struct S { + int i; +}; + +union U { + struct S *p; +}; + diff --git a/test/SILOptimizer/Inputs/include/module.modulemap b/test/SILOptimizer/Inputs/include/module.modulemap index 9dbf53720ec1a..7519ebe61bebf 100644 --- a/test/SILOptimizer/Inputs/include/module.modulemap +++ b/test/SILOptimizer/Inputs/include/module.modulemap @@ -2,3 +2,9 @@ module gizmo { header "Gizmo.h" export * } + +module CUnion { + header "cunion.h" + export * +} + diff --git a/test/SILOptimizer/dead_store_elim_c.sil b/test/SILOptimizer/dead_store_elim_c.sil new file mode 100644 index 0000000000000..16219280475b8 --- /dev/null +++ b/test/SILOptimizer/dead_store_elim_c.sil @@ -0,0 +1,42 @@ +// RUN: %target-sil-opt %s -dead-store-elimination -I %S/Inputs/include | %FileCheck %s + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims +import CUnion + + +sil [noinline] @modify_U : $@convention(thin) (@inout U) -> () { +[%0: read v**] +[global: read,write,copy,destroy,allocate,deinit_barrier] +} + +// CHECK-LABEL: sil @pointer_escape_via_c_union : +// CHECK: store %0 to %1 +// CHECK: } // end sil function 'pointer_escape_via_c_union' +sil @pointer_escape_via_c_union : $@convention(thin) (S) -> () { +[global: read,write,copy,destroy,allocate,deinit_barrier] +bb0(%0 : $S): + %1 = alloc_stack [var_decl] $S, var, name "vs" + store %0 to %1 + %3 = address_to_pointer [stack_protection] %1 to $Builtin.RawPointer + %4 = struct $UnsafeMutablePointer (%3) + %5 = alloc_stack [var_decl] $U, var, name "u" + %6 = enum $Optional>, #Optional.some!enumelt, %4 + %7 = alloc_stack [var_decl] $U + %8 = address_to_pointer %7 to $Builtin.RawPointer + %9 = pointer_to_address %8 to [strict] $*Optional> + store %6 to %9 + %11 = load %7 + dealloc_stack %7 + store %11 to %5 + %14 = function_ref @modify_U : $@convention(thin) (@inout U) -> () + %15 = apply %14(%5) : $@convention(thin) (@inout U) -> () + dealloc_stack %5 + dealloc_stack %1 + %18 = tuple () + return %18 +} +