CIL / MSIL Boxing issue? - cil

I thought I knew how boxing and unboxing works, but apparently I don't, because what I would expect to compile properly,
// the start of my Program::Main()
.maxstack 8 // Yes I know it's a large stack size for
// the given method; it's just a test program ;)
.entrypoint
ldc.i4 10
box int32
unbox int32 // Removing these two lines
box int32 // makes it run properly
call void [mscorlib]System.Console::WriteLine(object)
ret
instead throws an error saying "Invalid IL code in Program:Main(): box 0x1b000004."
From my understanding, the operations went like this:
// instruction: stack after instruction is run:
ldc.i4 10 // 10
box int32 // object(int32,10)
unbox int32 // 10
box int32 // should be object(int32,10), but instead, got an error.
I tried removing the unboxing and re-boxing, and it runs fine. Also, removing the call to WriteLine and the second boxing, just leaving an int, then discarding the int from the stack runs fine. For some strange reason, boxing, unboxing, then reboxing throws an error.
So, what's different during the second boxing that causes it to throw an error instead of executing like the first?

unbox pushes a managed pointer to the value onto the evaluation stack, not the value itself. Try using unbox.any instead. – Lee

Related

How can I pass a Perl 6 object through a Nativecall callback?

I'm working with the NativeCall interface.
The library is going to call my callback function a bunch of times.
That works fine. I can just declare my callback with the right
signature, pass it in as &callback and the library calls the sub just
fine.
It also has the capability to set a payload void *pointer to anything
I want, and it will include that in the call to my callback function.
Can I hide a Perl Str, for example, in the payload and successfully round trip it?
sub set_userdata(Pointer) returns int32 is native { ... }
sub set_callback(&callback(Pointer $userdata --> int32)) returns int32 is native { ... }
sub callback(Pointer $userdata) returns int32 {
my Str $mystring = ???
...
}
my Str $my-userdata-string;
set_userdata(???);
set_callback(&callback);
It seems like it could work with some incantation of binding, "is rw", nativecast() and/or .deref.
You can only use a native representation in such a case (such as CStruct, CArray, and CPointer), or alternatively a Blob. You are also responsible for ensuring that you keep a reference to the thing you pass as userdata alive from Perl 6's perspective also, so the GC doesn't reclaim the memory that was passed to the C function.
Memory management is the reason you can't pass any old Perl 6 object off to a C function: there's no way for the GC to know whether the object is still reachable through some C data structure it can't introspect. In a VM like MoarVM objects are moved around in memory over time as part of the garbage collection process also, meaning that the C code could end up with an out-dated pointer.
An alternative strategy is not not pass a pointer at all, but instead pass an integer and use that to index into an array of objects. (That's how the libuv binding inside of MoarVM tracks down the VM-level callbacks, fwiw.)
I got around this by just ignoring the userdata and making a new closure referencing the Perl object directly for every callback function. Since there is a new closure created every time I set the callback, I think this will leak memory over time.

StringTemplate Probable I/O race condition detected while copying memory

Hy,
In my project I am using Antlr.StringTemplate.StringTemplateGroup class in order to create a localized template. I access the .st file and set the desired attributes as below.
public StringTemplate WrapValuesReportTemplateContent(
private StringTemplateGroup StringTemplateGroup = new StringTemplateGroup(StringTemplateGroupName);
StringTemplate stringTemplate = this.StringTemplateGroup.GetInstanceOf(path);
stringTemplate.SetAttribute("atr1", value1);
stringTemplate.SetAttribute("atr2", value2);
return stringTemplate
)
The class is repeatedly used by a manager and due to this reason the following exception was triggered.
System.IndexOutOfRangeException: Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithread applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader.
at System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount)
at System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count)
at System.IO.TextWriter.WriteLine(String value)
at System.IO.TextWriter.SyncTextWriter.WriteLine(String value)
at Antlr.StringTemplate.ConsoleErrorListener.Error(String s, Exception e)
at Antlr.StringTemplate.StringTemplate.BreakTemplateIntoChunks()
I am quire new to StringTemplate and it's not clear for me how StringTemplates really work. From the error description I understand that the .st resource is not closed. And I have the following questions:
When creating a new StringTemplate we create a Stream for writing and reading to the .st file, or a new object where we modify the attributes
After a .st file is opened is it closed automatically once it gets out of scope
How is the best approach in order to avoid this error. We should use locks on the resources, or wrap everything in a using?
Any clarification would be very useful.
Thanks
You could try synchronizing accesses on the stringTemplate object.
My guess is that you will only need to synchronize if you are simultaneously modifying it and reading or modifying it. If you are just reading it, it doesn't usually matter.
lock (stringTemplate)
{
// Access thread-sensitive resources.
}
For efficiency reasons, you should keep your synchronized block as small as possible; just with the stringTemplate access.
I've recently encountered the same bug!
Look at your stacktrace: it is thrown from ConsoleErrorListener.
To be short, the exception is thrown because of two threads are trying to write to Console.Out stream.
To eliminate this error You should override error handler for your template.
The solution which is marked as answer will work, but there will be too much lock contention.

NullReferenceException on bool, int, or other stack variable

First of all: the title of this post does not match the actual question I have.
But I am also supplying the answer to the original problem (NullRefExcp on bool), so other users will find it's solution here by the chosen title.
I have a class, similar to the following:
ref class CTest
{
bool m_bInit;
void func()
{
if (!m_bInit)
return;
...
}
...
}
Today I had the problem that func crashed with a NullReferenceException at some point although it had been executed successfully many times before.
The exception occured in the line if (!m_bInit)!
I know, you all are saying now, that this is impossible. But it actually was this line. The reason was following:
I have two different variables, both named oTest, but at different places. One of them was initialized: oTest = gcnew CTest. Calling func on this oTest worked well. The first call of func on the other oTest failed with the exception from above. The curious thing is, that the crash seems to happen at the query on m_bInit, also the stacktrace of the exception tells so. But this was just the first place where a member of the not initialized object (it was still nullptr) was called.
Therefore, the advice for other users with the same problem: Check the stack backwards to find a function call on an object that is nullptr/null.
My question now is:
Why does the execution not fail on the first call of a function of oTest which is nullptr?
Why is the function entered and executed until the first access to a member?
Actually, in my case 3 functions were entered and a couple of variables were created on the stack and on the heap...
This code:
void func()
{
if (!m_bInit)
return;
...
}
could actually be written as:
void func()
{
if (!this->m_bInit)
return;
...
}
Hopefully now you can see where the problem comes from.
A member function call is just a regular function call that includes the this parameter implicitly (it's passed along with the other parameters).
The C++/CLI compiler won't perform a nullptr check when calling non-virtual functions - it emits a call MSIL opcode.
This is not actually the case in C#, since the C# compiler will emit the callvirt MSIL opcode even for non-virtual functions. This opcode forces the JIT to perform a null check on the target instance. The only ways you could get this error in C# is by calling the function via reflection or by generating your own IL that uses the call opcode.

Sponsor's Renewal function stops being called

I have a server and client process both running on the same machine. The client creates a CAO object and uses it for some time (<1s up to hours). It takes a lot of memory so I want to dispose of this object as soon as possible after the client finishes with it.
I set InitialLeaseTime and RenewOnCallTime to 10s (0.1s and 15s have the same problem). I can see that for a few minutes, the sponsor's Renweal functon is being called every 10s. After several minutes the client starts doing different kind of work and the sponsor stops being called (this seems wrong). A few minutes later when the client tries to use the remote object, it throws an exception saying it has been disconnected (probably because the sponsor wasn't called for a long time).
It seems like the lease manager somehow stops trying to check the lease after a while.
Long time in-between responses, but I figure others may run into this issue too, so here goes.
I'd recommend attaching to your server in VS, going to the Debug menu, choosing 'exceptions,' and then checking the 'System.Net.Sockets.SocketException' exception. This will break your program on any socket exception that occurs.
In my case, I've recently begun seeing this issue, and after a lot of debugging noticed that just before the Lease Manager stops checking for leases, a SocketException was occurring. In my case, the socket exception was AddressChangedCallback, with the stack trace:
1 [External Code]
2 System.dll!System.Net.Dns.TryGetAddrInfo(string name = "me.win.mycompany.com", System.Net.AddressInfoHints flags, out System.Net.IPHostEntry hostinfo = null)
3 System.dll!System.Net.Dns.GetAddrInfo(string name)
4 System.dll!System.Net.Dns.InternalGetHostByName(string hostName, bool includeIPv6)
5 System.dll!System.Net.Dns.GetHostEntry(string hostNameOrAddress)
6 System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.UpdateCachedIPAddresses()
7 System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.OnNetworkAddressChanged(object sender = null, System.EventArgs e = {System.EventArgs})
8 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
9 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
10 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
11 System.dll!System.Net.NetworkInformation.NetworkChange.AddressChangeListener.AddressChangedCallback(object stateObject, bool signaled)
12 mscorlib.dll!System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(object state, bool timedOut)
13 [External Code]
This AddressChangedCallback, which, in my case, seems to be related to a network adapter going down or being changed (you can see your network adapters by holding windows+r then typing ncpa.cpl - if you have two or more it's possible this event is caused by you switching between them) appeared to cause the socket to stop reading. This meant that the next time the LeaseManager went to use the remoting connection to check the remote lease, it couldn't read that lease from the dead socket. So, it did the reasonable thing - disconnect that sponsor, since we can't read it anymore, and remove it from the list of sponsors for the object. And since it's probably the only sponsor for the object in question, that object then gets unsponsored by the LeaseManger, leaving it free for the GC to eventually pick up.
One approach to solving this is to, in your InitializeLifetimeService() method, return null instead of setting timeouts. This bypasses the LeaseManager, so you never have to worry about the object getting de-sponsored due to a socket exception, since you're not using leases in the first place. However, if you're like me, this also means you could have a buildup of objects and unmanaged resources over a period of time on the server. The only way around the buildup issue that I can see is making your remoting object implement Dispose, and making sure that you Dispose it when you're finished with it. Basically, you can't rely on the LeaseManager handling garbage collection, so you'll have to do GC yourself, the ol' fashioned way.
Also worthy of note: the ITrackingHandler object will allow you to track when LeaseManager-related objects are Disconnected, Marshaled, and Unmarshaled. It was a big help in figuring out what was going on, since I could see that an object was being disconnected, instead of inferring it from the fact that the calls stopped happening.
I've worked around it by putting the sponsor on the server instead of the client. The server side sponsor seems to be reliably called enough to keep the remote object alive.
Class SelfSponsor
Implements ISponsor
Public Function Renewal(ByVal lease As ILease) As System.TimeSpan Implements ISponsor.Renewal
Return lease.RenewOnCallTime
End Function
End Class
And in the class of the MarshalByRef remote object:
Private Sponsor As SelfSponsor
Public Sub SponsorYourself()
Sponsor = New SelfSponsor
DirectCast(GetLifetimeService(), ILease).Register(Sponsor)
End Sub
Public Sub UnSponsorYourself()
DirectCast(GetLifetimeService(), ILease).Unregister(Sponsor)
End Sub
Somehow the SponsorYourself() code throws an exception if it's placed in the constructor so the client calls SponsorYourself immediately after creating the object.
This would be a bad solution if the server is always running and clients come and go because if a client exits abnormally without explicitly calling UnsponsorYourself() then the object will stay alive forever. But in my case the server is started and stopped by the client so that doesn't matter.

Trivial bit of IL does not work under Mono

I have some .net code that generates an assembly then runs it. It has worked reliably under .net for some time. Under Mono the code works on some non-trivial instances but on others it dies with an illegal IL exception.
When attempting to isolate the problem I cut it down to the point where it just returns a native int. The example works fine under .net and dies under Mono. Reflector says the code is as follows, and this is as expected:
.method public hidebysig static native int Main() cil managed
{
.maxstack 8
L_0000: ldc.i8 4
L_0009: ret
}
The exception I get is: System.InvalidProgramException: Invalid IL code in HelloWorldType:Main (): IL_0009: ret
What am I doing wrong, please?
I would guess: An i8 is not considered the same type as a native int. If you want to return a native int, you'd need a conv.i in the middle. A native int is 8 bytes on a 64-bit platform but only 4 bytes on a 32-bit platform.