Skip to content

Commit 4f4b409

Browse files
committed
[fix] Added correct handling for mocked generics, split abstract class with/without implementation onto different cases
1 parent bade429 commit 4f4b409

File tree

4 files changed

+63
-38
lines changed

4 files changed

+63
-38
lines changed

VSharp.Fuzzer/Fuzzer.fs

+4-4
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ type internal Fuzzer(
7979
let generationData = generationDatas[i]
8080
results[i] <- invoke method generationData.this generationData.args
8181

82-
let fuzzBatch typeSolverSeed (rnd: Random) (method: MethodBase) typeStorage =
82+
let fuzzBatch mockedGenerics typeSolverSeed (rnd: Random) (method: MethodBase) typeStorage =
8383
use fuzzingCancellationTokenSource = new CancellationTokenSource()
8484

8585
traceFuzzing "Generate data"
86-
let data = Array.init batchSize (fun _ -> generator.Generate method typeStorage (rnd.Next()))
86+
let data = Array.init batchSize (fun _ -> generator.Generate mockedGenerics method typeStorage (rnd.Next()))
8787
let invocationResults = Array.init batchSize (fun _ -> Unchecked.defaultof<InvocationResult>)
8888
let threadIds = Array.init batchSize (fun _ -> threadIdGenerator.NextId())
8989
traceFuzzing "Data generated"
@@ -235,14 +235,14 @@ type internal Fuzzer(
235235
let typeSolverRnd = Random(typeSolverSeed)
236236

237237
match typeSolver.SolveGenericMethodParameters method (generator.GenerateClauseObject typeSolverRnd) with
238-
| Some(methodBase, typeStorage) ->
238+
| Some(methodBase, typeStorage, mockedGenerics) ->
239239

240240
traceFuzzing "Generics successfully solved"
241241
while int stopwatch.ElapsedMilliseconds < fuzzerOptions.timeLimitPerMethod do
242242
traceFuzzing "Start fuzzing iteration"
243243

244244
stopwatch.Start()
245-
match fuzzBatch typeSolverSeed rnd methodBase typeStorage with
245+
match fuzzBatch mockedGenerics typeSolverSeed rnd methodBase typeStorage with
246246
| Some results -> do! handleResults method results
247247
| None -> ()
248248
stopwatch.Stop()

VSharp.Fuzzer/Generator.fs

+49-29
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ type internal GenerationData = {
2222
}
2323

2424
type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver) =
25-
let instancesCache = Dictionary<Type, Type option>()
25+
let instancesCache = Dictionary<Type, Type[] option>()
2626
let mutable allocatedObjects = HashSet<obj>()
2727
let mutable instantiatedMocks = Dictionary<obj, ITypeMock>()
2828
let mutable referencedObjects = HashSet<obj>()
2929

30+
let mutable mockedGenerics = Dictionary<Type, ITypeMock>()
31+
3032
let traceGeneration (t: Type) msg = Logger.traceGeneration $"[{t.Name}] {msg}"
3133

3234
let setAllFields (t: Type) (setter: Type -> obj) =
@@ -57,14 +59,13 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
5759
| :? TargetInvocationException as e ->
5860
traceGeneration t $"Constructor thrown an exception: {e}"
5961
None
60-
61-
let getInstance (t: Type) (rnd: Random) _ =
62-
traceGeneration t "Try get installable type"
62+
63+
let findInstances (t: Type) =
64+
traceGeneration t "Try find installable type"
6365
match instancesCache.TryGetValue t with
64-
| true, instance ->
65-
let none = "None"
66-
traceGeneration t $"Installable type got from cache: {match instance with | Some x -> x.Name | None -> none}"
67-
instance
66+
| true, instances ->
67+
traceGeneration t "Installable types got from cache"
68+
instances
6869
| false, _ ->
6970
let instances =
7071
t.Assembly.GetTypes()
@@ -79,9 +80,8 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
7980
traceGeneration t "Installable type not found"
8081
instancesCache.Add(t, None)
8182
else
82-
let installableType = instances[rnd.Next(0, instances.Length)]
83-
traceGeneration t $"Installable type found: {installableType}"
84-
instancesCache.Add(t, Some installableType)
83+
traceGeneration t "Installable types found"
84+
instancesCache.Add(t, Some instances)
8585
instancesCache[t]
8686

8787
let generateUnboxedChar (rnd: Random) =
@@ -160,15 +160,21 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
160160
// TODO: LowerBound
161161
__notImplemented__ ()
162162

163-
let generateAbstractClass commonGenerator (rnd: Random) (t: Type) =
164-
traceGeneration t "Generate abstract class"
165-
match getInstance t rnd commonGenerator with
166-
| Some instance -> commonGenerator rnd instance
167-
| None ->
168-
let mock, typ = typeSolver.MockType t (commonGenerator rnd)
169-
let result = commonGenerator rnd typ
170-
instantiatedMocks.Add(result, mock)
171-
result
163+
let generateAbstractClassWithInstances commonGenerator (rnd: Random) (t: Type) =
164+
traceGeneration t "Generate abstract class with instances"
165+
let instances = findInstances t |> Option.defaultWith (fun () ->
166+
internalfailf "Incorrect usage of generateAbstractClassWithInstances"
167+
)
168+
let instance = instances[rnd.Next(0, instances.Length)]
169+
commonGenerator rnd instance
170+
171+
let generateAbstractClassWithoutInstances commonGenerator (rnd: Random) (t: Type) =
172+
traceGeneration t "Generate abstract class without instances"
173+
assert (findInstances t |> Option.isNone)
174+
let mock, typ = typeSolver.MockType t (commonGenerator rnd)
175+
let result = commonGenerator rnd typ
176+
instantiatedMocks.Add(result, mock)
177+
result
172178

173179
let generateByRef commonGenerator (rnd: Random) (t: Type) =
174180
traceGeneration t "Generate ByRef"
@@ -214,11 +220,15 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
214220
else OtherStruct
215221

216222
// Reference types
217-
let (|Array|Delegate|String|AbstractClass|OtherClass|) (t: Type) =
223+
let (|Array|Delegate|String|AbstractClassWithInstances|AbstractClassWithoutInstances|OtherClass|) (t: Type) =
218224
if t.IsArray then Array
219225
elif t = typeof<string> then String
220226
elif t.IsSubclassOf typeof<System.Delegate> then Delegate
221-
elif t.IsAbstract || t.IsInterface then AbstractClass
227+
elif t.IsAbstract || t.IsInterface then
228+
if findInstances t |> Option.isSome then
229+
AbstractClassWithInstances
230+
else
231+
AbstractClassWithoutInstances
222232
else OtherClass
223233

224234
let rec commonGenerate (rnd: Random) (t: Type) =
@@ -240,7 +250,8 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
240250
| Array -> generateArray
241251
| Delegate -> generateDelegate
242252
| String -> generateString
243-
| AbstractClass -> __notImplemented__ ()
253+
| AbstractClassWithoutInstances -> __notImplemented__ ()
254+
| AbstractClassWithInstances -> generateAbstractClassWithInstances
244255
| OtherClass -> generateClass
245256
| ByRefType -> __notImplemented__ ()
246257
| PointerType -> __notImplemented__ ()
@@ -249,11 +260,19 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
249260

250261
member private this.GenerateObject rnd (t: Type) =
251262
Logger.traceGeneration $"Target type: {t.Name}"
252-
match t with
253-
| ByRefType -> generateByRef commonGenerate rnd t
254-
| PointerType -> generatePointer commonGenerate rnd t
255-
| AbstractClass -> generateAbstractClass commonGenerate rnd t
256-
| _ -> commonGenerate rnd t
263+
264+
let result =
265+
match t with
266+
| ByRefType -> generateByRef commonGenerate rnd t
267+
| PointerType -> generatePointer commonGenerate rnd t
268+
| AbstractClassWithoutInstances -> generateAbstractClassWithoutInstances commonGenerate rnd t
269+
| _ -> commonGenerate rnd t
270+
271+
if mockedGenerics.ContainsKey t then
272+
traceGeneration t "Added generated object to instantiated mocks"
273+
instantiatedMocks.Add(result, mockedGenerics[t])
274+
275+
result
257276

258277
member private this.RefreshInstantiatedMocks () =
259278
let result = instantiatedMocks
@@ -290,7 +309,8 @@ type internal Generator(options: Startup.FuzzerOptions, typeSolver: TypeSolver)
290309

291310
{| this = methodThis; thisType = methodThisType; args = args; argsTypes = argsTypes |}
292311

293-
member this.Generate (method: MethodBase) typeStorage rndSeed =
312+
member this.Generate methodMockedGenerics (method: MethodBase) typeStorage rndSeed =
313+
mockedGenerics <- methodMockedGenerics
294314
let case = this.GenerateCase method rndSeed
295315
{
296316
seed = rndSeed

VSharp.Fuzzer/Interaction.fs

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ type private TestRestorer (fuzzerOptions, assemblyPath, outputDirectory) =
6262
|> Application.getMethod
6363

6464
match typeSolver.SolveGenericMethodParameters methodBase (generator.GenerateClauseObject typeSolverRnd) with
65-
| Some(methodBase, typeStorage) ->
65+
| Some(methodBase, typeStorage, mockedGenerics) ->
6666

67-
let data = generator.Generate methodBase typeStorage executionData.fuzzerSeed
67+
let data = generator.Generate mockedGenerics methodBase typeStorage executionData.fuzzerSeed
6868

6969
let thrown =
7070
match exceptionName with

VSharp.Fuzzer/TypeSolver.fs

+8-3
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,18 @@ type internal TypeSolver() =
8282
member this.SolveGenericMethodParameters (method: Method) (generate: System.Type -> obj) =
8383
// TODO: Receive type parameters substitution from master process
8484
Logger.traceTypeSolving $"Solve generics for {method.Name}"
85+
86+
let mockedGenerics = System.Collections.Generic.Dictionary<System.Type, ITypeMock>()
87+
8588
let substituteGenerics classParams methodParams =
8689
let getConcreteType =
8790
function
8891
| ConcreteType t -> t
8992
| MockType m ->
90-
mockTypes (m.SuperTypes |> Seq.toList) generate
91-
|> snd
93+
let typeMock, systemType = mockTypes (m.SuperTypes |> Seq.toList) generate
94+
if mockedGenerics.ContainsKey(systemType) |> not then
95+
mockedGenerics.Add(systemType, typeMock)
96+
systemType
9297

9398
let methodBase = (method :> IMethod).MethodBase
9499
let classParams = classParams |> Array.map getConcreteType
@@ -103,7 +108,7 @@ type internal TypeSolver() =
103108
| Some(classParams, methodParams) ->
104109
let method = substituteGenerics classParams methodParams
105110
Logger.traceTypeSolving $"Solved generics for {method.Name}"
106-
Some (method, typeStorage)
111+
Some (method, typeStorage, mockedGenerics)
107112
| _ ->
108113
Logger.traceTypeSolving $"Failed solve generics for {method.Name}"
109114
None

0 commit comments

Comments
 (0)