GetRef's memory consumption (garbage collectio

2020-07-03 05:36发布

问题:

We experience out-of-memory issues after installing KB4525236 on our Windows 2016 Servers/Windows 10 Clients. This security fix seems to have changed the moment when memory is garbage collected when calling a function through GetRef.

Pré KB4525236

Each instance created in a function called through GetRef got garbage collected as soon as the instance variable was set to nothing

Post KB4525236

Each instance created in a function called through GetRef remains in memory and is garbage collected only when the entire function completes. When creating instances in a loop, this can quickly add up and lead to an out-of-memory, especially in a 32-bit process.

Questions

  • we can not find anything relevant online so we would like to get confirmation from others experiencing the same issue.
    EDIT scratch that: this is the same issue but with no solution as of yet
    (vbscript.dll class_terminate bug since KB4524570 (November 12, 2019) Windows 10 1903)
  • if anyone can verify and knows a workable solution, that would be awesome.

POC

following script running on a device with KB4525236 installed shows the difference in garbage collecting when

  • called directly: the second instance gets created only after the first instance is destroyed (this is our desired behavior)
  • called through GetRef: the second instance gets created before the first instance is destroyed so whe have two instances using memory.

save as: KB4525236.vbs
run as: wscript KB4525236.vbs

Dim Name, Log

Class IDummyInstance
  Dim FName
  Sub Class_Initialize
    FName = Name
    Log = Log & "Initialize " & FName & VbNewLine
  End Sub
  Sub Class_Terminate
    Log = Log & "Terminate " & FName & vbNewLine
  End Sub
End Class

Sub CreateDestroyTwoInstances
  Dim DummyInstance
  Name = "First Instance"
  Set DummyInstance = New IDummyInstance
  Set DummyInstance = Nothing
  Name = "Second Instance"
  Set DummyInstance = New IDummyInstance
  Set DummyInstance = Nothing
End Sub

Log = "(1) Direct Call :" & VbNewLine
Call CreateDestroyTwoInstances

Log = VbNewLine & Log & "(2) GetRef Call :" & vbNewLine
Set GetRefCall = GetRef ("CreateDestroyTwoInstances")
Call GetRefCall

MsgBox Log

回答1:

Since I don't have a solution or an official source explaining the issue I was waiting the bounty to expire.

I've come up with an unpleasant workaround that can help until the bug is fixed.

The workaround is not to use any local variable to hold object instances in procedures that might be executed through GetRef.

Instead of implicit or explicit variables, using a local (or global if there's no recursion) dictionary object to hold object instances and calling them through that dictionary works.

Sub CreateDestroyTwoInstances
  Dim Refs
  Set Refs = CreateObject("Scripting.Dictionary")
  Name = "First Instance"
  Refs.Add "DummyInstance", New IDummyInstance
  ' Call Refs("DummyInstance").DoSomething()
  Refs.Remove "DummyInstance"
  Name = "Second Instance"
  Refs.Add "DummyInstance", New IDummyInstance
  ' Call Refs("DummyInstance").DoSomething()
  Refs.Remove "DummyInstance"
End Sub

It seems to be worth using if you have a script that is not too complicated.