Skip to content

Commit 1be52aa

Browse files
Fix StackOverflow in non-recursive bindings checker (#16908)
* Fix StackOverflow in non-recursive bindings checker * Release notes * Automated command ran: fantomas Co-authored-by: vzarytovskii <[email protected]> * Update src/Compiler/Checking/CheckDeclarations.fs Remove commented-out code --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 447639e commit 1be52aa

File tree

6 files changed

+87
-30
lines changed

6 files changed

+87
-30
lines changed

docs/release-notes/.FSharp.Compiler.Service/8.0.300.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* Enforce AttributeTargets on enums ([PR #16887](https://github.com/dotnet/fsharp/pull/16887))
2626
* Completion: fix for unfinished record field decl ([PR #16893](https://github.com/dotnet/fsharp/pull/16893))
2727
* Enforce AttributeTargets on delegates ([PR #16891](https://github.com/dotnet/fsharp/pull/16891))
28-
28+
* Fix StackOverflow when checking non-recursive bindings in module or namespace in `fscAnyCpu`/`fsiAnyCpu`. ([PR #16908](https://github.com/dotnet/fsharp/pull/16908))
2929

3030
### Added
3131

src/Compiler/Checking/CheckDeclarations.fs

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module internal FSharp.Compiler.CheckDeclarations
44

55
open System
66
open System.Collections.Generic
7+
open System.Threading
78

89
open FSharp.Compiler.Diagnostics
910
open Internal.Utilities.Collections
@@ -5330,22 +5331,29 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
53305331
}
53315332

53325333
/// The non-mutually recursive case for a sequence of declarations
5333-
and TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) =
5334-
cancellable {
5335-
match moreDefs with
5336-
| firstDef :: otherDefs ->
5337-
// Lookahead one to find out the scope of the next declaration.
5338-
let scopem =
5339-
if isNil otherDefs then unionRanges firstDef.Range endm
5340-
else unionRanges (List.head otherDefs).Range endm
5334+
and [<TailCall>] TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm (defsSoFar, env, envAtEnd) (moreDefs: SynModuleDecl list) (ct: CancellationToken) =
5335+
5336+
if ct.IsCancellationRequested then
5337+
ValueOrCancelled.Cancelled (OperationCanceledException())
5338+
else
5339+
match moreDefs with
5340+
| [] ->
5341+
ValueOrCancelled.Value (List.rev defsSoFar, envAtEnd)
5342+
| firstDef :: otherDefs ->
5343+
// Lookahead one to find out the scope of the next declaration.
5344+
let scopem =
5345+
if isNil otherDefs then
5346+
unionRanges firstDef.Range endm
5347+
else
5348+
unionRanges (List.head otherDefs).Range endm
53415349

5342-
let! firstDef, env, envAtEnd = TcModuleOrNamespaceElementNonMutRec cenv parent typeNames scopem env firstDef
5350+
let result = Cancellable.run ct (TcModuleOrNamespaceElementNonMutRec cenv parent typeNames scopem env firstDef)
53435351

5344-
// tail recursive
5345-
return! TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ( (firstDef :: defsSoFar), env, envAtEnd) otherDefs
5346-
| [] ->
5347-
return List.rev defsSoFar, envAtEnd
5348-
}
5352+
match result with
5353+
| ValueOrCancelled.Cancelled x ->
5354+
ValueOrCancelled.Cancelled x
5355+
| ValueOrCancelled.Value(firstDef, env, envAtEnd) ->
5356+
TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ((firstDef :: defsSoFar), env, envAtEnd) otherDefs ct
53495357

53505358
/// The mutually recursive case for a sequence of declarations (and nested modules)
53515359
and TcModuleOrNamespaceElementsMutRec (cenv: cenv) parent typeNames m envInitial mutRecNSInfo (defs: SynModuleDecl list) =
@@ -5470,20 +5478,24 @@ and TcModuleOrNamespaceElements cenv parent endm env xml mutRecNSInfo openDecls0
54705478
escapeCheck()
54715479
return (moduleContents, topAttrsNew, envAtEnd)
54725480

5473-
| None ->
5474-
5475-
let! compiledDefs, envAtEnd = TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ([], env, env) synModuleDecls
5476-
5477-
// Apply the functions for each declaration to build the overall expression-builder
5478-
let moduleDefs = List.collect p13 compiledDefs
5479-
let moduleDefs = match openDecls0 with [] -> moduleDefs | _ -> TMDefOpens openDecls0 :: moduleDefs
5480-
let moduleContents = TMDefs moduleDefs
5481+
| None ->
5482+
let! ct = Cancellable.token ()
5483+
let result = TcModuleOrNamespaceElementsNonMutRec cenv parent typeNames endm ([], env, env) synModuleDecls ct
5484+
5485+
match result with
5486+
| ValueOrCancelled.Value(compiledDefs, envAtEnd) ->
5487+
// Apply the functions for each declaration to build the overall expression-builder
5488+
let moduleDefs = List.collect p13 compiledDefs
5489+
let moduleDefs = match openDecls0 with [] -> moduleDefs | _ -> TMDefOpens openDecls0 :: moduleDefs
5490+
let moduleContents = TMDefs moduleDefs
5491+
5492+
// Collect up the attributes that are global to the file
5493+
let topAttrsNew = List.collect p33 compiledDefs
5494+
return (moduleContents, topAttrsNew, envAtEnd)
5495+
| ValueOrCancelled.Cancelled x ->
5496+
return! Cancellable(fun _ -> ValueOrCancelled.Cancelled x)
5497+
}
54815498

5482-
// Collect up the attributes that are global to the file
5483-
let topAttrsNew = compiledDefs |> List.collect p33
5484-
return (moduleContents, topAttrsNew, envAtEnd)
5485-
}
5486-
54875499

54885500
//--------------------------------------------------------------------------
54895501
// CheckOneImplFile - Typecheck all the namespace fragments in a file.

src/Compiler/Facilities/DiagnosticsLogger.fs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ open System
1111
open System.Diagnostics
1212
open System.Reflection
1313
open System.Threading
14+
open System.Runtime.CompilerServices
15+
open System.Runtime.InteropServices
1416
open Internal.Utilities.Library
1517
open Internal.Utilities.Library.Extras
1618
open System.Collections.Concurrent
@@ -853,7 +855,25 @@ type StackGuard(maxDepth: int, name: string) =
853855
let mutable depth = 1
854856

855857
[<DebuggerHidden; DebuggerStepThrough>]
856-
member _.Guard(f) =
858+
member _.Guard
859+
(
860+
f,
861+
[<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string,
862+
[<CallerFilePath; Optional; DefaultParameterValue("")>] path: string,
863+
[<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int
864+
) =
865+
use _ =
866+
Activity.start
867+
"DiagnosticsLogger.StackGuard.Guard"
868+
[|
869+
Activity.Tags.stackGuardName, name
870+
Activity.Tags.stackGuardCurrentDepth, string depth
871+
Activity.Tags.stackGuardMaxDepth, string maxDepth
872+
Activity.Tags.callerMemberName, memberName
873+
Activity.Tags.callerFilePath, path
874+
Activity.Tags.callerLineNumber, string line
875+
|]
876+
857877
depth <- depth + 1
858878

859879
try

src/Compiler/Facilities/DiagnosticsLogger.fsi

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ open System
66
open FSharp.Compiler.Diagnostics
77
open FSharp.Compiler.Features
88
open FSharp.Compiler.Text
9+
open System.Runtime.CompilerServices
10+
open System.Runtime.InteropServices
911

1012
/// Represents the style being used to format errors
1113
[<RequireQualifiedAccess>]
@@ -448,7 +450,12 @@ type StackGuard =
448450
new: maxDepth: int * name: string -> StackGuard
449451

450452
/// Execute the new function, on a new thread if necessary
451-
member Guard: f: (unit -> 'T) -> 'T
453+
member Guard:
454+
f: (unit -> 'T) *
455+
[<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string *
456+
[<CallerFilePath; Optional; DefaultParameterValue("")>] path: string *
457+
[<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int ->
458+
'T
452459

453460
static member GetDepthOption: string -> int
454461

src/Compiler/Utilities/Activity.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ module internal Activity =
3434
let outputDllFile = "outputDllFile"
3535
let buildPhase = "buildPhase"
3636
let version = "version"
37+
let stackGuardName = "stackGuardName"
38+
let stackGuardCurrentDepth = "stackGuardCurrentDepth"
39+
let stackGuardMaxDepth = "stackGuardMaxDepth"
40+
let callerMemberName = "callerMemberName"
41+
let callerFilePath = "callerFilePath"
42+
let callerLineNumber = "callerLineNumber"
3743

3844
let AllKnownTags =
3945
[|
@@ -50,6 +56,12 @@ module internal Activity =
5056
gc2
5157
outputDllFile
5258
buildPhase
59+
stackGuardName
60+
stackGuardCurrentDepth
61+
stackGuardMaxDepth
62+
callerMemberName
63+
callerFilePath
64+
callerLineNumber
5365
|]
5466

5567
module Events =

src/Compiler/Utilities/Activity.fsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ module internal Activity =
2929
val cache: string
3030
val buildPhase: string
3131
val version: string
32+
val stackGuardName: string
33+
val stackGuardCurrentDepth: string
34+
val stackGuardMaxDepth: string
35+
val callerMemberName: string
36+
val callerFilePath: string
37+
val callerLineNumber: string
3238

3339
module Events =
3440
val cacheHit: string

0 commit comments

Comments
 (0)