Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

block with inout parameter that returns a sending value crashes #75982

Open
mattmassicotte opened this issue Aug 20, 2024 · 5 comments
Open

block with inout parameter that returns a sending value crashes #75982

mattmassicotte opened this issue Aug 20, 2024 · 5 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features crash Bug: A crash, i.e., an abnormal termination of software

Comments

@mattmassicotte
Copy link
Contributor

Description

I think this has something to do with the inout + sending combination in the with function. Removing either allows the code to be processed succesfully.

Reproduction

public class Context {
	let value: Int

	init(value: Int) {
		self.value = value
	}
}

public struct Transaction {
	public static func with<T>(block: (inout Transaction) throws -> sending T) throws -> sending T {
		var txn = Transaction()

		return try block(&txn)
	}
}

actor MyActor {
	private var context = Context(value: 0)

	public func withContext<T>(_ block: sending (Context) throws -> T) async throws -> sending T {
		let value: T = try Transaction.with { txn in
			return try block(context)
		}

		// ERROR: returning 'self'-isolated 'value' as a 'sending' result risks causing data races
		return value
	}
}

Stack dump

1.	Apple Swift version 6.0-dev (LLVM 311c8b35213308e, Swift 488a207cc9d2994)
2.	Compiling with the current language version
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for test)
4.	While running pass #225 SILFunctionTransform "TransferNonSendable" on SILFunction "@$s4test7MyActorC11withContextyxxAA0E0CKXEYaKlFxAA11TransactionVzKYTXEfU_".
 for expression at [test.swift:21:39 - line:23:3] RangeText="{ txn in
			return try block(context)
		"
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000105d4eab4 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x0000000105d4d280 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000105d4f0fc SignalHandler(int) + 304
3  libsystem_platform.dylib 0x00000001965eb584 _sigtramp + 56
4  libsystem_pthread.dylib  0x00000001965bac20 pthread_kill + 288
5  libsystem_c.dylib        0x00000001964c7a30 abort + 180
6  libsystem_c.dylib        0x00000001964c6d20 err + 0
7  swift-frontend           0x0000000105f34d24 void swift::Diagnostic::gatherArgs<swift::DeclBaseName, bool, llvm::StringRef>(swift::DeclBaseName, bool, llvm::StringRef) (.cold.1) + 0
8  swift-frontend           0x00000001011e7e18 swift::ApplyInstBase<swift::TryApplyInst, swift::TryApplyInstBase, true>::getSelfArgument() const + 112
9  swift-frontend           0x00000001012862d0 (anonymous namespace)::TransferNonSendableImpl::emitDiagnostics() + 5784
10 swift-frontend           0x0000000101284a68 (anonymous namespace)::TransferNonSendable::run() + 528
11 swift-frontend           0x00000001012a916c swift::SILPassManager::runPassOnFunction(unsigned int, swift::SILFunction*) + 1432
12 swift-frontend           0x00000001012a9fd8 swift::SILPassManager::runFunctionPasses(unsigned int, unsigned int) + 1060
13 swift-frontend           0x00000001012ac744 swift::SILPassManager::execute() + 596
14 swift-frontend           0x00000001012a714c swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 72
15 swift-frontend           0x00000001012a70cc swift::ExecuteSILPipelineRequest::evaluate(swift::Evaluator&, swift::SILPipelineExecutionDescriptor) const + 68
16 swift-frontend           0x00000001012e24d4 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 28
17 swift-frontend           0x00000001012c2a30 swift::ExecuteSILPipelineRequest::OutputType swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()>(swift::ExecuteSILPipelineRequest const&, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()) + 204
18 swift-frontend           0x00000001012a7328 swift::executePassPipelinePlan(swift::SILModule*, swift::SILPassPipelinePlan const&, bool, swift::irgen::IRGenModule*) + 64
19 swift-frontend           0x00000001012c4ef8 swift::runSILDiagnosticPasses(swift::SILModule&) + 192
20 swift-frontend           0x0000000100ae3b94 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 80
21 swift-frontend           0x00000001008a2e70 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 796
22 swift-frontend           0x00000001008a276c swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1216
23 swift-frontend           0x00000001008ae248 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
24 swift-frontend           0x00000001008a4414 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 708
25 swift-frontend           0x00000001008a3ae8 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2344
26 swift-frontend           0x00000001006b8e5c swift::mainEntry(int, char const**) + 3096
27 dyld                     0x00000001962320e0 start + 2360

Expected behavior

I think it's still a little unclear if this code should actually compile cleanly or produce an error due to:

#75473

Environment

Apple Swift version 6.0-dev (LLVM 311c8b35213308e, Swift 488a207)
Target: arm64-apple-macosx14.0

Additional information

No response

@mattmassicotte mattmassicotte added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Aug 20, 2024
@hborla hborla added concurrency Feature: umbrella label for concurrency language features and removed triage needed This issue needs more specific labels labels Aug 20, 2024
@gottesmm
Copy link
Contributor

gottesmm commented Aug 24, 2024

This doesn't crash with my fix from #76076.

Now I get:

test.swift:22:15: error: returning 'self'-isolated 'self.context' as a 'sending' result risks causing data races
20 | 	public func withContext<T>(_ block: sending (Context) throws -> T) async throws -> sending T {
21 | 		let value: T = try Transaction.with { txn in
22 | 			return try block(context)
   |               |- error: returning 'self'-isolated 'self.context' as a 'sending' result risks causing data races
   |               `- note: returning 'self'-isolated 'self.context' risks causing data races since the caller assumes that 'self.context' can be safely sent to other isolation domains
23 | 		}
24 | 

There is something funky going on here. I am going out of town, I'll look further when I get back.

@gottesmm
Copy link
Contributor

I do think that there does need to be an error here, just the error is messed up in some way.

.with expects its closure parameter to have a sending result... so the closure has a sending result... but block does not have a sending result. So you are returning a non-sending thing into a sending thing. Since context is actor isolated and the result of body is not sending, I would expect its result to be actor isolated as well... and one cannot return an actor isolated value as a sending result.

@mattmassicotte
Copy link
Contributor Author

Yes, I agree with your analysis here. I think (hope) that had I not run into other issues, I would have figured that out myself. I'll be satisified with the crash resolved, but if you want to use this issue to look more closely at the error I'm all for it.

@gottesmm
Copy link
Contributor

Yes. While I am here, I want to fix this.

@mattmassicotte
Copy link
Contributor Author

Crash definitely fixed in the 6.1 snapshot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features crash Bug: A crash, i.e., an abnormal termination of software
Projects
None yet
Development

No branches or pull requests

3 participants