Skip to content

Commit 4c3eb71

Browse files
authored
Restrict filesystem reads during resolution phase (#5043)
Follow up to #5037, but for resolution phase rather than execution. We allow filesystem reads within `interp.watchValue` blocks, since those get properly handled w.r.t. `--watch` and other things Covered by updated integration tests. There are a few awkward existing violations that I grandfathered in for now
1 parent 337efb2 commit 4c3eb71

File tree

9 files changed

+64
-40
lines changed

9 files changed

+64
-40
lines changed

contrib/jmh/src/mill/contrib/jmh/JmhModule.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ trait JmhModule extends JavaModule {
4242
Jvm.callProcess(
4343
mainClass = "org.openjdk.jmh.Main",
4444
classPath = (runClasspath() ++ generatorDeps()).map(_.path) ++
45-
Seq(compileGeneratedSources().path, resources),
45+
Seq(compileGeneratedSources().path, resources.path),
4646
mainArgs = args,
4747
cwd = Task.ctx().dest,
4848
javaHome = jvmWorker().javaHome().map(_.path),
@@ -58,7 +58,7 @@ trait JmhModule extends JavaModule {
5858
Task {
5959
val dest = Task.ctx().dest
6060
val (sourcesDir, _) = generateBenchmarkSources()
61-
val sources = os.walk(sourcesDir).filter(os.isFile)
61+
val sources = os.walk(sourcesDir.path).filter(os.isFile)
6262

6363
os.proc(
6464
Jvm.jdkTool("javac"),
@@ -101,7 +101,7 @@ trait JmhModule extends JavaModule {
101101
stdout = os.Inherit
102102
)
103103

104-
(sourcesDir, resourcesDir)
104+
(PathRef(sourcesDir), PathRef(resourcesDir))
105105
}
106106

107107
def generatorDeps = Task {

core/constants/src/mill/constants/Util.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ public static String interpolateEnvVars(
124124
matcher.appendReplacement(result, "\\$");
125125
} else {
126126
String envVarValue;
127-
mill.constants.DebugLog.println("MATCH " + match);
128127
envVarValue = env.containsKey(match) ? env.get(match) : onMissing.apply(match);
129128
matcher.appendReplacement(result, envVarValue);
130129
}

core/define/src/mill/define/internal/ResolveChecker.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package mill.define.internal
22

33
class ResolveChecker(workspace: os.Path) extends os.Checker {
4-
def onRead(path: os.ReadablePath): Unit = ()
4+
def onRead(path: os.ReadablePath): Unit = {
5+
path match {
6+
case path: os.Path =>
7+
sys.error(s"Reading from ${path.relativeTo(workspace)} not allowed during resolution phase")
8+
case _ =>
9+
}
10+
}
511

612
def onWrite(path: os.Path): Unit = {
713
sys.error(s"Writing to ${path.relativeTo(workspace)} not allowed during resolution phase")

core/util/src/mill/util/Jvm.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,11 @@ object Jvm {
576576
artifactTypes,
577577
resolutionParams
578578
).map { res =>
579-
res.files
580-
.map(os.Path(_))
581-
.map(PathRef(_, quick = true))
579+
os.checker.withValue(os.Checker.Nop) {
580+
res.files
581+
.map(os.Path(_))
582+
.map(PathRef(_, quick = true))
583+
}
582584
}
583585

584586
def jvmIndex(
@@ -682,7 +684,6 @@ object Jvm {
682684
case cp =>
683685
cp.split(';').map { s =>
684686
val url = os.Path(s).toNIO.toUri.toURL
685-
mill.constants.DebugLog.println("MILL_LOCAL_TEST_OVERRIDE_CLASSPATH " + url)
686687
new java.net.URLClassLoader(Array(url))
687688
}.toList
688689
}

integration/failure/os-checker/src/OsCheckerTests.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ object OsCheckerTests extends UtestIntegrationTestSuite {
1010
import tester._
1111
val res = tester.eval("foo.bar")
1212

13-
val sep = if (mill.constants.Util.isWindows) "\\" else "/"
1413
assert(res.isSuccess == false)
1514
assert(res.err.contains(
1615
s"Writing to foo not allowed during resolution phase"
@@ -31,6 +30,18 @@ object OsCheckerTests extends UtestIntegrationTestSuite {
3130
s"Writing to not allowed during resolution phase"
3231
))
3332

33+
tester.modifyFile(workspacePath / "build.mill", _.replace("if (true)", "if (false)"))
34+
tester.modifyFile(
35+
workspacePath / "build.mill",
36+
_ + "\nprintln(os.read(mill.define.WorkspaceRoot.workspaceRoot / \"build.mill\"))"
37+
)
38+
val res4 = tester.eval("baz")
39+
40+
assert(res4.isSuccess == false)
41+
assert(res4.err.contains(
42+
s"Reading from build.mill not allowed during resolution phase"
43+
))
44+
3445
}
3546
}
3647
}

integration/invalidation/watch-source-input/resources/build.mill

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ def writeCompletionMarker(name: String) = {
4343
}
4444

4545
writeCompletionMarker("initialized")
46-
47-
if (os.read(moduleDir / "watchValue.txt").contains("exit")) {
48-
Thread.sleep(1000)
49-
System.exit(0)
46+
os.checker.withValue(os.Checker.Nop) {
47+
if (os.read(moduleDir / "watchValue.txt").contains("exit")) {
48+
Thread.sleep(1000)
49+
System.exit(0)
50+
}
5051
}

libs/javascriptlib/src/mill/javascriptlib/TypeScriptModule.scala

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -152,21 +152,21 @@ trait TypeScriptModule extends Module { outer =>
152152
if (!os.exists(T.dest)) os.makeDir.all(T.dest)
153153

154154
// Copy everything except "build.mill" and the "/out" directory from Task.workspace
155-
os.walk(moduleDir, skip = _.last == "out")
156-
.filter(_.last != "build.mill")
157-
.filter(_.last != "mill")
158-
.filter(_.last != "package.json")
159-
.filter(_.last != "package-lock.json")
160-
.filter(_.last != "tsconfig.json")
161-
.foreach { path =>
162-
val relativePath = path.relativeTo(moduleDir)
163-
val destination = T.dest / relativePath
164-
165-
if (os.isDir(path)) os.makeDir.all(destination)
166-
else os.checker.withValue(os.Checker.Nop) {
167-
os.copy.over(path, destination)
155+
os.checker.withValue(os.Checker.Nop) {
156+
os.walk(moduleDir, skip = _.last == "out")
157+
.filter(_.last != "build.mill")
158+
.filter(_.last != "mill")
159+
.filter(_.last != "package.json")
160+
.filter(_.last != "package-lock.json")
161+
.filter(_.last != "tsconfig.json")
162+
.foreach { path =>
163+
val relativePath = path.relativeTo(moduleDir)
164+
val destination = T.dest / relativePath
165+
166+
if (os.isDir(path)) os.makeDir.all(destination)
167+
else os.copy.over(path, destination)
168168
}
169-
}
169+
}
170170

171171
object IsSrcDirectory {
172172
def unapply(path: Path): Option[Path] =

libs/main/src/mill/main/MainModule.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@ trait MainModule extends BaseModule with MainModuleApi {
2626
protected[mill] val evalWatchedValues: mutable.Buffer[Watchable] = mutable.Buffer.empty[Watchable]
2727
object interp {
2828
def watchValue[T](v0: => T)(implicit fn: sourcecode.FileName, ln: sourcecode.Line): T = {
29-
val v = v0
30-
val watchable = Watchable.Value(
31-
() => v0.hashCode,
32-
v.hashCode(),
33-
fn.value + ":" + ln.value
34-
)
35-
watchedValues.append(watchable)
36-
v
29+
os.checker.withValue(os.Checker.Nop) {
30+
val v = v0
31+
val watchable = Watchable.Value(
32+
() => v0.hashCode,
33+
v.hashCode(),
34+
fn.value + ":" + ln.value
35+
)
36+
watchedValues.append(watchable)
37+
v
38+
}
3739
}
3840

3941
def watch(p: os.Path): os.Path = {

runner/meta/src/mill/runner/meta/MillBuildRootModule.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ class MillBuildRootModule()(implicit
3838

3939
override def scalaVersion: T[String] = BuildInfo.scalaVersion
4040

41-
val scriptSourcesPaths = FileImportGraph
42-
.walkBuildFiles(rootModuleInfo.projectRoot / os.up, rootModuleInfo.output)
43-
.sorted
41+
val scriptSourcesPaths = os.checker.withValue(os.Checker.Nop) {
42+
FileImportGraph
43+
.walkBuildFiles(rootModuleInfo.projectRoot / os.up, rootModuleInfo.output)
44+
.sorted
45+
}
4446

4547
/**
4648
* All script files (that will get wrapped later)
@@ -52,7 +54,9 @@ class MillBuildRootModule()(implicit
5254

5355
def parseBuildFiles: T[FileImportGraph] = Task {
5456
scriptSources()
55-
MillBuildRootModule.parseBuildFiles(compilerWorker(), rootModuleInfo)
57+
os.checker.withValue(os.Checker.Nop) {
58+
MillBuildRootModule.parseBuildFiles(compilerWorker(), rootModuleInfo)
59+
}
5660
}
5761

5862
private[runner] def compilerWorker: Worker[ScalaCompilerWorkerApi] = Task.Worker {

0 commit comments

Comments
 (0)