mIRC Home    About    Download    Register    News    Help

Print Thread
Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
A procedural error can affect memory over time.
I noticed that when using /SOCKREAD &BINVAR and if during the Sockread Event I do:
if ($sockbr == 0) return
This BinVar is not removed from memory.
The mIRC examples basically show /SOCKREAD %VAR
For this reason the code should be:
if ($sockbr == 0) { bunset &BINVAR | return }

ON *:SOCKREAD:mySocket:{
if ($sockerr > 0) { return }
sockread &MyVar
;ERROR MEMORY
if (!$sockbr) return
;FREE MEMORY
if (!$sockbr) { bunset &MyVar | return }
;;;
Your Code
}

If you have a recurring Socket command, you will notice your memory gradually rising without stopping.

https://en.wikichip.org/wiki/mirc/on_events/on_sockread
https://en.wikichip.org/wiki/mirc/commands/sockread
Thanks!

Joined: Jan 2004
Posts: 2,127
Hoopy frood
Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
If &MyVar is not being unset, then you should be able to put the debugging message
echo -s event $event $bvar(&MyVar) $bvar(&MyVar,0)
at the top of your ON SOCKREAD event and find that it exists with a non-zero size, and I don't see that when I add that check to one of my scripts.
While there might be a memory leak of some kind, your example doesn't demonstrate it. Also, if you are finding sockread causing mirc memory to increase gradually due to a &binvar not being unset, does the increase stop happening if you instead have it read to a %variable ?

Joined: Dec 2002
Posts: 5,465
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,465
Thanks for your bug report. I have not been able to reproduce this issue here.

In my tests, the &binvar is automatically freed when the on sockread event ends.

You can test for this by, eg. calling //echo $bvar(&binvar,0) after the on sockread event exits.

Can you provide a script that reproduces your issue? Your test script should use /socklisten, /sockopen, /sockwrite, and the socket events, so that I can run it here to reproduce your issue.

Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
You need to let him read for a long time to notice.
Here I left it for a day in a loop opening and closing the socket.

The problem is the return before finishing the Sockread Event. It will prevent the Event from finishing and &BinVar's memory will not be released.

Put a Return at some point and you will see that the memory will not be freed.

I showed this case, because that's how the example explains the return in case of $sockbr, but any return will cause the failure of not freeing the memory.

Joined: Jan 2004
Posts: 2,127
Hoopy frood
Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
Heya, reminder you had 2 replies asking you to give an example that demonstrates this memory leak bug. You're basically asking to have the other person create a script, then run it for a day, with the promise that they'll see an unstated memory increase.

Joined: Dec 2002
Posts: 5,465
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,465
Okay, I ran a test script that sent almost a gigabyte of data, received in the sockread event into a &binvar, and there has been no memory loss so far.

This is the reason why I ask scripters to please provide an example script that reproduces their issue. I can spend all day guessing at what your script looks like, what calls it makes, the order of calls, etc. but that will not help.

Your last post says that "Here I left it for a day in a loop opening and closing the socket." So this might have nothing to do with &binvars. This might be related to repeatedly opening and closing sockets.

Please provide a working test script that reproduces the issue for you.

Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
My Example:

ON *:SOCKREAD:mySocket:{
if ($sockerr > 0) { return }
sockread $+(&,$sockname)
;ERROR MEMORY
if ($sockbr == 0) return
;FREE MEMORY
;;;if (!$sockbr == 0) { bunset $+(&,$sockname) | return }
;;;
Your Code
}

It is necessary for $sockbr to return 0 to cause the problem of not freeing memory.

Here this type of example gives trouble. If $sockbr is zero and the return is triggered.

Joined: Jan 2004
Posts: 2,127
Hoopy frood
Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
this is not an example. You can put this code into a clean copy of mirc and i promise this does nothing for 100 years. You're being asked for code to show the bug, and this isn't that.

Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
I guarantee you that this code does not free up memory. I use it in my code here and you can put me read from socket to html page and you will see this error occur. I guarantee you with absolute certainty.
After I freed the memory before the return the problem stopped.
After a day running the memory doubled in size.
If I put this code there, just a socket that reads some simple html page is enough.

Joined: Jan 2004
Posts: 2,127
Hoopy frood
Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
Sorry, I'm checking out. I dunno why you don't want to just provide some example code that would demo this bug in a clean mirc.

Joined: Jul 2006
Posts: 4,172
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,172
Hello,

The script you provided has a theorical misconception, so if it works the way you're implying it does, then the socket design/event is far more broken than just a leak.

In theory, you're reading into a binvar without specifying a number of bytes so a default of 4096 bytes is read into the buffer.
Let's say data arrives on the socket, any data, on sockread triggers, 4096 bytes (or less if less) are read, $sockbr isn't 0.
1) if you have read the full buffer and no more data is available, per the note in the help file under /help /sockread, on sockread won't retrigger in this case, so, certainly not with $sockbr = 0.
2) if you haven't read the full buffer, on sockread retriggers and we're back to reading 4096 or less bytes etc (your on sockread event logic guarantees data is there if the event is triggered)

So it should not be possible for this on sockread event to trigger with $sockbr = 0.

Which version of mIRC are you using, are you using SSL?


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Apr 2010
Posts: 969
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
win10
mIRC v7.72 (Fresh install; no coms, dlls, or unrelated scripts)

I cannot reproduce this after testing a veriety of ways. Things I've tried:

Singular sockread calls across multiple events:
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [CLIENT] SockRead error
  sockread 8192 &bvar
}

Multiple sockread calls in the same event
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [CLIENT] SockRead error
  sockread 1024 &bvar
  sockread 1024 &bvar
  sockread 1024 &bvar
  sockread 1024 &bvar
}

Context dependant sockread calls:
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [CLIENT] SockRead error
  sockread 1024 &bvar
  while ($sockbr) {
    sockread 1024 &bvar
  }
}


The script used (sub out the SOCKREAD test-client event):
Code
;; To start the test: /test-start
alias test-start {
  socklisten test-listener 1010
  echo * [Host] Listening for connections
  startclient

  ;; adjust timer to alter run length
  timerteststop 1 15 test-stop
}

alias test-stop {
  if ($sock(test-listener)) {
    sockclose test-listener
  }
  if ($sock(test-host)) {
    sockclose test-host
  }
  if ($sock(test-client)) {
    sockclose test-client
  }
  if ($timer(teststop)) {
    timerteststop off
  }

  if ($0) {
    echo * $1-
  }
  else {
    echo * Test ended
  }
  halt
}


; Setup Listener
on *:SOCKLISTEN:test-listener:{
  if ($sockerr) test-stop [LISTENER] SockListen error
  sockaccept test-host
  sockwrite -t test-host str(a, 8192)
}
on *:SOCKCLOSE:test-listener: {
  if ($sockerr) test-stop [LISTENER] SockClose error
  test-stop [LISTENER] Listener closed
}



/*
** Host/server side of connection
** Attempts to keep the send-buffer at 8kb
*/
on *:SOCKWRITE:test-host:{
  if ($sockerr) test-stop [HOST] SockWrite error
  var %space = $calc(8192 - $sock($sockname).sq)
  if (%space > 0) {
    sockwrite -t $sockname $str(a, %space)
  }
}
on *:SOCKCLOSE:test-host: {
  if ($sockerr) test-stop [HOST] SockClose error
  test-stop [HOST] Shutdown: Client disconnected from host
}


/*
Client: Connects to host, reads received data into bvar, then returns
*/
alias -l startclient {
  sockopen test-client 127.0.0.1 1010
  echo * [Client] Connecting to host...
}
on *:SOCKOPEN:test-client: {
  if ($sockerr) test-stop [CLIENT] SockOpen error
  echo * [Client] Connected to host.
}
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [Client] SockRead error
  sockread 8192 &mybvar
}
on *:SOCKCLOSE:test-client:{
  if ($sockerr) test-stop [Client] SockClose error
  test-stop [Client] Connection to host closed
}


I am SReject
My Stuff
Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
Version 7.72

Joined: Nov 2021
Posts: 21
F
Ameglian cow
OP Offline
Ameglian cow
F
Joined: Nov 2021
Posts: 21
Your example:

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 8192 &bvar
}

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 1024 &bvar
sockread 1024 &bvar
sockread 1024 &bvar
sockread 1024 &bvar
}

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 1024 &bvar
while ($sockbr) {
sockread 1024 &bvar
}
}

Where is the return?

THE PROBLEM IS RETURNING AFTER /SOCKREAD, UNDERSTAND?

Modifying your code:

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 8192 &bvar
if ($sockbr == 0) return
}

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 1024 &bvar
if ($sockbr == 0) return
sockread 1024 &bvar
if ($sockbr == 0) return
sockread 1024 &bvar
if ($sockbr == 0) return
sockread 1024 &bvar
if ($sockbr == 0) return
}

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 1024 &bvar
if ($sockbr == 0) return
while ($sockbr) {
sockread 1024 &bvar
if ($sockbr == 0) return
}
}

If you want, just put a return later without checking the $sockbr:

on *:SOCKREAD:test-client:{
if ($sockerr) test-stop [CLIENT] SockRead error
sockread 8192 &bvar
return
}

Joined: Apr 2010
Posts: 969
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
Still cannot reproduce after testing the following:

Singular Read per event
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [Client] SockRead error
  sockread 8192 &mybvar
  return
}

Multi-read per event
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [Client] SockRead error
  sockread 4092 &mybvar
  sockread 4092 &mybvar
  return
}

State-specific read per event
Code
on *:SOCKREAD:test-client:{
  if ($sockerr) test-stop [Client] SockRead error
  sockread 1024 &bvar
  while ($sockbr) {
    sockread 1024 &bvar
  }
  return
}


I am SReject
My Stuff
Joined: Dec 2002
Posts: 5,465
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,465
Quote
if ($sockbr == 0) return
I have added this line, in several places, to the on sockread event in my test script and it has made no difference. I also tried:

if ($sockbr == 0) {
echo 4 sockbr is zero
return
}

The above message never displays because $sockbr is never set to zero, which means /return can never be called. I also added just /return to the script in different places.

&binvars are freed automatically at the end of a script. This is completely independent of what a script does and cannot be prevented. So my guess is that the issue you are seeing is not related to &binvars and is due to something else in your script.

I realize that you are trying to help, and it's possible that there is a bug, but if no one here is able to reproduce it, we really need a test script from you that reproduces the issue for you, so we can try to track it down.

Thanks for your help everyone.


Link Copied to Clipboard