Skip to content

[AutoDiff] Assertion failure due to "Found leaked temporary" #81607

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

Closed
kovdan01 opened this issue May 19, 2025 · 5 comments · Fixed by #81676
Closed

[AutoDiff] Assertion failure due to "Found leaked temporary" #81607

kovdan01 opened this issue May 19, 2025 · 5 comments · Fixed by #81676
Labels
AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software

Comments

@kovdan01
Copy link
Contributor

kovdan01 commented May 19, 2025

Description

With the reproducer provided below, we get an assertion failure in PullbackCloner when running mandatory Differentiation pass.

/path/to/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin/swift-frontend -emit-sil leak.swift

Reproduction

import _Differentiation

@differentiable(reverse)
func sum(_ a: Float, _ b: [Float]) -> [Float] {
  if b.count != 0 {
    return b
  }
  return [a]
}

Stack dump

[AD] Found leaked temporary:
  %90 = load [trivial] %10 : $*Float              // user: %95
[AD] Found leaked temporary:
  %103 = load [trivial] %91 : $*Float             // users: %180, %124
[AD] Found leaked temporary:
  %122 = load [take] %110 : $*Array<Float>.DifferentiableView
swift-frontend: /path/to/swift/swift/lib/SILOptimizer/Differentiation/PullbackCloner.cpp:2725: bool swift::autodiff::PullbackCloner::Implementation::run(): Assertion `!leakFound && "Leaks found!"' failed.
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0.	Program arguments: /path/to/swift/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin/swift-frontend -emit-sil leak.swift
1.	Swift version 6.2-dev (LLVM 94a95edd9aa32e1, Swift c4b0e97c11c5af6)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for leak)
4.	While running pass #33 SILModuleTransform "Differentiation".
5.	While processing // differentiability witness for sum(_:_:)
sil_differentiability_witness hidden [reverse] [parameters 0 1] [results 0] @$s4leak3sumySaySfGSf_ACtF : $@convention(thin) (Float, @guaranteed Array<Float>) -> @owned Array<Float> {
}

 on SIL function "@$s4leak3sumySaySfGSf_ACtF".
 for 'sum(_:_:)' (at leak.swift:4:1)
6.	While generating VJP for SIL function "@$s4leak3sumySaySfGSf_ACtF".
 for 'sum(_:_:)' (at leak.swift:4:1)
7.	While generating pullback for SIL function "@$s4leak3sumySaySfGSf_ACtF".
 for 'sum(_:_:)' (at leak.swift:4:1)
 #0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /path/to/swift/llvm-project/llvm/lib/Support/Unix/Signals.inc:728:13
 #1 llvm::sys::RunSignalHandlers() /path/to/swift/llvm-project/llvm/lib/Support/Signals.cpp:106:18
 #2 SignalHandler(int, siginfo_t*, void*) /path/to/swift/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #3 (/usr/lib/libc.so.6+0x3d600)
 #4 __pthread_kill_implementation /usr/src/debug/glibc/glibc/nptl/pthread_kill.c:44:76
 #5 raise /usr/src/debug/glibc/glibc/signal/../sysdeps/posix/raise.c:27:6
 #6 abort /usr/src/debug/glibc/glibc/stdlib/abort.c:81:3
 #7 __assert_perror_fail /usr/src/debug/glibc/glibc/assert/assert-perr.c:31:1
 #8 (/path/to/swift/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin/swift-frontend+0x1fef14a)
 #9 swift::autodiff::PullbackCloner::run() /path/to/swift/swift/lib/SILOptimizer/Differentiation/PullbackCloner.cpp:2122:7
#10 swift::autodiff::VJPCloner::Implementation::run() /path/to/swift/swift/lib/SILOptimizer/Differentiation/VJPCloner.cpp:1445:7
#11 swift::autodiff::VJPCloner::run() /path/to/swift/swift/lib/SILOptimizer/Differentiation/VJPCloner.cpp:1455:7
#12 (anonymous namespace)::DifferentiationTransformer::canonicalizeDifferentiabilityWitness(swift::SILDifferentiabilityWitness*, swift::autodiff::DifferentiationInvoker, swift::SerializedKind_t) /path/to/swift/swift/lib/SILOptimizer/Mandatory/Differentiation.cpp:1070:19
#13 (anonymous namespace)::Differentiation::run() /path/to/swift/swift/lib/SILOptimizer/Mandatory/Differentiation.cpp:1494:21
#14 llvm::SmallVectorTemplateCommon<swift::SILAnalysis*, void>::begin() /path/to/swift/llvm-project/llvm/include/llvm/ADT/SmallVector.h:281:45
#15 swift::SILPassManager::analysesUnlocked() /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:529:16
#16 swift::SILPassManager::runModulePass(unsigned int) /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:907:3
#17 swift::SILPassManager::execute() /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:1019:7
#18 __gnu_cxx::__normal_iterator<swift::SILPassPipeline const*, std::vector<swift::SILPassPipeline, std::allocator<swift::SILPassPipeline>>>::operator++() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../include/c++/15.1.1/bits/stl_iterator.h:1103:2
#19 swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:974:40
#20 swift::ExecuteSILPipelineRequest::evaluate(swift::Evaluator&, swift::SILPipelineExecutionDescriptor) const /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:384:1
#21 std::tuple<> swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::callDerived<0ul>(swift::Evaluator&, std::integer_sequence<unsigned long, 0ul>) const /path/to/swift/swift/include/swift/AST/SimpleRequest.h:287:24
#22 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) /path/to/swift/swift/include/swift/AST/SimpleRequest.h:311:20
#23 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'()) /path/to/swift/swift/include/swift/AST/Evaluator.h:0:19
#24 swift::executePassPipelinePlan(swift::SILModule*, swift::SILPassPipelinePlan const&, bool, swift::irgen::IRGenModule*) /path/to/swift/swift/lib/SILOptimizer/PassManager/PassManager.cpp:393:1
#25 std::_Vector_base<swift::SILPassPipeline, std::allocator<swift::SILPassPipeline>>::~_Vector_base() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../include/c++/15.1.1/bits/stl_vector.h:375:24
#26 std::vector<swift::SILPassPipeline, std::allocator<swift::SILPassPipeline>>::~vector() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../include/c++/15.1.1/bits/stl_vector.h:805:7
#27 swift::SILPassPipelinePlan::~SILPassPipelinePlan() /path/to/swift/swift/include/swift/SILOptimizer/PassManager/PassPipeline.h:73:34
#28 swift::runSILDiagnosticPasses(swift::SILModule&) /path/to/swift/swift/lib/SILOptimizer/PassManager/Passes.cpp:64:3
#29 swift::CompilerInstance::performSILProcessing(swift::SILModule*) /path/to/swift/swift/lib/Frontend/Frontend.cpp:1852:56
#30 performCompileStepsPostSILGen(swift::CompilerInstance&, std::unique_ptr<swift::SILModule, std::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:1750:7
#31 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:765:12
#32 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:1200:25
#33 performAction(swift::CompilerInstance&, int&, swift::FrontendObserver*) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:0:12
#34 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:1409:19
#35 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) /path/to/swift/swift/lib/FrontendTool/FrontendTool.cpp:0:19
#36 run_driver(llvm::StringRef, llvm::ArrayRef<char const*>, llvm::ArrayRef<char const*>) /path/to/swift/swift/lib/DriverTool/driver.cpp:0:0
#37 swift::mainEntry(int, char const**) /path/to/swift/swift/lib/DriverTool/driver.cpp:530:10
#38 __libc_start_call_main /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#39 call_init /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:128:20
#40 __libc_start_main /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:347:5
#41 _start (/path/to/swift/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin/swift-frontend+0xcf4095)

Expected behavior

No assertion failures should be present

Environment

Swift version 6.2-dev (LLVM 94a95edd9aa32e1, Swift c4b0e97)
Target: x86_64-unknown-linux-gnu
Build config: +assertions

Additional information

No response

@kovdan01 kovdan01 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 AutoDiff and removed triage needed This issue needs more specific labels labels May 19, 2025
@kovdan01
Copy link
Contributor Author

Tagging @asl @JaapWijnen

@asl
Copy link
Contributor

asl commented May 21, 2025

I'm seeing different assert (though this is with -Xllvm -debug-only=differentiation):

[ADJ] Emitted in pullback (pb bb0):
Assertion failed: (isa<SingleValueInstruction>(node) || isa<NonSingleValueInstruction>(node)), function asSILNode, file SILInstruction.h, line 982.

@kovdan01
Copy link
Contributor Author

I'm seeing different assert:

[ADJ] Emitted in pullback (pb bb0):
Assertion failed: (isa<SingleValueInstruction>(node) || isa<NonSingleValueInstruction>(node)), function asSILNode, file SILInstruction.h, line 982.

Hmm, it's interesting. I'm seeing that one about leaks (see initial issue description) on my machine (re-verified that right now). Just in case: I'm on commit c4b0e97 (merge PR81589).

And one more thought: since I'm on Linux, arrays are implemented differently, and this might affect the observed assertion.

@kovdan01
Copy link
Contributor Author

though this is with -Xllvm -debug-only=differentiation

With these arguments, I have the same assertion as you've mentioned

@asl
Copy link
Contributor

asl commented May 21, 2025

The original SIL is as follows:

sil hidden [ossa] @$s4main3sumySaySfGSf_ACtF : $@convention(thin) (Float, @guaranteed Array<Float>) -> @owned Array<Float> {
// %0 "a"                                         // users: %24, %2
// %1 "b"                                         // users: %15, %6, %3
bb0(%0 : $Float, %1 : @guaranteed $Array<Float>):
  debug_value %0, let, name "a", argno 1          // id: %2
  debug_value %1, let, name "b", argno 2          // id: %3
  %4 = metatype $@thin Int.Type                   // user: %12
  // function_ref Array.count.getter
  %5 = function_ref @$sSa5countSivg : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int // user: %6
  %6 = apply %5<Float>(%1) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int // user: %12
  %7 = integer_literal $Builtin.IntLiteral, 0     // user: %10
  %8 = metatype $@thin Int.Type                   // user: %10
  // function_ref Int.init(_builtinIntegerLiteral:)
  %9 = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int // user: %10
  %10 = apply %9(%7, %8) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int // user: %12
  // function_ref static Int.!= infix(_:_:)
  %11 = function_ref @$sSi2neoiySbSi_SitFZ : $@convention(method) (Int, Int, @thin Int.Type) -> Bool // user: %12
  %12 = apply %11(%6, %10, %4) : $@convention(method) (Int, Int, @thin Int.Type) -> Bool // user: %13
  %13 = struct_extract %12, #Bool._value          // user: %14
  cond_br %13, bb1, bb2                           // id: %14

bb1:                                              // Preds: bb0
  %15 = copy_value %1                             // user: %16
  br bb3(%15)                                     // id: %16

bb2:                                              // Preds: bb0
  %17 = integer_literal $Builtin.Word, 1          // user: %19
  // function_ref _allocateUninitializedArray<A>(_:)
  %18 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %19
  %19 = apply %18<Float>(%17) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %20
  (%20, %21) = destructure_tuple %19              // users: %26, %22, %22
  %22 = mark_dependence %21 on %20                // user: %23
  %23 = pointer_to_address %22 to [strict] $*Float // user: %24
  store %0 to [trivial] %23                       // id: %24
  // function_ref _finalizeUninitializedArray<A>(_:)
  %25 = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %26
  %26 = apply %25<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %27
  br bb3(%26)                                     // id: %27

// %28                                            // user: %29
bb3(%28 : @owned $Array<Float>):                  // Preds: bb2 bb1
  return %28                                      // id: %29
} // end sil function '$s4main3sumySaySfGSf_ACtF'

Activity info is stragihtforward:


bb2:
[USEFUL]   %17 = integer_literal $Builtin.Word, 1          // user: %19
[NONE]   // function_ref _allocateUninitializedArray<A>(_:)
  %18 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %19
[ACTIVE]   %19 = apply %18<Float>(%17) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %20
[ACTIVE] (**%20**, %21) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer) // users: %26, %22
[VARIED] (%20, **%21**) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer) // user: %22
[VARIED]   %22 = mark_dependence %21 : $Builtin.RawPointer on %20 : $Array<Float> // user: %23
[ACTIVE]   %23 = pointer_to_address %22 : $Builtin.RawPointer to [strict] $*Float // user: %24
[NONE]   // function_ref _finalizeUninitializedArray<A>(_:)
  %25 = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %26
[ACTIVE]   %26 = apply %25<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %27

We need to propagate adjoint of %20 to adjoint to %23 (via %21 and %22) in a reverse pass:

[ ]   br bb3(%26 : $Array<Float>)                     // id: %27
[x]   %26 = apply %25<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %27
[ ]   // function_ref _finalizeUninitializedArray<A>(_:)
  %25 = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %26
[x]   store %0 to [trivial] %23 : $*Float             // id: %24
[ ]   %23 = pointer_to_address %22 : $Builtin.RawPointer to [strict] $*Float // user: %24
[ ]   %22 = mark_dependence %21 : $Builtin.RawPointer on %20 : $Array<Float> // user: %23
[x]   (%20, %21) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer) // users: %26, %22, %22
[x]   %19 = apply %18<Float>(%17) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %20
[ ]   // function_ref _allocateUninitializedArray<A>(_:)
  %18 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %19
[ ]   %17 = integer_literal $Builtin.Word, 1          // user: %19

Looks like accumulateArrayLiteralElementAddressAdjoints for some reason unknown to me tries to do this accumulation in the BB where adjoint is defined. However, in this case adjoint comes from predecessor BB and therefore accumulation there is obviously wrong. I believe it was broken since the time we started to add "symbolic adjoints" and stopped to produce explicit copy_value to materialize adjoints the current BB. Looks like there was no test coverage for this case.

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

Successfully merging a pull request may close this issue.

2 participants