-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[mlir] Fix DistinctAttributeUniquer deleting attribute storage when crash reproduction is enabled #128566
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
[mlir] Fix DistinctAttributeUniquer deleting attribute storage when crash reproduction is enabled #128566
Changes from 5 commits
b4a909e
55a7a38
8ace71b
d611dba
3792201
68843d5
8baecc9
e7fd522
7fffb59
da4e176
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,9 @@ | |
#include "mlir/Support/ThreadLocalCache.h" | ||
#include "llvm/ADT/APFloat.h" | ||
#include "llvm/ADT/PointerIntPair.h" | ||
#include "llvm/Support/ErrorHandling.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need error handling? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is left over from a previous commit, apologies. I would like to clarify though, since clangd tells me there are other headers unused here, shall I remove those too as an en-passant tidy? Notably,
|
||
#include "llvm/Support/TrailingObjects.h" | ||
#include <mutex> | ||
|
||
namespace mlir { | ||
namespace detail { | ||
|
@@ -401,7 +403,8 @@ class DistinctAttributeUniquer { | |
/// is freed after the destruction of the distinct attribute allocator. | ||
class DistinctAttributeAllocator { | ||
public: | ||
DistinctAttributeAllocator() = default; | ||
DistinctAttributeAllocator() | ||
: useThreadLocalAllocator(true), useSynchronizedAllocator(false) {}; | ||
|
||
DistinctAttributeAllocator(DistinctAttributeAllocator &&) = delete; | ||
DistinctAttributeAllocator(const DistinctAttributeAllocator &) = delete; | ||
|
@@ -411,12 +414,56 @@ class DistinctAttributeAllocator { | |
/// Allocates a distinct attribute storage using a thread local bump pointer | ||
/// allocator to enable synchronization free parallel allocations. | ||
DistinctAttrStorage *allocate(Attribute referencedAttr) { | ||
return new (allocatorCache.get().Allocate<DistinctAttrStorage>()) | ||
DistinctAttrStorage(referencedAttr); | ||
if (useSynchronizedAllocator && !useThreadLocalAllocator) { | ||
std::scoped_lock<std::mutex> lock(allocatorMutex); | ||
return allocateImpl(referencedAttr); | ||
} | ||
if (!useSynchronizedAllocator) | ||
return allocateImpl(referencedAttr); | ||
llvm_unreachable( | ||
"Cannot use both a synchronised and thread_local allocator!"); | ||
abulavin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// Sets flags to use thread local bump pointer allocators or a single | ||
/// non-thread safe bump pointer allocator depending on if multi-threading is | ||
/// enabled. Use this to disable the use of thread local storage and bypass | ||
/// thread safety synchronization overhead. | ||
abulavin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void disableMultiThreading(bool disable = true) { | ||
disableThreadLocalStorage(disable); | ||
useSynchronizedAllocator = !disable; | ||
abulavin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// Sets flags to disable using thread local bump pointer allocators and use a | ||
/// single thread-safe allocator. Use this to persist allocated storage beyond | ||
/// the lifetime of a child thread calling this function while ensuring | ||
/// thread-safe allocation. | ||
abulavin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void disableThreadLocalStorage(bool disable = true) { | ||
useThreadLocalAllocator = !disable; | ||
useSynchronizedAllocator = disable; | ||
} | ||
|
||
private: | ||
DistinctAttrStorage *allocateImpl(Attribute referencedAttr) { | ||
return new (getAllocatorInUse().Allocate<DistinctAttrStorage>()) | ||
DistinctAttrStorage(referencedAttr); | ||
} | ||
|
||
/// If threading is disabled on the owning MLIR context, a normal non | ||
/// thread-local, non-thread safe bump pointer allocator is used instead to | ||
/// prevent use-after-free errors whenever attribute storage created on a | ||
/// crash recover thread is accessed after the thread joins. | ||
llvm::BumpPtrAllocator &getAllocatorInUse() { | ||
abulavin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (useThreadLocalAllocator) | ||
return allocatorCache.get(); | ||
return allocator; | ||
} | ||
|
||
ThreadLocalCache<llvm::BumpPtrAllocator> allocatorCache; | ||
llvm::BumpPtrAllocator allocator; | ||
std::mutex allocatorMutex; | ||
|
||
bool useThreadLocalAllocator : 1; | ||
bool useSynchronizedAllocator : 1; | ||
}; | ||
} // namespace detail | ||
} // namespace mlir | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Test that the enable-debug-info-scope-on-llvm-func pass can create its | ||
// distinct attributes when running in the crash reproducer thread. | ||
|
||
// RUN: mlir-opt --mlir-disable-threading --mlir-pass-pipeline-crash-reproducer=. \ | ||
// RUN: --pass-pipeline="builtin.module(ensure-debug-info-scope-on-llvm-func)" \ | ||
// RUN: --mlir-print-debuginfo %s | FileCheck %s | ||
|
||
// RUN: mlir-opt --mlir-pass-pipeline-crash-reproducer=. \ | ||
// RUN: --pass-pipeline="builtin.module(ensure-debug-info-scope-on-llvm-func)" \ | ||
// RUN: --mlir-print-debuginfo %s | FileCheck %s | ||
|
||
module { | ||
llvm.func @func_no_debug() { | ||
llvm.return loc(unknown) | ||
} loc(unknown) | ||
} loc(unknown) | ||
|
||
// CHECK-LABEL: llvm.func @func_no_debug() | ||
// CHECK: llvm.return loc(#loc | ||
// CHECK: loc(#loc[[LOC:[0-9]+]]) | ||
// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, | ||
// CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// This test verifies that when running with crash reproduction enabled, distinct | ||
// attribute storage is not allocated in thread-local storage. Since crash | ||
// reproduction runs the pass manager in a separate thread, using thread-local | ||
// storage for distinct attributes causes use-after-free errors once the thread | ||
// that runs the pass manager joins. | ||
|
||
// RUN: mlir-opt --mlir-disable-threading --mlir-pass-pipeline-crash-reproducer=. %s -test-distinct-attrs | FileCheck %s | ||
// RUN: mlir-opt --mlir-pass-pipeline-crash-reproducer=. %s -test-distinct-attrs | FileCheck %s | ||
|
||
// CHECK: #[[DIST0:.*]] = distinct[0]<42 : i32> | ||
// CHECK: #[[DIST1:.*]] = distinct[1]<42 : i32> | ||
#distinct = distinct[0]<42 : i32> | ||
|
||
// CHECK: @foo_1 | ||
func.func @foo_1() { | ||
// CHECK: "test.op"() {distinct.input = #[[DIST0]], distinct.output = #[[DIST1]]} | ||
"test.op"() {distinct.input = #distinct} : () -> () | ||
} |
Uh oh!
There was an error while loading. Please reload this page.