Skip to content

Commit ee5d555

Browse files
committed
Limit stack size. Provide procedure thread-max-stack to set maximum stack size.
1 parent 35dbaf9 commit ee5d555

File tree

13 files changed

+243
-159
lines changed

13 files changed

+243
-159
lines changed

LispKit.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5307,7 +5307,7 @@
53075307
repositoryURL = "https://github.com/weichsel/ZIPFoundation";
53085308
requirement = {
53095309
kind = upToNextMajorVersion;
5310-
minimumVersion = 0.9.14;
5310+
minimumVersion = 0.9.15;
53115311
};
53125312
};
53135313
/* End XCRemoteSwiftPackageReference section */

LispKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@
5050
"kind" : "remoteSourceControl",
5151
"location" : "https://github.com/weichsel/ZIPFoundation",
5252
"state" : {
53-
"revision" : "7254c74b49cec2cb81520523ba993c671f71b066",
54-
"version" : "0.9.14"
53+
"revision" : "f6a22e7da26314b38bf9befce34ae8e4b2543090",
54+
"version" : "0.9.15"
5555
}
5656
}
5757
],

Package.resolved

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
"repositoryURL": "https://github.com/weichsel/ZIPFoundation.git",
5252
"state": {
5353
"branch": null,
54-
"revision": "1b662e2e7a091710ad8a963263939984e2ebf527",
55-
"version": "0.9.14"
54+
"revision": "f6a22e7da26314b38bf9befce34ae8e4b2543090",
55+
"version": "0.9.15"
5656
}
5757
}
5858
]

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import PackageDescription
4141
let package = Package(
4242
name: "LispKit",
4343
platforms: [
44-
.macOS(.v10_13)
44+
.macOS(.v10_14)
4545
],
4646
products: [
4747
.library(name: "LispKit", targets: ["LispKit"]),
@@ -63,7 +63,7 @@ let package = Package(
6363
.upToNextMajor(from: "1.0.3")),
6464
.package(name: "ZIPFoundation",
6565
url: "https://github.com/weichsel/ZIPFoundation.git",
66-
.upToNextMajor(from: "0.9.14")),
66+
.upToNextMajor(from: "0.9.15")),
6767
.package(name: "swift-atomics",
6868
url: "https://github.com/apple/swift-atomics.git",
6969
.upToNextMajor(from: "1.0.2"))

Sources/LispKit/Compiler/EvalError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public enum EvalError: Int, Hashable {
9898
case cyclicImportExport
9999
case corruptLibrary
100100
case redefinitionOfImport
101+
case stackOverflow
101102
case unknownFile
102103
case unknownDirectory
103104
case unknownSystemDirectory
@@ -308,6 +309,8 @@ public enum EvalError: Int, Hashable {
308309
return "internal state of library $0 is corrupt ($,1)"
309310
case .redefinitionOfImport:
310311
return "redefinition of imported definition $0 in library $1"
312+
case .stackOverflow:
313+
return "stack overflow"
311314
case .unknownFile:
312315
return "file '$,0' unknown or a directory"
313316
case .unknownDirectory:

Sources/LispKit/Primitives/ThreadLibrary.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public final class ThreadLibrary: NativeLibrary {
6565
self.define(Procedure("thread-runnable?", self.isThreadRunnable))
6666
self.define(Procedure("thread-blocked?", self.isThreadBlocked))
6767
self.define(Procedure("thread-terminated?", self.isThreadTerminated))
68+
self.define(Procedure("thread-max-stack", self.threadMaxStack))
6869
self.define(Procedure("thread-start!", self.threadStart))
6970
self.define(Procedure("thread-yield!", self.threadYield))
7071
self.define(Procedure("thread-sleep!", self.threadSleep))
@@ -218,6 +219,50 @@ public final class ThreadLibrary: NativeLibrary {
218219
return .makeBoolean(try self.thread(from: th).value.state == .terminated)
219220
}
220221

222+
private func threadMaxStack(fst: Expr?, snd: Expr?) throws -> Expr {
223+
guard let snd = snd else {
224+
guard let fst = fst else {
225+
if let limit = self.context.evaluator.threads.current?.value.machine?.limitSp {
226+
return .makeNumber(limit)
227+
} else {
228+
return .false
229+
}
230+
}
231+
switch fst {
232+
case .fixnum(let limit):
233+
if let machine = self.context.evaluator.threads.current?.value.machine {
234+
if limit >= 1000 && limit <= Int64(Int.max) {
235+
_ = machine.setStackLimit(to: Int(limit))
236+
}
237+
return .makeNumber(machine.limitSp)
238+
} else {
239+
return .false
240+
}
241+
case .object(let obj):
242+
guard let nt = obj as? NativeThread else {
243+
throw RuntimeError.type(fst, expected: [NativeThread.type])
244+
}
245+
if let machine = nt.value.machine {
246+
return .makeNumber(machine.limitSp)
247+
} else {
248+
return .false
249+
}
250+
default:
251+
throw RuntimeError.type(fst, expected: [.fixnumType])
252+
}
253+
}
254+
let thread = try self.thread(from: fst!)
255+
let limit = try snd.asInt()
256+
if let machine = thread.value.machine {
257+
if limit >= 1000 {
258+
_ = machine.setStackLimit(to: limit)
259+
}
260+
return .makeNumber(machine.limitSp)
261+
} else {
262+
return .false
263+
}
264+
}
265+
221266
private func threadStart(th: Expr) throws -> Expr {
222267
let thread = try self.thread(from: th)
223268
try thread.value.start()

Sources/LispKit/Runtime/Context.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ open class Context {
9191
includeDocumentPath: String?,
9292
assetPath: String?,
9393
gcDelay: Double,
94-
features: [String]) {
94+
features: [String],
95+
limitStack: Int) {
9596
// Initialize components
9697
self.delegate = delegate
9798
self.implementationName = implementationName
@@ -116,7 +117,7 @@ open class Context {
116117
self.features = supported
117118
self.libraries = LibraryManager(for: self)
118119
self.environment = Environment(in: self)
119-
self.evaluator = Evaluator(for: self)
120+
self.evaluator = Evaluator(for: self, limitStack: limitStack)
120121
self.inputPort = Port(input: TextInput(source: delegate,
121122
abortionCallback: self.evaluator.isAbortionRequested))
122123
self.outputPort = Port(output: TextOutput(target: delegate, threshold: 0))

Sources/LispKit/Runtime/Evaluator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ public final class Evaluator: TrackedObject {
6363
/// All managed threads
6464
internal var threads = ThreadManager()
6565

66-
init(for context: Context) {
66+
init(for context: Context, limitStack: Int = 10000000) {
6767
self.context = context
68-
self.main = VirtualMachine(for: context)
68+
self.main = VirtualMachine(for: context, limitStack: limitStack)
6969
context.objects.manage(self.main)
7070
super.init()
7171
self.mainThread = NativeThread(EvalThread(worker: self))

Sources/LispKit/Runtime/LispKitContext.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public final class LispKitContext: Context {
5757
includeDocumentPath: String? = "LispKit",
5858
assetPath: String? = nil,
5959
gcDelay: Double = 5.0,
60-
features: [String] = []) {
60+
features: [String] = [],
61+
limitStack: Int = 10000000) {
6162
super.init(delegate: delegate,
6263
implementationName: implementationName ?? LispKitContext.implementationName,
6364
implementationVersion: implementationVersion ?? LispKitContext.implementationVersion,
@@ -67,6 +68,7 @@ public final class LispKitContext: Context {
6768
includeDocumentPath: includeDocumentPath,
6869
assetPath: assetPath,
6970
gcDelay: gcDelay,
70-
features: features)
71+
features: features,
72+
limitStack: limitStack)
7173
}
7274
}

0 commit comments

Comments
 (0)