Skip to content

Commit 8064187

Browse files
authored
Merge pull request #2438 from Lukasa/cb-scudo
Add support for the Scudo sanitizer.
2 parents 617c8a7 + 594ccaa commit 8064187

File tree

10 files changed

+112
-1
lines changed

10 files changed

+112
-1
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// swift-tools-version:5.1
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "double-free",
7+
targets: [
8+
.target(
9+
name: "lib",
10+
dependencies: []),
11+
.target(
12+
name: "exec",
13+
dependencies: ["lib"]),
14+
.testTarget(
15+
name: "libTests",
16+
dependencies: ["lib"]),
17+
]
18+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# double-free
2+
3+
A description of this package.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import lib
2+
3+
executeDoubleFree()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
public func executeDoubleFree() {
2+
let size = 512
3+
4+
let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: size, alignment: 1)
5+
buffer[0] = 0
6+
buffer.deallocate()
7+
buffer.deallocate()
8+
print(buffer[0])
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
3+
import libTests
4+
5+
var tests = [XCTestCaseEntry]()
6+
tests += libTests.__allTests()
7+
8+
XCTMain(tests)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import XCTest
2+
3+
extension libTests {
4+
static let __allTests = [
5+
("testDoubleFree", testDoubleFree),
6+
]
7+
}
8+
9+
#if !os(macOS)
10+
public func __allTests() -> [XCTestCaseEntry] {
11+
return [
12+
testCase(libTests.__allTests),
13+
]
14+
}
15+
#endif
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
import lib
3+
4+
final class libTests: XCTestCase {
5+
func testDoubleFree() {
6+
executeDoubleFree()
7+
}
8+
}

Sources/SPMBuildCore/Sanitizers.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ public enum Sanitizer: String, Encodable {
1616
case address
1717
case thread
1818
case undefined
19+
case scudo
1920

2021
/// Return an established short name for a sanitizer, e.g. "asan".
2122
public var shortName: String {
2223
switch self {
2324
case .address: return "asan"
2425
case .thread: return "tsan"
2526
case .undefined: return "ubsan"
27+
case .scudo: return "scudo"
2628
}
2729
}
2830
}
@@ -72,6 +74,7 @@ extension Sanitizer: StringEnumArgument {
7274
public static let completion: ShellCompletion = .values([
7375
(address.rawValue, "enable Address sanitizer"),
7476
(thread.rawValue, "enable Thread sanitizer"),
75-
(undefined.rawValue, "enable Undefined Behavior sanitizer")
77+
(undefined.rawValue, "enable Undefined Behavior sanitizer"),
78+
(scudo.rawValue, "enable Scudo hardened allocator")
7679
])
7780
}

Tests/CommandsTests/RunToolTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,27 @@ final class RunToolTests: XCTestCase {
128128
}
129129
#endif
130130
}
131+
132+
func testSanitizeScudo() throws {
133+
// Scudo is only supported on Linux.
134+
#if os(Linux)
135+
fixture(name: "Miscellaneous/DoubleFree") { path in
136+
// Ensure that we don't abort() when we find the race. This avoids
137+
// generating the crash report on macOS.
138+
let cmdline = {
139+
try SwiftPMProduct.SwiftRun.execute(
140+
["--sanitize=scudo"], packagePath: path)
141+
}
142+
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
143+
switch error {
144+
case .executionFailure(_, _, let error):
145+
XCTAssertMatch(error, .contains("invalid chunk state"))
146+
return true
147+
default:
148+
return false
149+
}
150+
}
151+
}
152+
#endif
153+
}
131154
}

Tests/CommandsTests/TestToolTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,25 @@ final class TestToolTests: XCTestCase {
8080
}
8181
#endif
8282
}
83+
84+
func testSanitizeScudo() throws {
85+
// This test only runs on Linux because Scudo only runs on Linux
86+
#if os(Linux)
87+
fixture(name: "Miscellaneous/DoubleFree") { path in
88+
let cmdline = {
89+
try SwiftPMProduct.SwiftTest.execute(
90+
["--sanitize=scudo"], packagePath: path)
91+
}
92+
XCTAssertThrows(try cmdline()) { (error: SwiftPMProductError) in
93+
switch error {
94+
case .executionFailure(_, _, let error):
95+
XCTAssertMatch(error, .contains("invalid chunk state"))
96+
return true
97+
default:
98+
return false
99+
}
100+
}
101+
}
102+
#endif
103+
}
83104
}

0 commit comments

Comments
 (0)