mIRC Home    About    Download    Register    News    Help

Print Thread
#247861 01/09/14 07:19 PM
Joined: Jul 2006
Posts: 4,145
W
Wims Offline OP
Hoopy frood
OP Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Although one should always check there are data available before /sockreading, if you /sockread after emptying the receive buffer, mIRC will report there is data to be read, type /testsw :

Code:
alias testsw {
  sockclose testsw
  socklisten testsw 8005
  .timer 1 1 sockopen testsw2 127.0.0.1 8005
}
;sending two bytes, $crlf
on *:sockopen:testsw2:if (!$sockerr) sockwrite -n testsw2
on *:socklisten:testsw:if (!$sockerr) sockaccept testsw1
on *:sockread:testsw1:{
if (!$sockerr) {
var %a 
echo -a $sock($sockname).rq
sockread -f %a
echo -a $qt(%a) -- $ascii(%a)
sockread -f %a
echo -a $qt(%a) -- $ascii(%a)
sockclose testsw*
}
alias -l ascii returnex $regsubex($1-,/(*UTF8)(.)/g,$asc(\1) $+ $chr(32))


Quote:
2
"" --
"ea" -- 9 9 9 9 9 9 101 97


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Thanks for your bug report. I have not been able to reproduce this issue here. If you remove the $ascii() reference and add "echo -a $sock($sockname).rq" before the second /sockread, and add a third /sockread, what results do you see?

Joined: Jul 2006
Posts: 4,145
W
Wims Offline OP
Hoopy frood
OP Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Quote:
#0 sock.rq 2
#1 "" -- sockbr 2 -- sock.rq 0
#2 "ea" -- sockbr 0 -- sock.rq 0
#3 "" -- sockbr 0 -- sock.rq 0

Code:
alias testsw {
  sockclose testsw
  socklisten testsw 8005
  .timer 1 1 sockopen testsw2 127.0.0.1 8005
}
on *:sockopen:testsw2:if (!$sockerr) sockwrite -n testsw2
on *:socklisten:testsw:if (!$sockerr) sockaccept testsw1
on *:sockread:testsw1:{
  if (!$sockerr) { 
    var %a
    echo -a #0 sock.rq $sock($sockname).rq
    sockread -f %a
    echo -a #1 $qt(%a) -- sockbr $sockbr -- sock.rq $sock($sockname).rq
    sockread -f %a
    echo -a #2 $qt(%a) -- sockbr $sockbr -- sock.rq $sock($sockname).rq
    sockread -f %a
    echo -a #3 $qt(%a) -- sockbr $sockbr -- sock.rq $sock($sockname).rq

    sockclose testsw* 
  }
}
All you need to reproduce is a NULL byte somewhere in memory wink After restarting mIRC #2 appears as $null

Last edited by Wims; 01/09/14 08:43 PM.

#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Thanks, I have been able to reproduce this issue. It is not due to a buffer overflow. When you attempt to /sockread and $sock().rq == 0, it clears the %a variable by unsetting it. Any further reference to %a will use the global %a variable. I have changed /sockread so that, in this context, it no longer unsets the variable but sets it to an empty value. This will retain the local variable. This has been fixed for the next version.

Joined: Jul 2006
Posts: 4,145
W
Wims Offline OP
Hoopy frood
OP Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Thanks for answer.

Let me see if I get this right, /sockread will unset the variable because $sock().rq = 0, perfect.
But then, the next /sockread still has $sock().rq = 0, why doesn't mIRC keep unsetting the variable then? If you are saying that the second /sockread is not seeing the variable %a because it has been unset by the previous /sockread and as a result is creating a global variable %a with some value, then this is a quite serious bug and should be fixed. I can't seem to see your logic there.

I strongly suggest you do not change the current behavior, a script might very well using /sockread %a without declaring %a as local, counting on the first /sockread with $sock().rq = 0 to unset it. With this change they would have empty global variable everywhere. This solution also quite does not seem to be the logical fix there.

If it's not a buffer overflow, where does the value of the variable come from? why mIRC sets a value to the variable if /sockread is supposed to unset the variable when $sock().rq = 0?

Why isn't the fix simply to get /sockread to work as intended confused ? I would really appreciate if you could elaborate a bit on this


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Apr 2004
Posts: 871
Sat Offline
Hoopy frood
Offline
Hoopy frood
Joined: Apr 2004
Posts: 871
Originally Posted By: Wims
Let me see if I get this right, /sockread will unset the variable because $sock().rq = 0, perfect.

The first empty result from echo #1 is because you're reading the CR/LF pair.

mIRC unsets the (local) variable %a between #1 and #2, because there is nothing left to read at that point. Right after, your echo #2 prints the value of the global variable %a. This can be demonstrated quite simply with "/set %a foo" before running /testsw.

Originally Posted By: Wims
But then, the next /sockread still has $sock().rq = 0, why doesn't mIRC keep unsetting the variable then?

It does, which is why the global variable %a is also unset between #2 and #3, resulting in an empty string being printed by echo #3.

Originally Posted By: Wims
I strongly suggest you do not change the current behavior, a script might very well using /sockread %a without declaring %a as local, counting on the first /sockread with $sock().rq = 0 to unset it. With this change they would have empty global variable everywhere.

Their fault for writing stupid scripts, but it could easily be fixed by /sockread either emptying or unsetting the variable based on whether it is local or global, respectively.

Originally Posted By: Wims
If it's not a buffer overflow, where does the value of the variable come from?

It is the value of your global variable %a.

Last edited by Sat; 02/09/14 02:43 PM. Reason: clarity

Saturn, QuakeNet staff
Joined: Jul 2006
Posts: 4,145
W
Wims Offline OP
Hoopy frood
OP Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
You missed the point.
That mIRC evaluates %a in #2, that's correct behavior, if during that process, %a is not found as local but is found as global and its value is returned, that's also correct.
If you make me set a global variable %a, and mIRC evaluates that variable just like we agree it should, yes I'll get that value, still correct behavior, but that's irrelevant to the point, which is that I specified I had no global variables set before running the test.
I can make a video if you don't trust this is possible.

With that in mind, if there are no global variables set prior the test and that you type /testsw and you get a value different from $null for #2, how do you explain it?

I'll try to reproduce again because it really sounds like I had a global %a set, in any case the behavior should not be changed.

Last edited by Wims; 02/09/14 04:38 PM.

#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
I am indeed assuming that you had a global %a variable set before running the script. If you did not, this means that something else is going on. If you install a clean copy of mIRC, with no scripts, and test the above script do you see the same issue?

Last edited by Khaled; 02/09/14 04:50 PM.
Joined: Apr 2004
Posts: 871
Sat Offline
Hoopy frood
Offline
Hoopy frood
Joined: Apr 2004
Posts: 871
Originally Posted By: Wims
You missed the point [..], which is that I specified I had no global variables set before running the test.

I don't see this mentioned anywhere in the thread so far. Even if you had mentioned it, you may still be wrong about it.

Originally Posted By: Wims
if there are no global variables set prior the test and that you type /testsw and you get a value different from $null for #2, how do you explain it?

Could it be that you're just overlooking some other script that sets the global variable %a somewhere? It may help to test it against $null right before the "var %a" line.


Saturn, QuakeNet staff
Joined: Apr 2010
Posts: 969
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
Tested on a clean copy, with a slightly updated script to check the read %var scope:
Code:
alias testsw {
  ;set %a $null

  sockclose testsw*
  socklisten testsw 8005
  .timer 1 1 sockopen testsw2 127.0.0.1 8005
}
on *:socklisten:testsw:{
  if (!$sockerr) sockaccept testsw1
}
on *:sockopen:testsw2:{
  if (!$sockerr) sockwrite testsw2 1
}
on *:sockread:testsw1:{
  if (!$sockerr) {
    var %a
        
    echo -a #0 sock.rq $sock($sockname).rq

    sockread -f %a
    echo -a #1: $qt(%a) -- var[ $var(%a, 1).global - $var(%a, 2).local ] -- sockbr $sockbr -- sock.rq $sock($sockname).rq

    sockread -f %a
    echo -a #2: $qt(%a) -- var[ $var(%a, 1).global - $var(%a, 2).local ] -- sockbr $sockbr -- sock.rq $sock($sockname).rq

    sockread -f %a
    echo -a #3: $qt(%a) -- var[ $var(%a, 1).global - $var(%a, 2).local ] -- sockbr $sockbr -- sock.rq $sock($sockname).rq

    sockclose testsw* 
  }
}


I also tested commenting the "var %a" line in the on sockread event and adding "set %a $null" to the /testws alias. The results are the same. The variable gets unset by the 2nd sockread regardless of scope:
Code:
#0 sock.rq 1
#1: "1" -- var[ %a - ] -- sockbr 1 -- sock.rq 0
#2: "" -- var[ - ] -- sockbr 0 -- sock.rq 0
#3: "" -- var[ - ] -- sockbr 0 -- sock.rq 0

AND

#0 sock.rq 1
#1: "1" -- var[ - %a ] -- sockbr 1 -- sock.rq 0
#2: "" -- var[ - ] -- sockbr 0 -- sock.rq 0
#3: "" -- var[ - ] -- sockbr 0 -- sock.rq 0


I am SReject
My Stuff
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Quote:
I strongly suggest you do not change the current behavior, a script might very well using /sockread %a without declaring %a as local, counting on the first /sockread with $sock().rq = 0 to unset it. With this change they would have empty global variable everywhere.

A script depending on a /sockread to unset a global variable may not be wise as a /sockread in that context may not always take place, depending on how the script is written. However, I will change the fix so that it will only unset the variable if it is global. This means that in your example script, the local variable would remain in place until the local scope is exited, which would prevent the side-effect of a global variable being read unexpectedly.

Joined: Jul 2006
Posts: 4,145
W
Wims Offline OP
Hoopy frood
OP Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Right, I was just saying the current behavior is fine. If anything the thing to do would be to document that /sockread currently unset the variable if $sock().rq = 0.
I'm not saying scripts are relying on this but I don't think it's a good idea to treat a global and a local variable differently in this situation, I can only see this leading to troubles though the purpose is to avoid them

Anyway, I've been trying to reproduce this again on a clean 7.36 and my current 7.36 with no success so far.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel

Link Copied to Clipboard