File tree Expand file tree Collapse file tree 2 files changed +26
-0
lines changed Expand file tree Collapse file tree 2 files changed +26
-0
lines changed Original file line number Diff line number Diff line change @@ -341,11 +341,14 @@ private struct IndexOutOfDateChecker {
341341
342342 private enum Error : Swift . Error , CustomStringConvertible {
343343 case fileAttributesDontHaveModificationDate
344+ case circularSymlink( URL )
344345
345346 var description : String {
346347 switch self {
347348 case . fileAttributesDontHaveModificationDate:
348349 return " File attributes don't contain a modification date "
350+ case . circularSymlink( let url) :
351+ return " Circular symlink at \( url) "
349352 }
350353 }
351354 }
@@ -484,6 +487,8 @@ private struct IndexOutOfDateChecker {
484487 }
485488 var modificationDate = try Self . modificationDate ( atPath: fileURL. filePath)
486489
490+ var visited : Set < URL > = [ fileURL]
491+
487492 // Get the maximum mtime in the symlink chain as the modification date of the URI. That way if either the symlink
488493 // is changed to point to a different file or if the underlying file is modified, the modification time is
489494 // updated.
@@ -492,6 +497,9 @@ private struct IndexOutOfDateChecker {
492497 ) ,
493498 let symlinkDestination = URL ( string: relativeSymlinkDestination, relativeTo: fileURL)
494499 {
500+ if !visited. insert ( symlinkDestination) . inserted {
501+ throw Error . circularSymlink ( symlinkDestination)
502+ }
495503 fileURL = symlinkDestination
496504 modificationDate = max ( modificationDate, try Self . modificationDate ( atPath: fileURL. filePath) )
497505 }
Original file line number Diff line number Diff line change @@ -2201,6 +2201,24 @@ final class BackgroundIndexingTests: XCTestCase {
22012201 }
22022202 )
22032203 }
2204+
2205+ func testCircularSymlink( ) async throws {
2206+ let project = try await SwiftPMTestProject (
2207+ files: [
2208+ " Symlink.swift " : " "
2209+ ] ,
2210+ enableBackgroundIndexing: true
2211+ )
2212+ let circularSymlink = try XCTUnwrap ( project. uri ( for: " Symlink.swift " ) . fileURL)
2213+ try FileManager . default. removeItem ( at: circularSymlink)
2214+ try FileManager . default. createSymbolicLink ( at: circularSymlink, withDestinationURL: circularSymlink)
2215+
2216+ project. testClient. send (
2217+ DidChangeWatchedFilesNotification ( changes: [ FileEvent ( uri: URI ( circularSymlink) , type: . changed) ] )
2218+ )
2219+ // Check that we don't enter an infinite loop trying to index the circular symlink.
2220+ try await project. testClient. send ( PollIndexRequest ( ) )
2221+ }
22042222}
22052223
22062224extension HoverResponseContents {
You can’t perform that action at this time.
0 commit comments