Merge remote-tracking branch 'origin/main' into rebranch

This commit is contained in:
swift-ci
2022-11-11 22:52:44 -08:00
23 changed files with 809 additions and 288 deletions

View File

@@ -28,16 +28,16 @@ private func log(_ message: @autoclosure () -> String) {
/// Within safe swift code there shouldn't be any buffer overflows. But if the address
/// of a stack variable is converted to an unsafe pointer, it's not in the control of
/// the compiler anymore.
/// This means, if there is any `address_to_pointer` instruction for an `alloc_stack`,
/// such a function is marked for stack protection.
/// Another case is `index_addr` for non-tail allocated memory. This pattern appears if
/// pointer arithmetic is done with unsafe pointers in swift code.
/// This means, if an `alloc_stack` ends up at an `address_to_pointer [stack_protection]`,
/// the `alloc_stack`'s function is marked for stack protection.
/// Another case is `index_addr [stack_protection]` for non-tail allocated memory. This
/// pattern appears if pointer arithmetic is done with unsafe pointers in swift code.
///
/// If the origin of an unsafe pointer can only be tracked to a function argument, the
/// pass tries to find the root stack allocation for such an argument by doing an
/// inter-procedural analysis. If this is not possible, the fallback is to move the
/// argument into a temporary `alloc_stack` and do the unsafe pointer operations on
/// the temporary.
/// inter-procedural analysis. If this is not possible and the `enableMoveInoutStackProtection`
/// option is set, the fallback is to move the argument into a temporary `alloc_stack`
/// and do the unsafe pointer operations on the temporary.
let stackProtection = ModulePass(name: "stack-protection", {
(context: ModulePassContext) in
@@ -45,7 +45,7 @@ let stackProtection = ModulePass(name: "stack-protection", {
return
}
var optimization = StackProtectionOptimization()
var optimization = StackProtectionOptimization(enableMoveInout: context.options.enableMoveInoutStackProtection)
optimization.processModule(context)
})
@@ -60,13 +60,15 @@ let functionStackProtection = FunctionPass(name: "function-stack-protection", {
return
}
var optimization = StackProtectionOptimization()
var optimization = StackProtectionOptimization(enableMoveInout: context.options.enableMoveInoutStackProtection)
optimization.process(function: function, context)
})
/// The optimization algorithm.
private struct StackProtectionOptimization {
private let enableMoveInout: Bool
// The following members are nil/not used if this utility is used on function-level.
private var moduleContext: ModulePassContext?
@@ -77,6 +79,10 @@ private struct StackProtectionOptimization {
// are added to this array in `findOriginsInCallers`.
private var needStackProtection: [Function] = []
init(enableMoveInout: Bool) {
self.enableMoveInout = enableMoveInout
}
/// The main entry point if running on module-level.
mutating func processModule(_ moduleContext: ModulePassContext) {
self.moduleContext = moduleContext
@@ -147,6 +153,8 @@ private struct StackProtectionOptimization {
case .yes:
// For example:
// %baseAddr = alloc_stack $T
log("local: \(function.name) -- \(instruction)")
function.setNeedsStackProtection(context)
case .decidedInCaller(let arg):
@@ -157,7 +165,7 @@ private struct StackProtectionOptimization {
defer { worklist.deinitialize() }
worklist.push(arg)
if !findOriginsInCallers(&worklist) {
if findOriginsInCallers(&worklist) == NeedInsertMoves.yes {
// We don't know the origin of the function argument. Therefore we need to do the
// conservative default which is to move the value to a temporary stack location.
if let beginAccess = scope {
@@ -179,22 +187,19 @@ private struct StackProtectionOptimization {
// If the object is passed as an argument to its function, add those arguments
// to the worklist.
switch worklist.push(rootsOf: obj) {
case .failed:
// If we cannot find the roots, the object is most likely not stack allocated.
return
case .succeeded(let foundStackAlloc):
let (_, foundStackAlloc) = worklist.push(rootsOf: obj)
if foundStackAlloc {
// The object is created by an `alloc_ref [stack]`.
log("objectIfStackPromoted: \(function.name) -- \(instruction)")
function.setNeedsStackProtection(context)
}
}
// In case the (potentially) stack allocated object is passed via an argument,
// process the worklist as we do for indirect arguments (see above).
// For example:
// bb0(%0: $Class):
// %baseAddr = ref_element_addr %0 : $Class, #Class.field
if !findOriginsInCallers(&worklist),
if findOriginsInCallers(&worklist) == NeedInsertMoves.yes,
let beginAccess = scope {
// We don't know the origin of the object. Therefore we need to do the
// conservative default which is to move the value to a temporary stack location.
@@ -207,14 +212,25 @@ private struct StackProtectionOptimization {
}
}
/// Return value of `findOriginsInCallers()`.
enum NeedInsertMoves {
// Not all call sites could be identified, and if moves are enabled (`enableMoveInout`)
// the original argument should be moved to a temporary.
case yes
// Either all call sites could be identified, which means that stack protection is done
// in the callers, or moves are not enabled (`enableMoveInout` is false).
case no
}
/// Find all origins of function arguments in `worklist`.
/// All functions, which allocate such an origin are added to `self.needStackProtection`.
/// Returns true if all origins could be found and false, if there are unknown origins.
private mutating func findOriginsInCallers(_ worklist: inout ArgumentWorklist) -> Bool {
private mutating func findOriginsInCallers(_ worklist: inout ArgumentWorklist) -> NeedInsertMoves {
guard let moduleContext = moduleContext else {
// Don't do any inter-procedural analysis when used on function-level.
return false
return enableMoveInout ? .yes : .no
}
// Put the resulting functions into a temporary array, because we only add them to
@@ -230,21 +246,25 @@ private struct StackProtectionOptimization {
while let arg = worklist.pop() {
let f = arg.function
let uses = functionUses.getUses(of: f)
if uses.hasUnknownUses {
return false
if uses.hasUnknownUses && enableMoveInout {
return NeedInsertMoves.yes
}
for useInst in uses {
guard let fri = useInst as? FunctionRefInst else {
return false
if enableMoveInout {
return NeedInsertMoves.yes
}
continue
}
for functionRefUse in fri.uses {
guard let apply = functionRefUse.instruction as? ApplySite else {
return false
guard let apply = functionRefUse.instruction as? ApplySite,
let callerArgIdx = apply.callerArgIndex(calleeArgIndex: arg.index) else {
if enableMoveInout {
return NeedInsertMoves.yes
}
guard let callerArgIdx = apply.callerArgIndex(calleeArgIndex: arg.index) else {
return false
continue
}
let callerArg = apply.arguments[callerArgIdx]
if callerArg.type.isAddress {
@@ -252,6 +272,7 @@ private struct StackProtectionOptimization {
switch callerArg.accessBase.isStackAllocated {
case .yes:
if !callerArg.function.needsStackProtection {
log("alloc_stack in caller: \(callerArg.function.name) -- \(callerArg)")
newFunctions.push(callerArg.function)
}
case .no:
@@ -266,36 +287,38 @@ private struct StackProtectionOptimization {
case .objectIfStackPromoted(let obj):
// If the object is passed as an argument to its function,
// add those arguments to the worklist.
switch worklist.push(rootsOf: obj) {
case .failed:
return false
case .succeeded(let foundStackAlloc):
let (foundUnknownRoots, foundStackAlloc) = worklist.push(rootsOf: obj)
if foundUnknownRoots && enableMoveInout {
return NeedInsertMoves.yes
}
if foundStackAlloc && !obj.function.needsStackProtection {
// The object is created by an `alloc_ref [stack]`.
log("object in caller: \(obj.function.name) -- \(obj)")
newFunctions.push(obj.function)
}
}
case .unknown:
return false
if enableMoveInout {
return NeedInsertMoves.yes
}
}
} else {
// The argument is an object. If the object is itself passed as an argument
// to its function, add those arguments to the worklist.
switch worklist.push(rootsOf: callerArg) {
case .failed:
return false
case .succeeded(let foundStackAlloc):
let (foundUnknownRoots, foundStackAlloc) = worklist.push(rootsOf: callerArg)
if foundUnknownRoots && enableMoveInout {
return NeedInsertMoves.yes
}
if foundStackAlloc && !callerArg.function.needsStackProtection {
// The object is created by an `alloc_ref [stack]`.
log("object arg in caller: \(callerArg.function.name) -- \(callerArg)")
newFunctions.push(callerArg.function)
}
}
}
}
}
}
needStackProtection.append(contentsOf: newFunctions)
return true
return NeedInsertMoves.no
}
/// Moves the value of an indirect argument to a temporary stack location, if possible.
@@ -366,9 +389,16 @@ private struct StackProtectionOptimization {
/// Worklist for inter-procedural analysis of function arguments.
private struct ArgumentWorklist : ValueUseDefWalker {
var walkUpCache = WalkerCache<SmallProjectionPath>()
private var foundStackAlloc = false
// Used in `push(rootsOf:)`
private var foundStackAlloc = false
private var foundUnknownRoots = false
// Contains arguments which are already handled and don't need to be put into the worklist again.
// Note that this cannot be a `ValueSet`, because argument can be from different functions.
private var handled = Set<FunctionArgument>()
// The actual worklist.
private var list: Stack<FunctionArgument>
init(_ context: PassContext) {
@@ -385,21 +415,15 @@ private struct ArgumentWorklist : ValueUseDefWalker {
}
}
enum PushResult {
case failed
case succeeded(foundStackAlloc: Bool)
}
/// Pushes all roots of `object`, which are function arguments, to the worklist.
/// Returns `.succeeded(true)` if some of the roots are `alloc_ref [stack]` instructions.
mutating func push(rootsOf object: Value) -> PushResult {
/// If the returned `foundUnknownRoots` is true, it means that not all roots of `object` could
/// be tracked to a function argument.
/// If the returned `foundStackAlloc` than at least one found root is an `alloc_ref [stack]`.
mutating func push(rootsOf object: Value) -> (foundUnknownRoots: Bool, foundStackAlloc: Bool) {
foundStackAlloc = false
switch walkUp(value: object, path: SmallProjectionPath(.anything)) {
case .continueWalk:
return .succeeded(foundStackAlloc: foundStackAlloc)
case .abortWalk:
return .failed
}
foundUnknownRoots = false
_ = walkUp(value: object, path: SmallProjectionPath(.anything))
return (foundUnknownRoots, foundStackAlloc)
}
mutating func pop() -> FunctionArgument? {
@@ -413,15 +437,12 @@ private struct ArgumentWorklist : ValueUseDefWalker {
if ar.canAllocOnStack {
foundStackAlloc = true
}
return .continueWalk
case let arg as FunctionArgument:
if handled.insert(arg).0 {
list.push(arg)
push(arg)
default:
foundUnknownRoots = true
}
return .continueWalk
default:
return .abortWalk
}
}
}
@@ -491,7 +512,6 @@ private extension Instruction {
private extension Function {
func setNeedsStackProtection(_ context: PassContext) {
if !needsStackProtection {
log("needs protection: \(name)")
set(needStackProtection: true, context)
}
}

View File

@@ -18,4 +18,8 @@ struct Options {
var enableStackProtection: Bool {
SILOptions_enableStackProtection(_bridged) != 0
}
var enableMoveInoutStackProtection: Bool {
SILOptions_enableMoveInoutStackProtection(_bridged) != 0
}
}

View File

@@ -52,6 +52,11 @@ private:
GenericSignature = 4,
// static func _typeSignature(...) -> (UnsafePointer<UInt8>, count: Int)
TypeSignature = 5,
// static func _owningModule(...) -> (UnsafePointer<UInt8>, count: Int)
OwningModule = 6,
// static func _supplementalSignatureModules(...)
// -> (UnsafePointer<UInt8>, count: Int)
SupplementalSignatureModules = 7,
};
/// The plugin type metadata.
@@ -100,6 +105,14 @@ public:
/// result string buffer.
StringRef invokeTypeSignature() const;
/// Invoke the `_owningModule` method. The caller assumes ownership of the
/// result string buffer.
StringRef invokeOwningModule() const;
/// Invoke the `_supplementalSignatureModules` method. The caller assumes
/// ownership of the result string buffer.
StringRef invokeSupplementalSignatureModules() const;
StringRef getName() const {
return name;
}

86
include/swift/AST/Macro.h Normal file
View File

@@ -0,0 +1,86 @@
//===--- Macro.h - Swift Macro Definition -----------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the `Macro` type that describes a macro definition.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_MACRO_H
#define SWIFT_AST_MACRO_H
#include "swift/AST/ASTAllocated.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Type.h"
namespace swift {
class ModuleDecl;
class Macro : public ASTAllocated<Macro> {
public:
/// The kind of macro, which determines how it can be used in source code.
enum Kind: uint8_t {
/// An expression macro.
Expression,
};
/// Describes how the macro is implemented.
enum class ImplementationKind: uint8_t {
/// The macro is built-in to the compiler, linked against the same
/// underlying syntax tree libraries.
Builtin,
/// The macro was defined in a compiler plugin.
Plugin,
};
/// The kind of macro.
const Kind kind;
/// How the macro is implemented.
const ImplementationKind implementationKind;
/// The name of the macro in the source, e.g., "stringify".
const Identifier name;
/// The generic signature, used to describe the signature of macros that
/// involve generic parameters.
const GenericSignature genericSignature;
/// The type signature of the macro.
const Type signature;
/// The module with which this macro is associated.
ModuleDecl * const owningModule;
/// Supplemental modules that should be imported when
const ArrayRef<ModuleDecl *> supplementalSignatureModules;
/// An opaque handle to the representation of the macro.
void * const opaqueHandle;
public:
Macro(
Kind kind, ImplementationKind implementationKind, Identifier name,
GenericSignature genericSignature, Type signature,
ModuleDecl *owningModule,
ArrayRef<ModuleDecl *> supplementalSignatureModules,
void *opaqueHandle
) : kind(kind), implementationKind(implementationKind), name(name),
genericSignature(genericSignature), signature(signature),
owningModule(owningModule),
supplementalSignatureModules(supplementalSignatureModules),
opaqueHandle(opaqueHandle) { }
};
}
#endif // SWIFT_AST_MACRO_H

View File

@@ -129,7 +129,11 @@ public:
bool EnablePerformanceAnnotations = false;
/// Enables the emission of stack protectors in functions.
bool EnableStackProtection = false;
bool EnableStackProtection = true;
/// Like `EnableStackProtection` and also enables moving of values to
/// temporaries for stack protection.
bool EnableMoveInoutStackProtection = false;
/// Controls whether or not paranoid verification checks are run.
bool VerifyAll = false;

View File

@@ -45,6 +45,7 @@ class DefaultArgumentExpr;
class DefaultArgumentType;
class ClosureExpr;
class GenericParamList;
class Macro;
class PrecedenceGroupDecl;
class PropertyWrapperInitializerInfo;
struct PropertyWrapperLValueness;
@@ -3733,26 +3734,11 @@ public:
bool isCached() const { return true; }
};
/// Retrieves the evaluation context of a macro with the given name.
///
/// The macro evaluation context is a user-defined generic signature and return
/// type that serves as the "interface type" of references to the macro. The
/// current implementation takes those pieces of syntax from the macro itself,
/// then inserts them into a Swift struct that looks like
///
/// \code
/// struct __MacroEvaluationContext\(macro.genericSignature) {
/// typealias SignatureType = \(macro.signature)
/// }
/// \endcode
///
/// So that we can use all of Swift's native name lookup and type resolution
/// facilities to map the parsed signature type back into a semantic \c Type
/// AST and a set of requiremnets.
class MacroContextRequest
: public SimpleRequest<MacroContextRequest,
StructDecl *(std::string, ModuleDecl *),
/// Lookup all macros with the given name that are visible from the given
/// module.
class MacroLookupRequest
: public SimpleRequest<MacroLookupRequest,
ArrayRef<Macro *>(Identifier, ModuleDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
@@ -3760,8 +3746,8 @@ public:
private:
friend SimpleRequest;
StructDecl *evaluate(Evaluator &evaluator,
std::string macroName, ModuleDecl *mod) const;
ArrayRef<Macro *> evaluate(Evaluator &evaluator,
Identifier macroName, ModuleDecl *mod) const;
public:
bool isCached() const { return true; }
@@ -3772,6 +3758,7 @@ void simple_display(llvm::raw_ostream &out, Type value);
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
void simple_display(llvm::raw_ostream &out, ResultBuilderBodyPreCheck pck);
void simple_display(llvm::raw_ostream &out, const Macro *macro);
#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"

View File

@@ -440,6 +440,6 @@ SWIFT_REQUEST(TypeChecker, GetTypeWrapperInitializer,
SWIFT_REQUEST(TypeChecker, SynthesizeHasSymbolQueryRequest,
FuncDecl *(ValueDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, MacroContextRequest,
StructDecl *(std::string, ModuleDecl *),
SWIFT_REQUEST(TypeChecker, MacroLookupRequest,
ArrayRef<Macro *>(Identifier, ModuleDecl *),
Cached, NoLocationInfo)

View File

@@ -1104,6 +1104,9 @@ def enable_stack_protector :
def disable_stack_protector :
Flag<["-"], "disable-stack-protector">,
HelpText<"Disable the stack-protector">;
def enable_move_inout_stack_protector :
Flag<["-"], "enable-move-inout-stack-protector">,
HelpText<"Enable the stack protector by moving values to temporaries">;
def enable_new_llvm_pass_manager :
Flag<["-"], "enable-new-llvm-pass-manager">,

View File

@@ -184,6 +184,7 @@ OptionalBridgedFunction
PassContext_loadFunction(BridgedPassContext context, llvm::StringRef name);
SwiftInt SILOptions_enableStackProtection(BridgedPassContext context);
SwiftInt SILOptions_enableMoveInoutStackProtection(BridgedPassContext context);
SWIFT_END_NULLABILITY_ANNOTATIONS

View File

@@ -4911,7 +4911,7 @@ public:
///
/// \returns The opened type of the macro with this name, or the null \c Type
/// if no such macro exists.
Type getTypeOfMacroReference(StringRef macro, Expr *anchor);
Type getTypeOfMacroReference(Identifier macroName, Expr *anchor);
#endif
/// Retrieve a list of generic parameter types solver has "opened" (replaced

View File

@@ -319,3 +319,27 @@ StringRef CompilerPlugin::invokeTypeSignature() const {
llvm_unreachable("Incompatible host compiler");
#endif
}
StringRef CompilerPlugin::invokeOwningModule() const {
#if __clang__
using Method = SWIFT_CC CharBuffer(
SWIFT_CONTEXT const void *, const void *, const void *);
auto method = getWitnessMethodUnsafe<Method>(
WitnessTableEntry::OwningModule);
return method(metadata, metadata, witnessTable).str();
#else
llvm_unreachable("Incompatible host compiler");
#endif
}
StringRef CompilerPlugin::invokeSupplementalSignatureModules() const {
#if __clang__
using Method = SWIFT_CC CharBuffer(
SWIFT_CONTEXT const void *, const void *, const void *);
auto method = getWitnessMethodUnsafe<Method>(
WitnessTableEntry::SupplementalSignatureModules);
return method(metadata, metadata, witnessTable).str();
#else
llvm_unreachable("Incompatible host compiler");
#endif
}

View File

@@ -1,3 +1,4 @@
import SwiftParser
import SwiftSyntax
@_spi(Testing) import _SwiftSyntaxMacros
@@ -81,43 +82,107 @@ private func allocateUTF8String(
}
}
@_cdecl("swift_ASTGen_getMacroGenericSignature")
public func getMacroGenericSignature(
macroPtr: UnsafeMutablePointer<UInt8>,
genericSignaturePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
genericSignatureLengthPtr: UnsafeMutablePointer<Int>
) {
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
guard let genericSig = macro.pointee.macro.genericSignature else {
(genericSignaturePtr.pointee, genericSignatureLengthPtr.pointee) = (nil, 0)
return
}
(genericSignaturePtr.pointee, genericSignatureLengthPtr.pointee) =
allocateUTF8String(genericSig.description)
}
}
/// Query the type signature of the given macro.
@_cdecl("swift_ASTGen_getMacroTypeSignature")
public func getMacroTypeSignature(
macroPtr: UnsafeMutablePointer<UInt8>,
evaluationContextPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
evaluationContextLengthPtr: UnsafeMutablePointer<Int>
signaturePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
signatureLengthPtr: UnsafeMutablePointer<Int>
) {
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
(evaluationContextPtr.pointee, evaluationContextLengthPtr.pointee) =
allocateUTF8String(macro.pointee.evaluationContext, nullTerminated: true)
(signaturePtr.pointee, signatureLengthPtr.pointee) =
allocateUTF8String(macro.pointee.macro.signature.description)
}
}
extension ExportedMacro {
var evaluationContext: String {
"""
struct __MacroEvaluationContext\(self.macro.genericSignature?.description ?? "") {
typealias SignatureType = \(self.macro.signature)
}
"""
/// Query the documentation of the given macro.
@_cdecl("swift_ASTGen_getMacroDocumentation")
public func getMacroDocumentation(
macroPtr: UnsafeMutablePointer<UInt8>,
documentationPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
documentationLengthPtr: UnsafeMutablePointer<Int>
) {
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
(documentationPtr.pointee, documentationLengthPtr.pointee) =
allocateUTF8String(macro.pointee.macro.documentation)
}
}
/// Query the macro evaluation context of the given macro.
/// Query the owning module of the given macro.
@_cdecl("swift_ASTGen_getMacroOwningModule")
public func getMacroOwningModule(
macroPtr: UnsafeMutablePointer<UInt8>,
owningModulePtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
owningModuleLengthPtr: UnsafeMutablePointer<Int>
) {
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
(owningModulePtr.pointee, owningModuleLengthPtr.pointee) =
allocateUTF8String(macro.pointee.macro.owningModule)
}
}
/// Query the supplemental signature modules of the given macro,
/// as a semicolon-separated string
@_cdecl("swift_ASTGen_getMacroSupplementalSignatureModules")
public func getMacroSupplementableSignatureModules(
macroPtr: UnsafeMutablePointer<UInt8>,
modulesPtr: UnsafeMutablePointer<UnsafePointer<UInt8>?>,
modulesLengthPtr: UnsafeMutablePointer<Int>
) {
macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
let modules = macro.pointee.macro.supplementalSignatureModules
.joined(separator: ";")
(modulesPtr.pointee, modulesLengthPtr.pointee) =
allocateUTF8String(modules)
}
}
/// Query the macro evaluation context given the evaluation
/// context sources.
@_cdecl("swift_ASTGen_getMacroEvaluationContext")
public func getMacroEvaluationContext(
sourceFilePtr: UnsafePointer<UInt8>,
declContext: UnsafeMutableRawPointer,
context: UnsafeMutableRawPointer,
macroPtr: UnsafeMutablePointer<UInt8>,
contextPtr: UnsafeMutablePointer<UnsafeMutableRawPointer?>
) {
contextPtr.pointee = macroPtr.withMemoryRebound(to: ExportedMacro.self, capacity: 1) { macro in
return ASTGenVisitor(ctx: context, base: sourceFilePtr, declContext: declContext)
.visit(StructDeclSyntax(stringLiteral: macro.pointee.evaluationContext))
.rawValue
evaluatedSourceBuffer: UnsafePointer<UInt8>,
evaluatedSourceBufferLength: Int
) -> UnsafeMutableRawPointer? {
let evaluatedSource = UnsafeBufferPointer(
start: evaluatedSourceBuffer,
count: evaluatedSourceBufferLength
)
let sourceFile = Parser.parse(source: evaluatedSource)
// Dig out the top-level typealias declaration. That's all we'll
// parse.
guard let typealiasDecl = sourceFile.statements.first(
where: { item in item.item.is(TypealiasDeclSyntax.self)
})?.item.as(TypealiasDeclSyntax.self) else {
return nil
}
// Parse and ASTGen that top-level declaration.
// FIXME: we need to emit diagnostics from this.
return ASTGenVisitor(
ctx: context, base: sourceFilePtr, declContext: declContext
).visit(typealiasDecl).rawValue
}
@_cdecl("swift_ASTGen_evaluateMacro")

View File

@@ -69,4 +69,20 @@ public protocol _CompilerPlugin {
/// - Returns: A newly allocated buffer containing the type signature. The
/// caller is responsible for managing the memory.
static func _typeSignature() -> (UnsafePointer<UInt8>, count: Int)
/// Returns the module that owns this macro.
///
/// - Returns: A newly allocated buffer containing the owning module name. The
/// caller is responsible for managing the memory.
static func _owningModule() -> (UnsafePointer<UInt8>, count: Int)
/// Returns the set of modules that are needed (beyond the owning module) to
/// process the module signature.
///
/// - Returns: A newly allocated buffer containing a string with all of the
/// supplemental signature module names, separated by semicolons. The caller
/// is responsible for managing the memory.
static func _supplementalSignatureModules()
-> (UnsafePointer<UInt8>, count: Int)
}

View File

@@ -1825,6 +1825,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
Opts.EnableStackProtection =
Args.hasFlag(OPT_enable_stack_protector, OPT_disable_stack_protector,
Opts.EnableStackProtection);
Opts.EnableMoveInoutStackProtection =
Args.hasFlag(OPT_enable_move_inout_stack_protector, OPT_disable_stack_protector,
Opts.EnableMoveInoutStackProtection);
Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all);
Opts.VerifyNone |= Args.hasArg(OPT_sil_verify_none);
Opts.DebugSerialization |= Args.hasArg(OPT_sil_debug_serialization);

View File

@@ -1638,3 +1638,8 @@ SwiftInt SILOptions_enableStackProtection(BridgedPassContext context) {
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();
return mod->getOptions().EnableStackProtection;
}
SwiftInt SILOptions_enableMoveInoutStackProtection(BridgedPassContext context) {
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();
return mod->getOptions().EnableMoveInoutStackProtection;
}

View File

@@ -1200,7 +1200,8 @@ namespace {
if (!protocol)
return Type();
auto openedType = CS.getTypeOfMacroReference(kind, expr);
auto openedType = CS.getTypeOfMacroReference(
ctx.getIdentifier(kind), expr);
if (!openedType)
return Type();
@@ -3633,7 +3634,7 @@ namespace {
auto &ctx = CS.getASTContext();
if (ctx.LangOpts.hasFeature(Feature::Macros)) {
auto macroIdent = expr->getMacroName().getBaseIdentifier();
auto refType = CS.getTypeOfMacroReference(macroIdent.str(), expr);
auto refType = CS.getTypeOfMacroReference(macroIdent, expr);
if (!refType) {
ctx.Diags.diagnose(expr->getMacroNameLoc(), diag::macro_undefined,
macroIdent)

View File

@@ -24,6 +24,7 @@
#include "TypeChecker.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/Macro.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeCheckRequests.h"
@@ -2472,25 +2473,22 @@ ConstraintSystem::getTypeOfMemberReference(
}
#if SWIFT_SWIFT_PARSER
Type ConstraintSystem::getTypeOfMacroReference(StringRef macroName,
Type ConstraintSystem::getTypeOfMacroReference(Identifier macroName,
Expr *anchor) {
auto req = MacroContextRequest{macroName.str(), DC->getParentModule()};
auto *macroCtx = evaluateOrDefault(getASTContext().evaluator, req, nullptr);
if (!macroCtx)
auto req = MacroLookupRequest{macroName, DC->getParentModule()};
auto macros = evaluateOrDefault(getASTContext().evaluator, req, { });
if (macros.empty())
return Type();
auto *locator = getConstraintLocator(anchor);
// Dig through to __MacroEvaluationContext.SignatureType
auto sig = getASTContext().getIdentifier("SignatureType");
auto *signature = cast<TypeAliasDecl>(macroCtx->lookupDirect(sig).front());
auto type = signature->getUnderlyingType();
// FIXME: Handle macro overloading.
auto macro = macros.front();
// Open any the generic types.
OpenedTypeMap replacements;
openGeneric(signature->getParent(), signature->getGenericSignature(),
locator, replacements);
openGeneric(macro->owningModule, macro->genericSignature,
getConstraintLocator(anchor), replacements);
return openType(type, replacements);
return openType(macro->signature, replacements);
}
#endif

View File

@@ -19,8 +19,10 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/CompilerPlugin.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Macro.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "swift/Parse/Lexer.h"
@@ -32,54 +34,79 @@ extern "C" void *swift_ASTGen_lookupMacro(const char *macroName);
extern "C" void swift_ASTGen_destroyMacro(void *macro);
extern "C" void
extern "C" void *
swift_ASTGen_getMacroEvaluationContext(const void *sourceFile,
void *declContext, void *astContext,
void *macro, void **evaluationContext);
const char *evaluatedSource,
ptrdiff_t evaluatedSourceLength);
extern "C" ptrdiff_t swift_ASTGen_evaluateMacro(
void *sourceFile, const void *sourceLocation,
const char **evaluatedSource, ptrdiff_t *evaluatedSourceLength);
extern "C" void
swift_ASTGen_getMacroTypeSignature(void *macro,
const char **evaluationContextPtr,
ptrdiff_t *evaluationContextLengthPtr);
swift_ASTGen_getMacroGenericSignature(void *macro,
const char **genericSignaturePtr,
ptrdiff_t *genericSignatureLengthPtr);
extern "C" void
swift_ASTGen_getMacroTypeSignature(void *macro,
const char **signaturePtr,
ptrdiff_t *signatureLengthPtr);
extern "C" void
swift_ASTGen_getMacroOwningModule(void *macro,
const char **owningModuleNamePtr,
ptrdiff_t *owningModuleNameLengthPtr);
extern "C" void
swift_ASTGen_getMacroSupplementalSignatureModules(
void *macro, const char **moduleNamesPtr, ptrdiff_t *moduleNamesLengthPtr);
/// Create a new macro signature context buffer describing the macro signature.
///
/// The macro signature is a user-defined generic signature and return
/// type that serves as the "interface type" of references to the macro. The
/// current implementation takes those pieces of syntax from the macro itself,
/// then inserts them into a Swift typealias that looks like
///
/// \code
/// typealias __MacroEvaluationContext\(macro.genericSignature ?? "") =
/// \(macro.signature)
/// \endcode
///
/// So that we can use all of Swift's native name lookup and type resolution
/// facilities to map the parsed signature type back into a semantic
/// \c GenericSignature and \c Type ASTs. The macro signature source above is
/// provided via \c signatureSource.
static NullTerminatedStringRef
getPluginMacroTypeSignature(CompilerPlugin *plugin, ASTContext &ctx) {
auto genSig = plugin->invokeGenericSignature();
auto typeSig = plugin->invokeTypeSignature();
getMacroSignatureContextBuffer(
ASTContext &ctx, Optional<StringRef> genericSignature,
StringRef typeSignature
) {
std::string source;
llvm::raw_string_ostream out(source);
out << "struct __MacroEvaluationContext" << (genSig ? *genSig : "") << " {\n"
<< " typealias SignatureType = " << typeSig << "\n"
<< "}";
out << "typealias __MacroEvaluationContext"
<< (genericSignature ? *genericSignature : "")
<< " = " << typeSignature << "\n";
auto len = source.length();
auto *buffer = (char *)malloc(len + 1);
memcpy(buffer, source.data(), len + 1);
return {buffer, len};
}
StructDecl *MacroContextRequest::evaluate(Evaluator &evaluator,
std::string macroName,
ModuleDecl *mod) const {
#if SWIFT_SWIFT_PARSER
auto &ctx = mod->getASTContext();
auto *builtinMacro = swift_ASTGen_lookupMacro(macroName.c_str());
NullTerminatedStringRef evaluatedSource;
if (builtinMacro) {
const char *evaluatedSourcePtr;
ptrdiff_t evaluatedSourceLength;
swift_ASTGen_getMacroTypeSignature(builtinMacro, &evaluatedSourcePtr,
&evaluatedSourceLength);
evaluatedSource = NullTerminatedStringRef(
evaluatedSourcePtr, (size_t)evaluatedSourceLength);
} else if (auto *plugin = ctx.getLoadedPlugin(macroName)) {
evaluatedSource = getPluginMacroTypeSignature(plugin, ctx);
} else {
return nullptr;
}
/// Compute the macro signature for a macro given the source code for its
/// generic signature and type signature.
static Optional<std::pair<GenericSignature, Type>>
getMacroSignature(
ModuleDecl *mod, Identifier macroName,
Optional<StringRef> genericSignature,
StringRef typeSignature
) {
// Form a buffer containing the macro signature context.
ASTContext &ctx = mod->getASTContext();
StringRef signatureSource = getMacroSignatureContextBuffer(
ctx, genericSignature, typeSignature);
// Create a new source buffer with the contents of the macro's
// signature.
@@ -90,39 +117,211 @@ StructDecl *MacroContextRequest::evaluate(Evaluator &evaluator,
out << "Macro signature of #" << macroName;
}
auto macroBuffer = llvm::MemoryBuffer::getMemBuffer(
evaluatedSource, bufferName);
signatureSource, bufferName);
// FIXME: We should tell the source manager that this is a macro signature
// buffer.
unsigned macroBufferID =
sourceMgr.addNewSourceBuffer(std::move(macroBuffer));
auto macroSourceFile = new (ctx) SourceFile(
*mod, SourceFileKind::Library, macroBufferID);
mod->addAuxiliaryFile(*macroSourceFile);
// Make sure implicit imports are resolved in this file.
performImportResolution(*macroSourceFile);
// FIXME: Inject imports, which we don't yet have everywhere.
// Parse the struct declaration used for the macro evaluation context.
auto *start = sourceMgr.getLocForBufferStart(macroBufferID)
.getOpaquePointerValue();
if (builtinMacro) {
void *context = nullptr;
swift_ASTGen_getMacroEvaluationContext(
(const void *)start, (void *)(DeclContext *)macroSourceFile,
(void *)&ctx, builtinMacro, &context);
ctx.addCleanup([builtinMacro]() {
swift_ASTGen_destroyMacro(builtinMacro);
});
return dyn_cast<StructDecl>((Decl *)context);
} else {
Parser parser(macroBufferID, *macroSourceFile, &ctx.Diags, nullptr,
nullptr);
parser.consumeTokenWithoutFeedingReceiver();
DeclAttributes attrs;
auto parsedResult = parser.parseDeclStruct(Parser::PD_Default, attrs);
if (parsedResult.isParseError() || parsedResult.isNull())
return nullptr; // TODO: Diagnose this properly.
return parsedResult.get();
}
#else
auto decl = (Decl *)swift_ASTGen_getMacroEvaluationContext(
start, (DeclContext *)macroSourceFile,
&ctx, signatureSource.data(), signatureSource.size());
if (!decl)
return None;
// Make sure imports are resolved in this file.
performImportResolution(*macroSourceFile);
auto typealias = cast<TypeAliasDecl>(decl);
return std::make_pair(
typealias->getGenericSignature(), typealias->getUnderlyingType());
}
/// Create a macro.
static Macro *createMacro(
ModuleDecl *mod, Identifier macroName,
Macro::ImplementationKind implKind,
Optional<StringRef> genericSignature, StringRef typeSignature,
StringRef owningModuleName,
ArrayRef<StringRef> supplementalImportModuleNames,
void* opaqueHandle
) {
ASTContext &ctx = mod->getASTContext();
// Look up the owning module.
ModuleDecl *owningModule = ctx.getLoadedModule(
ctx.getIdentifier(owningModuleName));
if (!owningModule) {
// FIXME: diagnostic here
return nullptr;
}
// FIXME: Check that mod imports owningModule
// Look up all of the supplemental import modules.
SmallVector<ModuleDecl *, 1> supplementalImportModules;
for (auto supplementalModuleName : supplementalImportModuleNames) {
auto supplementalModuleId = ctx.getIdentifier(supplementalModuleName);
if (auto supplementalModule = ctx.getLoadedModule(supplementalModuleId)) {
supplementalImportModules.push_back(supplementalModule);
// FIXME: Check that mod imports supplementalModule somewhere.
}
}
// Get the type signature of the macro.
auto signature = getMacroSignature(
mod, macroName, genericSignature, typeSignature);
if (!signature) {
// FIXME: Swap in ErrorTypes, perhaps?
return nullptr;
}
// FIXME: All macros are expression macros right now
return new (ctx) Macro(
Macro::Expression, implKind, macroName,
signature->first, signature->second,
owningModule, supplementalImportModules,
opaqueHandle);
}
/// Create a builtin macro.
static Macro *createBuiltinMacro(
ModuleDecl *mod, Identifier macroName, void *opaqueHandle) {
// Get the macro generic signature.
const char *genericSignaturePtr;
ptrdiff_t genericSignatureLength;
swift_ASTGen_getMacroGenericSignature(opaqueHandle, &genericSignaturePtr,
&genericSignatureLength);
SWIFT_DEFER {
free((void*)genericSignaturePtr);
};
Optional<StringRef> genericSignature;
if (genericSignaturePtr && genericSignatureLength)
genericSignature = StringRef(genericSignaturePtr, genericSignatureLength);
// Get the macro type signature.
const char *typeSignaturePtr;
ptrdiff_t typeSignatureLength;
swift_ASTGen_getMacroTypeSignature(opaqueHandle, &typeSignaturePtr,
&typeSignatureLength);
SWIFT_DEFER {
free((void*)typeSignaturePtr);
};
StringRef typeSignature = StringRef(typeSignaturePtr, typeSignatureLength);
// Get the owning module name.
const char *owningModuleNamePtr;
ptrdiff_t owningModuleNameLength;
swift_ASTGen_getMacroOwningModule(opaqueHandle, &owningModuleNamePtr,
&owningModuleNameLength);
SWIFT_DEFER {
free((void*)owningModuleNamePtr);
};
StringRef owningModuleName = StringRef(
owningModuleNamePtr, owningModuleNameLength);
// Get the supplemental signature module names.
const char *supplementalModuleNamesPtr;
ptrdiff_t supplementalModuleNamesLength;
swift_ASTGen_getMacroSupplementalSignatureModules(
opaqueHandle, &supplementalModuleNamesPtr,
&supplementalModuleNamesLength);
SWIFT_DEFER {
free((void*)supplementalModuleNamesPtr);
};
SmallVector<StringRef, 2> supplementalModuleNames;
StringRef(owningModuleNamePtr, owningModuleNameLength)
.split(supplementalModuleNames, ";", -1, false);
return createMacro(
mod, macroName, Macro::ImplementationKind::Builtin,
genericSignature, typeSignature,
owningModuleName, supplementalModuleNames,
opaqueHandle);
}
/// Create a plugin-based macro.
static Macro *createPluginMacro(
ModuleDecl *mod, Identifier macroName, CompilerPlugin *plugin) {
auto genSignature = plugin->invokeGenericSignature();
SWIFT_DEFER {
if (genSignature)
free((void*)genSignature->data());
};
auto typeSignature = plugin->invokeTypeSignature();
SWIFT_DEFER {
free((void*)typeSignature.data());
};
auto owningModuleName = plugin->invokeOwningModule();
SWIFT_DEFER {
free((void*)owningModuleName.data());
};
// Get the supplemental signature module names.
auto supplementalModuleNamesStr =
plugin->invokeSupplementalSignatureModules();
SWIFT_DEFER {
free((void*)supplementalModuleNamesStr.data());
};
SmallVector<StringRef, 2> supplementalModuleNames;
supplementalModuleNamesStr
.split(supplementalModuleNames, ";", -1, false);
return createMacro(
mod, macroName, Macro::ImplementationKind::Plugin, genSignature,
typeSignature, owningModuleName, supplementalModuleNames, plugin);
}
ArrayRef<Macro *> MacroLookupRequest::evaluate(
Evaluator &evaluator, Identifier macroName, ModuleDecl *mod
) const {
#if SWIFT_SWIFT_PARSER
ASTContext &ctx = mod->getASTContext();
SmallVector<Macro *, 2> macros;
// Look for a builtin macro with this name.
if (auto *builtinHandle = swift_ASTGen_lookupMacro(
macroName.str().str().c_str())) {
if (auto builtinMacro = createBuiltinMacro(mod, macroName, builtinHandle)) {
macros.push_back(builtinMacro);
// Make sure we clean up after the macro.
ctx.addCleanup([builtinHandle]() {
swift_ASTGen_destroyMacro(builtinHandle);
});
} else {
// Destroy the builtin macro handle now; nothing references it.
swift_ASTGen_destroyMacro(builtinHandle);
}
}
// Look for a loaded plugin based on the macro name.
// FIXME: This API needs to be able to return multiple plugins, because
// several plugins could export a macro with the same name.
if (auto *plugin = ctx.getLoadedPlugin(macroName.str())) {
if (auto pluginMacro = createPluginMacro(mod, macroName, plugin)) {
macros.push_back(pluginMacro);
}
}
return ctx.AllocateCopy(macros);
#else
return { };
#endif // SWIFT_SWIFT_PARSER
}
@@ -145,6 +344,9 @@ Expr *swift::expandMacroExpr(
// Evaluate the macro.
NullTerminatedStringRef evaluatedSource;
// FIXME: The caller should tell us what macro is being expanded, so we
// don't do this lookup again.
// Built-in macros go through `MacroSystem` in Swift Syntax linked to this
// compiler.
if (auto *macro = swift_ASTGen_lookupMacro(macroName.str().c_str())) {

View File

@@ -28,6 +28,24 @@ struct StringifyMacro: _CompilerPlugin {
}
}
static func _owningModule() -> (UnsafePointer<UInt8>, count: Int) {
var swiftModule = "Swift"
return swiftModule.withUTF8 { buffer in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
result.initialize(from: buffer.baseAddress!, count: buffer.count)
return (UnsafePointer(result), count: buffer.count)
}
}
static func _supplementalSignatureModules() -> (UnsafePointer<UInt8>, count: Int) {
var nothing = ""
return nothing.withUTF8 { buffer in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
result.initialize(from: buffer.baseAddress!, count: buffer.count)
return (UnsafePointer(result), count: buffer.count)
}
}
static func _kind() -> _CompilerPluginKind {
.expressionMacro
}

View File

@@ -29,6 +29,24 @@ struct DummyMacro: _CompilerPlugin {
}
}
static func _owningModule() -> (UnsafePointer<UInt8>, count: Int) {
var swiftModule = "Swift"
return swiftModule.withUTF8 { buffer in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
result.initialize(from: buffer.baseAddress!, count: buffer.count)
return (UnsafePointer(result), count: buffer.count)
}
}
static func _supplementalSignatureModules() -> (UnsafePointer<UInt8>, count: Int) {
var nothing = ""
return nothing.withUTF8 { buffer in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
result.initialize(from: buffer.baseAddress!, count: buffer.count)
return (UnsafePointer(result), count: buffer.count)
}
}
static func _kind() -> _CompilerPluginKind {
.expressionMacro
}

View File

@@ -1,5 +1,6 @@
// RUN: %target-sil-opt -wmo -stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MODULE
// RUN: %target-sil-opt -function-stack-protection -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=FUNCTION
// RUN: %target-sil-opt -wmo -stack-protection -enable-move-inout-stack-protector -enable-sil-verify-all %s | %FileCheck %s --check-prefix=CHECK --check-prefix=MOVE
// REQUIRES: swift_in_compiler
@@ -57,8 +58,7 @@ bb0:
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @function_local_stack_obj
// MODULE-NOT: copy_addr
// FUNCTION: copy_addr
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'function_local_stack_obj'
sil @function_local_stack_obj : $@convention(thin) () -> () {
bb0:
@@ -72,10 +72,8 @@ bb0:
return %r : $()
}
// MODULE-LABEL: sil @function_local_obj
// FUNCTION-LABEL: sil [stack_protection] @function_local_obj
// MODULE-NOT: copy_addr
// FUNCTION: copy_addr
// CHECK-LABEL: sil @function_local_obj
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'function_local_obj'
sil @function_local_obj : $@convention(thin) () -> () {
bb0:
@@ -89,12 +87,16 @@ bb0:
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @inout_with_unknown_callers1
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] %0 to [init] [[T]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[T]]
// CHECK: copy_addr [take] [[T]] to [init] %0 : $*Int64
// CHECK: dealloc_stack [[T]] : $*Int64
// MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers1
// MODULE-LABEL: sil @inout_with_unknown_callers1
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] %0 to [init] [[T]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[T]]
// MOVE: copy_addr [take] [[T]] to [init] %0 : $*Int64
// MOVE: dealloc_stack [[T]] : $*Int64
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK-MODULE: address_to_pointer [stack_protection] %0
// CHECK: } // end sil function 'inout_with_unknown_callers1'
sil @inout_with_unknown_callers1 : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
@@ -114,13 +116,17 @@ bb0(%0 : $*Int64):
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @inout_with_modify_access
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [dynamic] %0 : $*Int64
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[T]]
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// CHECK: dealloc_stack [[T]] : $*Int64
// MOVE-LABEL: sil [stack_protection] @inout_with_modify_access
// MODULE-LABEL: sil @inout_with_modify_access
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [dynamic] %0 : $*Int64
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[T]]
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// MOVE: dealloc_stack [[T]] : $*Int64
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK-MODULE: address_to_pointer [stack_protection] %0
// CHECK: } // end sil function 'inout_with_modify_access'
sil @inout_with_modify_access : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
@@ -145,15 +151,18 @@ bb0(%0 : $*Int64):
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @inout_with_unknown_callers2
// CHECK: [[T:%[0-9]+]] = alloc_stack $S
// CHECK: copy_addr [take] %0 to [init] [[T]] : $*S
// CHECK: [[A:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.a
// CHECK: address_to_pointer [stack_protection] [[A]]
// CHECK: [[B:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.b
// CHECK: address_to_pointer [stack_protection] [[B]]
// CHECK: copy_addr [take] [[T]] to [init] %0 : $*S
// CHECK: dealloc_stack [[T]] : $*S
// MOVE-LABEL: sil [stack_protection] @inout_with_unknown_callers2
// MODULE-LABEL: sil @inout_with_unknown_callers2
// MOVE: [[T:%[0-9]+]] = alloc_stack $S
// MOVE: copy_addr [take] %0 to [init] [[T]] : $*S
// MOVE: [[A:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.a
// MOVE: address_to_pointer [stack_protection] [[A]]
// MOVE: [[B:%[0-9]+]] = struct_element_addr [[T]] : $*S, #S.b
// MOVE: address_to_pointer [stack_protection] [[B]]
// MOVE: copy_addr [take] [[T]] to [init] %0 : $*S
// MOVE: dealloc_stack [[T]] : $*S
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'inout_with_unknown_callers2'
sil @inout_with_unknown_callers2 : $@convention(thin) (@inout S) -> () {
bb0(%0 : $*S):
@@ -165,15 +174,18 @@ bb0(%0 : $*S):
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers1
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[T]]
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// CHECK: dealloc_stack [[T]] : $*Int64
// CHECK: end_access [[A]] : $*Int64
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers1
// MODULE-LABEL: sil @object_with_unknown_callers1
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[T]]
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// MOVE: dealloc_stack [[T]] : $*Int64
// MOVE: end_access [[A]] : $*Int64
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'object_with_unknown_callers1'
sil @object_with_unknown_callers1 : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
@@ -185,16 +197,19 @@ bb0(%0 : $C):
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers2
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// CHECK: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// CHECK: [[T:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[T]]
// CHECK: address_to_pointer [stack_protection] [[T]]
// CHECK: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// CHECK: dealloc_stack [[T]] : $*Int64
// CHECK: end_access [[A]] : $*Int64
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers2
// MODULE-LABEL: sil @object_with_unknown_callers2
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// MOVE: [[A:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// MOVE: [[T:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] [[A]] to [init] [[T]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[T]]
// MOVE: address_to_pointer [stack_protection] [[T]]
// MOVE: copy_addr [take] [[T]] to [init] [[A]] : $*Int64
// MOVE: dealloc_stack [[T]] : $*Int64
// MOVE: end_access [[A]] : $*Int64
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'object_with_unknown_callers2'
sil @object_with_unknown_callers2 : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
@@ -207,23 +222,26 @@ bb0(%0 : $C):
return %r : $()
}
// CHECK-LABEL: sil [stack_protection] @object_with_unknown_callers3
// CHECK: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// CHECK: [[AI:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// CHECK: [[TI:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] [[AI]] to [init] [[TI]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[TI]]
// CHECK: [[J:%[0-9]+]] = ref_element_addr %0 : $C, #C.j
// CHECK: [[AJ:%[0-9]+]] = begin_access [modify] [static] [[J]] : $*Int64
// CHECK: [[TJ:%[0-9]+]] = alloc_stack $Int64
// CHECK: copy_addr [take] [[AJ]] to [init] [[TJ]] : $*Int64
// CHECK: copy_addr [take] [[TI]] to [init] [[AI]] : $*Int64
// CHECK: end_access [[AI]] : $*Int64
// CHECK: address_to_pointer [stack_protection] [[TJ]]
// CHECK: copy_addr [take] [[TJ]] to [init] [[AJ]] : $*Int64
// CHECK: dealloc_stack [[TJ]] : $*Int64
// CHECK: dealloc_stack [[TI]] : $*Int64
// CHECK: end_access [[AJ]] : $*Int64
// MOVE-LABEL: sil [stack_protection] @object_with_unknown_callers3
// MODULE-LABEL: sil @object_with_unknown_callers3
// MOVE: [[I:%[0-9]+]] = ref_element_addr %0 : $C, #C.i
// MOVE: [[AI:%[0-9]+]] = begin_access [modify] [static] [[I]] : $*Int64
// MOVE: [[TI:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] [[AI]] to [init] [[TI]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[TI]]
// MOVE: [[J:%[0-9]+]] = ref_element_addr %0 : $C, #C.j
// MOVE: [[AJ:%[0-9]+]] = begin_access [modify] [static] [[J]] : $*Int64
// MOVE: [[TJ:%[0-9]+]] = alloc_stack $Int64
// MOVE: copy_addr [take] [[AJ]] to [init] [[TJ]] : $*Int64
// MOVE: copy_addr [take] [[TI]] to [init] [[AI]] : $*Int64
// MOVE: end_access [[AI]] : $*Int64
// MOVE: address_to_pointer [stack_protection] [[TJ]]
// MOVE: copy_addr [take] [[TJ]] to [init] [[AJ]] : $*Int64
// MOVE: dealloc_stack [[TJ]] : $*Int64
// MOVE: dealloc_stack [[TI]] : $*Int64
// MOVE: end_access [[AJ]] : $*Int64
// MODULE-NOT: alloc_stack
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'object_with_unknown_callers3'
sil @object_with_unknown_callers3 : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
@@ -257,10 +275,8 @@ bb0(%0 : $C):
return %r : $()
}
// MODULE-LABEL: sil hidden @known_callers_inout
// FUNCTION-LABEL: sil hidden [stack_protection] @known_callers_inout
// MODULE-NOT: copy_addr
// FUNCTION: copy_addr
// CHECK-LABEL: sil hidden @known_callers_inout
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'known_callers_inout'
sil hidden @known_callers_inout : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
@@ -315,9 +331,11 @@ bb3:
return %4 : $()
}
// CHECK-LABEL: sil hidden [stack_protection] @unknown_callers
// CHECK: copy_addr
// CHECK: copy_addr
// MOVE-LABEL: sil hidden [stack_protection] @unknown_callers
// MODULE-LABEL: sil hidden @unknown_callers
// MOVE: copy_addr
// MOVE: copy_addr
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'unknown_callers'
sil hidden @unknown_callers : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
@@ -341,10 +359,35 @@ bb0(%0 : $*Int64):
return %4 : $()
}
// MODULE-LABEL: sil hidden @known_callers_obj1
// FUNCTION-LABEL: sil hidden [stack_protection] @known_callers_obj1
// MOVE-LABEL: sil [stack_protection] @partially_known_callers
// MODULE-LABEL: sil @partially_known_callers
// MOVE: copy_addr
// MOVE: copy_addr
// MODULE-NOT: copy_addr
// FUNCTION: copy_addr
// CHECK: } // end sil function 'partially_known_callers'
sil @partially_known_callers : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):
%1 = address_to_pointer [stack_protection] %0 : $*Int64 to $Builtin.RawPointer
%2 = tuple ()
return %2 : $()
}
// MOVE-LABEL: sil @call_partially_known_callers
// MODULE-LABEL: sil [stack_protection] @call_partially_known_callers
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'call_partially_known_callers'
sil @call_partially_known_callers : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Int64
%1 = function_ref @partially_known_callers : $@convention(thin) (@inout Int64) -> ()
%2 = apply %1(%0) : $@convention(thin) (@inout Int64) -> ()
dealloc_stack %0 : $*Int64
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: sil hidden @known_callers_obj1
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'known_callers_obj1'
sil hidden @known_callers_obj1 : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
@@ -390,10 +433,12 @@ bb3(%5 : $C):
return %r : $()
}
// CHECK-LABEL: sil hidden [stack_protection] @known_callers_obj2
// CHECK: alloc_stack
// CHECK: copy_addr
// CHECK: copy_addr
// MOVE-LABEL: sil hidden [stack_protection] @known_callers_obj2
// MODULE-LABEL: sil hidden @known_callers_obj2
// MOVE: alloc_stack
// MOVE: copy_addr
// MOVE: copy_addr
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'known_callers_obj2'
sil hidden @known_callers_obj2 : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
@@ -428,10 +473,8 @@ bb3(%5 : $C):
return %r : $()
}
// MODULE-LABEL: sil private @closure_with_inout_capture
// FUNCTION-LABEL: sil private [stack_protection] @closure_with_inout_capture
// MODULE-NOT: copy_addr
// FUNCTION: copy_addr
// CHECK-LABEL: sil private @closure_with_inout_capture
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'closure_with_inout_capture'
sil private @closure_with_inout_capture : $@convention(thin) (@inout_aliasable Int64) -> () {
bb0(%0 : $*Int64):
@@ -464,10 +507,12 @@ bb0:
return %12 : $()
}
// CHECK-LABEL: sil private [stack_protection] @closure_with_inout_arg
// CHECK: alloc_stack
// CHECK: copy_addr
// CHECK: copy_addr
// MOVE-LABEL: sil private [stack_protection] @closure_with_inout_arg
// MODULE-LABEL: sil private @closure_with_inout_arg
// MOVE: alloc_stack
// MOVE: copy_addr
// MOVE: copy_addr
// MODULE-NOT: copy_addr
// CHECK: } // end sil function 'closure_with_inout_arg'
sil private @closure_with_inout_arg : $@convention(thin) (@inout Int64) -> () {
bb0(%0 : $*Int64):

View File

@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -module-name=test -emit-sil %s -O -enable-stack-protector | %FileCheck %s
// RUN: %target-swift-frontend -module-name=test -emit-sil %s -O | %FileCheck %s --check-prefix=CHECK --check-prefix=DEFAULT
// RUN: %target-swift-frontend -module-name=test -enable-move-inout-stack-protector -emit-sil %s -O -enable-stack-protector | %FileCheck %s --check-prefix=CHECK --check-prefix=MOVE
// REQUIRES: swift_in_compiler
@@ -71,9 +72,11 @@ public func callOverflowInoutPointer() {
inoutWithKnownCaller(&x)
}
// CHECK-LABEL: sil [stack_protection] @$s4test22inoutWithUnknownCalleryySizF
// CHECK: copy_addr [take] {{.*}} to [init]
// CHECK: copy_addr [take] {{.*}} to [init]
// DEFAULT-LABEL: sil @$s4test22inoutWithUnknownCalleryySizF
// MOVE-LABEL: sil [stack_protection] @$s4test22inoutWithUnknownCalleryySizF
// MOVE: copy_addr [take] {{.*}} to [init]
// MOVE: copy_addr [take] {{.*}} to [init]
// DEFAULT-NOT: copy_addr
// CHECK: } // end sil function '$s4test22inoutWithUnknownCalleryySizF'
public func inoutWithUnknownCaller(_ x: inout Int) {
withUnsafeMutablePointer(to: &x) {

View File

@@ -148,6 +148,10 @@ static llvm::cl::opt<bool>
EnableSpeculativeDevirtualization("enable-spec-devirt",
llvm::cl::desc("Enable Speculative Devirtualization pass."));
static llvm::cl::opt<bool>
EnableMoveInoutStackProtection("enable-move-inout-stack-protector",
llvm::cl::desc("Enable the stack protector by moving values to temporaries."));
static llvm::cl::opt<bool> EnableOSSAModules(
"enable-ossa-modules",
llvm::cl::desc("Do we always serialize SIL in OSSA form? If "
@@ -607,6 +611,7 @@ int main(int argc, char **argv) {
SILOpts.checkSILModuleLeaks = true;
SILOpts.EnablePerformanceAnnotations = true;
SILOpts.EnableStackProtection = true;
SILOpts.EnableMoveInoutStackProtection = EnableMoveInoutStackProtection;
SILOpts.VerifyExclusivity = VerifyExclusivity;
if (EnforceExclusivity.getNumOccurrences() != 0) {