Search code examples
.netdebuggingf#stack-overflow

F# debugger crashed due to StackOverflow inside `sprintf "%A"`


I have the following discriminated union type:

type Value =
    | Float of float
    | Int of int
    | String of string
    | Function of (ContextStack -> Value -> Value)
    | Action of (unit -> Value)
    | Constructor of string * int * Value
    | Type of string * Context
    | Object of Value * List<Value>
    | Ref of Context * (Context -> Value) * (Context -> Value -> Context)
    | Unrecognizable of Node
    | Closure of Value * ContextStack * bool
    | Application of Value * Value

where some constructors contain a field of type Context, which is basically just a System.Collections.Generic.Dictionary<string, Value> (and ContextStack is Context list). Because of that, there can be a situation, when a Value instance contains a reference to a dictionary, that contains said instance. Trying to print it using sprintf "%A", that recursively traverses the object, will result in unending recursion and StackOverflow error. But it is not really a problem for the application itself - as I never print these values anyway. However, when I am trying to debug my program, debugger tries to evaluate all object's string representation and fails with stack overflow.

To solve it, I tried to override ToString method, thinking the debugger uses it for string representation, but it didn't work. Even this:

type Value =
    | Float of float
    | Int of int
    | String of string
    | Function of (ContextStack -> Value -> Value)
    | Action of (unit -> Value)
    | Constructor of string * int * Value
    | Type of string * Context
    | Object of Value * List<Value>
    | Ref of Context * (Context -> Value) * (Context -> Value -> Context)
    | Unrecognizable of Node
    | Closure of Value * ContextStack * bool
    | Application of Value * Value
    with override this.ToString(): string = "Please, don't crash!" 

causes an error. What do I do?

Just in case:

  • Operating System - Windows 11
  • IDE - Rider 2024.3
  • .NET project's target framework - netcoreapp 3.1 (I know it is not supported anymore - I heavily rely on an old library - changing it is not an option)

Update: it seems that debugger actually uses toString for string representation, but only if the object to represent is Value. Trying to sprintf "%A" dictionary, that contains Value object, will call sprintf "%A" on the contained Value object instead of its toString.


Solution

  • It turns out, there is a debugger option to disable implicit evaluation. In Rider. it is: Settings -> Build, Execution, Deployment -> Debugger -> Value inspections/Allow property evaluations and other implicit function calls. Disabling this option solves the issue.