Fixed segmentation fault crash (#1198)

* Fixed glob segmentation fault

* Renamed AtomicDictionary to ThreadSafeDictionary

* Refactored ThreadSafeDictionary

* ThreadSafeDictionary replaced with ThreadSafeContainer

* Removed reader/writer

* ThreadSafeContainer replaced with Atomic
This commit is contained in:
Vladislav Lisyanskiy 2022-03-31 09:15:58 +04:00 committed by GitHub
parent be0c3c3926
commit 50aa8c51cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 8 deletions

View File

@ -8,6 +8,7 @@
### Fixed
- Fix Monterey macOS shell version, shell login flag for environments [#1167](https://github.com/yonaskolb/XcodeGen/issues/1167) @bimawa
- Fixed crash caused by a simultaneous write during a glob processing [#1177](https://github.com/yonaskolb/XcodeGen/issues/1177) @tr1ckyf0x
## 2.27.0

View File

@ -8,20 +8,45 @@
import Foundation
@propertyWrapper
struct Atomic<Value> {
private let queue = DispatchQueue(label: "com.xcodegencore.atomic")
public final class Atomic<Value> {
private var value: Value
init(wrappedValue: Value) {
private let queue = DispatchQueue(
label: "com.xcodegencore.atomic.\(UUID().uuidString)",
qos: .utility,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: .global()
)
public init(wrappedValue: Value) {
self.value = wrappedValue
}
var wrappedValue: Value {
public var wrappedValue: Value {
get {
return queue.sync { value }
queue.sync { value }
}
set {
queue.sync { value = newValue }
queue.async(flags: .barrier) { [weak self] in
self?.value = newValue
}
}
}
/// Allows us to get the actual `Atomic` instance with the $
/// prefix.
public var projectedValue: Atomic<Value> {
return self
}
/// Modifies the protected value using `closure`.
public func with<R>(
_ closure: (inout Value) throws -> R
) rethrows -> R {
try queue.sync(flags: .barrier) {
try closure(&value)
}
}
}

View File

@ -198,13 +198,17 @@ public class Glob: Collection {
var isDirectoryBool = ObjCBool(false)
let isDirectory = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectoryBool) && isDirectoryBool.boolValue
isDirectoryCache[path] = isDirectory
$isDirectoryCache.with { isDirectoryCache in
isDirectoryCache[path] = isDirectory
}
return isDirectory
}
private func clearCaches() {
isDirectoryCache.removeAll()
$isDirectoryCache.with { isDirectoryCache in
isDirectoryCache.removeAll()
}
}
private func paths(usingPattern pattern: String, includeFiles: Bool) -> [String] {

View File

@ -0,0 +1,39 @@
//
// AtomicTests.swift
//
//
// Created by Vladislav Lisianskii on 27.03.2022.
//
import XCTest
@testable import XcodeGenCore
final class AtomicTests: XCTestCase {
@Atomic private var atomicDictionary = [String: Int]()
func testSimultaneousWriteOrder() {
let group = DispatchGroup()
for index in (0..<100) {
group.enter()
DispatchQueue.global().async {
self.$atomicDictionary.with { atomicDictionary in
atomicDictionary["\(index)"] = index
}
group.leave()
}
}
group.notify(queue: .main, execute: {
var expectedValue = [String: Int]()
for index in (0..<100) {
expectedValue["\(index)"] = index
}
XCTAssertEqual(
self.atomicDictionary,
expectedValue
)
})
}
}