|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
I'm not sure if its mIRC or the interface I'm using, but something is leaking memory. The following code creates an instance of window's jscript engine, executes a function and dispatches the returned object. When the identifying mIRC com is closed, the memory consumed by the dispatch com isn't freed: ;; /LeakTest <amount_of_times_to_call_function>
alias leaktest {
var %x = $$1, %error
var %js = (function(){return{"test":Array(3001).join("a")}})()
.comopen LeakTest MSScriptControl.ScriptControl
if (!$com(LeakTest)) || ($comerr) {
%Error = SCRIPTCONTROL_INIT_FAIL
}
elseif (!$com(LeakTest, language, 4, bstr, jscript)) || ($comerr) {
%Error = LANGUAGE_SET_FAIL
}
else {
while (%x) {
dec %x
;; Dispatches the result of the js function, but then immediately closes it
;; yet the memory isn't freed even if given time
if (!$com(LeakTest, eval, 1, bstr, %Js, dispatch* LeakTest/Test) || $comerr || !$com(LeakTest/Test)) {
%Error = failed to dispatch LeakTest/Test
goto error
}
.comclose LeakTest/Test
}
}
:error
if ($com(LeakTest/Test)) .comclose $v1
if ($com(LeakTest)) .comclose $v1
if ($error || %error) {
Echo -a ERROR: $v1
}
else {
echo -a Done!
}
} More Info: //echo -a $os $version $beta $md5($mircexe,2) $file($mircexe).sig $alias(0) $script(0) $dll(0) $com(0)
10 7.47 7fbdee41d89a9a06431e08d52aa7f49b ok 1 1 0 0
Last edited by FroggieDaFrog; 20/01/17 03:41 PM.
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
After further testing, I'm fairly sure this is an mIRC leak. Using the following executed under cscript, the memory increases during the while loop but as soon as the loop finishes, the memory is freed; this doesn't appear to be the case with the previous posts' mIRC example Save as leaktest.js Open taskmanager (or any other tool to view memory usage) Open cmd.exe Navigate to the directory you saved leaktest.js Input: cscript.exe leaktest.js In the prompt, enter: 10000 WScript.StdOut.Write("How many times to iterate? ");
WScript.StdIn.Read(0);
var x = WScript.StdIn.ReadLine();
var js = '(function(){return{"test":Array(3001).join("a")}})()';
var leakTest, leakTestRes;
// creates an instance of scriptcontrol and sets the language
leakTest = new ActiveXObject("MSScriptControl.ScriptControl");
leakTest.language = "jscript";
while (x) {
x -= 1;
// calls the js function as the mSL code did
leakTestRes = leakTest.eval(js);
}
WScript.StdOut.Write("Press enter to exit...");
WScript.StdIn.Read(0);
WScript.StdIn.ReadLine(); EditAnd another test that doesn't use jscript at all pulled from the helpfile -- (but modified to show issue). Though not as significant as my previous two examples this one also shows an increase in memory without freeing once the com is closed (My guess is something to do with dispatching):
;; /cpu 10000
alias cpu {
var %Error, %x = $$1
comopen Locator WbemScripting.SWbemLocator
if ($comerr) {
%Error = Failed to open instance
}
else {
while (%x) {
dec %x
if ($com(Locator, ConnectServer, 3, dispatch* Services) && !$comerr && $com(Services)) {
.comclose services
}
else {
%Error = Failed to dispatch services
break
}
}
}
:error
if ($com(Services)) comclose Services
if ($com(Locator)) comclose Locator
if (%Error) {
echo -a $v1
}
elseif (!$error) {
echo -a Done!
}
}
Last edited by FroggieDaFrog; 20/01/17 11:19 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
Thanks, I was able to reproduce this issue. It was due to memory not being freed by a function that retrieves the $com().progid value from the dispatch pointer. This issue has been fixed for the next version.
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
Via my own testing this has indeed been fixed with the 7.47.91 beta. Thank you
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
I'm not sure when this crept back into the interface but mIRC isn't freeing memory again: 1. Open your favorite program-memory-usage monitor(taskmanager) 2. Load the following script into a fresh mIRC 3. Enter: /example alias example {
var %x = $iif($1 isnum, $1, 5000)
var %com = example
var %js = (function(){return{"test":Array(4000).join("a")}})()
var %err
echo -a Processing %x iterations
.comopen example MSScriptControl.scriptControl
if (!$com(example) || $comerr) {
%err = Failed to create MSScriptControl.ScriptControl
}
elseif (!$com(example, language, 4, bstr, jscript) || $comerr) {
%err = Failed to set language to jscript
}
else {
while (%x) {
dec %x
if (!$com(example, Eval, 1, bstr, %js) || $comerr) {
%err = Failed to execute jscript
}
}
}
echo -a Done!
:error
if ($com(example)) {
.comclose example
}
if (%err) {
echo -s %err
}
} For comparison, here is the same script to be ran under cscript.exe. You will notice after the initial memory spike of creating the MSScriptControl then the memory fluctuates but doesn't have a steady increase: WScript.StdOut.write("How many times to iterate?");
WScript.StdIn.Read(0);
var x = Number(WScript.StdIn.readLine());
var js = '(function(){return{"test":Array(4000).join("a")}})()'
if (isNaN(x)) {
x = 5000;
}
var leakTest, leakTestRes;
// create an instance of the ScriptControl and set language
leakTest = new ActiveXObject('MSScriptControl.ScriptControl');
leakTest.language = 'jscript';
while (x > 0) {
x--;
leakTestRes = leakTest.eval(js);
}
// remove reference.
leakTest = null;
WScript.StdOut.Write("Press enter to exit...");
WScript.StdIn.Read(0);
WScript.StdIn.ReadLine(); Echo info - this issue has been reported to me as early as mIRC v7.48 (the release that supposedly fixed it  ) 10 7.51 1561 ad5337d2a735eec9e6ffc9ffa5b097d3 ok 1 1 0 0
Last edited by FroggieDaFrog; 20/01/18 07:00 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
Are you able to reproduce this issue with your original bug report? I tested the "alias cpu" script you provided before and could not reproduce a memory leak. If so, this may be a different bug.
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
I do believe its a new bug. Before making this report I tested with the /CPU alias and other WMI objects and could not get a noticable leak.
To be clear, this is not related to dispatching; The latest example above doesn't use such yet mIRC's memory rises with each call and isn't freed once the com is closed.
Last edited by FroggieDaFrog; 20/01/18 09:19 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
$com(example, Eval, 1, bstr, %js) Right, what is this call meant to do?
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
It evaluates the input string(stored in %js) as javascript and returns the resulting value: an object containing a single key("test") with a string value of 4000 a's("aaaaaaaaaaaaaaa....") The documentation for MSScriptControl is scarce but here you go
Last edited by FroggieDaFrog; 20/01/18 09:36 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
It evaluates the input string(stored in %js) as javascript and returns the resulting value: an object containing a single key("test") with a string value of 3000 a's Okay, where in the $com() call is this array accessible by mIRC? The $com() identifier provides you with access to the variables returned by the routine that $com() calls. But I cannot see where this is in your call.
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
In the example, the result isn't used by the mSL. I stopped coding the example at the first point inwhich mIRC's memory consumption balloons.
The invocation of the Eval method begins the ballooning of mIRC's memory consumption even though the result of the call is discarded. Furthermore, closing the MSScriptControl com that the eval method was called against does NOT free the memory.
This is different from doing the same thing under cscript.exe which causes cscript.exe to max at 30-40mb regardless of number of calls against the MSScriptControl instance's Eval method.
If need be I can write a more fleshed-out script and provide the cscript.exe equivalent to help you further understand/trace the issue
Last edited by FroggieDaFrog; 20/01/18 09:49 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
I think I see what the issue is. The call you are making returns the result via a dispatch pointer. mIRC preserves this so that you can access it with $com().result. However, mIRC does not free it because in the past this caused mIRC to crash due to that pointer being later used by the scripter. There is currently no way for mIRC to know that this has happened. I can't remember all the ways scripters use the $com().result value. Have you used that in the past, if it was a dispatch pointer, to create a new COM object?
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
I could be wrong, but $com().result cannot be used short of its literal value; that is AFAIK, there's no way to take the value of $com().result to create a new com/dispatch instance.
So keeping the dispatched pointer alive doesn't make sense IF the $com() call does not provide a dispatch*/unknown* 'variable' for mIRC to fill with the result.
Using our example above: $com(example, eval, 1, bstr, %js) - Should NOT keep the returned dispatched pointer as the script has NOT requested it. Instead, $com().result should be filled with the pointer's converted UINT value, and the actual pointer be discarded
$com(example, eval, 1, bstr, %js, dispatch* result) - Should keep the dispatched pointer(referencable as a new com 'result') as the script has requested the result be kept alive.
--
Also, if I close the root com, why isn't the memory being freed for these inaccessible pointers.
Last edited by FroggieDaFrog; 20/01/18 10:33 PM.
|
|
|
|
Joined: Dec 2002
Posts: 3,840
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 3,840 |
Should NOT keep the returned dispatched pointer as the script has NOT requested it. Instead, $com().result should be filled with the pointer's converted UINT value, and the actual pointer be discarded The result cannot be freed immediately because it needs to be used in $com().result. This could also be used, for example, by a script that passes the UINT of the dispatch pointer to a DLL that then uses the dispatch pointer. However, this is short-lived, so mIRC should be able to free it on the next $com()/comclose call without side-effects - unless the script has stored the value of the pointer and tries to use it again - but that would be a script issue. This change has been made to the next version, however COM support will need thorough testing. This change is essentially undoing changes due to previous gpf bug reports, although the COM code may have been less robust at the time.
|
|
|
|
Joined: Apr 2010
Posts: 964
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 964 |
Using my JSON For mIRC script, and its test suit. The memory leak appears to be fixed in the .1800 beta without side affects. I have instructed the users of my script to monitor memory usage with the beta and report back. I will give you an update if something unexpected creeps up.
|
|
|
|
|