Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / April 2005

Tip: Looking for answers? Try searching our database.

ECMA Wrong - Class and Object Initialization Rules - Help!

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
George - 12 Apr 2005 11:25 GMT
Hi,

ECMA states in Section 1.8.1.4 (Partition III) on Class and Object
Initialization Rules:

"An object constructor shall not return unless a constructor for the base
class or a different construct for the object's class has been called on the
newly constructed object. The verification algorithm shall treat the this
pointer as uninitialized unless the base class constructor has been called."

This means in particular that, if a .ctor didn't invoke a base class .ctor
but another .ctor of the same class, then the "this" pointer is not
initialized. For example, class A has 2 .ctors that invoke eachother:
recursive constructor invocation is allowed at the bytecode level!

BUT, the examples I tried show that the "this" pointer is initialized even
after invoking another .ctor of the same class - for example I can load the
"this" into a local variable.

SO, it seems to me that the "this" is considered initialized also after
invoking a ctor of the same class and NOT ONLY a ctor of the base class!

====================================

There is another issue which is not clear.

Looking in the ROTOR source, I found the following commented idea:

"If there are any locals (or arg slot 0) containing uninit vars, it is
illegal to be in a try block."

This corresponds to error "VER_E_THIS_UNINIT_EXCEP" "Uninitialized this on
entering a try block"

Beside the fact that this is not documented in ECMA, I cannot have it
confirmed by examples.

Is this verification error still checked in the current version of the
verifier?

Many thanks for any help!

George
Daniel O'Connell [C# MVP] - 14 Apr 2005 20:24 GMT
> Hi,
>
[quoted text clipped - 7 lines]
> pointer as uninitialized unless the base class constructor has been
> called."

ALl that says is that the "verification algorithm shall treat the this
pointer as uninitialized", it does not say that the variable will *be*
uninitialized. What these means is that during verification the verifier
should look at the constructor, see it doesn't call the base, and treat this
as an uninitialized variable. It doesn't mean that the variable will be null
when a base constructor is not called.

I suspect your examples are valid but unverifiable, try running peverify on
your examples and see what it has to say.
George - 15 Apr 2005 10:23 GMT
Hi Daniel,

> ALl that says is that the "verification algorithm shall treat the this
> pointer as uninitialized", it does not say that the variable will *be*
> uninitialized. What these means is that during verification the verifier
> should look at the constructor, see it doesn't call the base, and treat this
> as an uninitialized variable.

I've completely understood that this is a verification issue - see also the
end of my previous post:

"What I'm complaining about is a verification rule not correctly specified in
the ECMA Standard."

> I suspect your examples are valid but unverifiable, try running peverify on
> your examples and see what it has to say.

I'm sure they are verifiable because I've run the "peverify". This bothers
me actually: STRICTLY according to the ECMA verification rule, the example
where the .ctor-s of the same class (A) invoke each other and one .ctor
stores the "this" pointer in a local variable SHOULD be rejected by the
verifier. This does *not* happen.

So, what I suspect is that the ECMA verification rules do not match the
implementation of peverify.

Regards,
George
Daniel O'Connell [C# MVP] - 15 Apr 2005 21:12 GMT
> Hi Daniel,
>
[quoted text clipped - 12 lines]
> in
> the ECMA Standard."

Which says nothing about you undrstanding that its a verification rule, your
post came across as if you expected the code to simply not work. You never
mentioned actually trying to verify it using peverify or any other tool.
Remember no one can read your mind, you have to be explicit.

>> I suspect your examples are valid but unverifiable, try running peverify
>> on
[quoted text clipped - 5 lines]
> stores the "this" pointer in a local variable SHOULD be rejected by the
> verifier. This does *not* happen.

It should, yes, but that it does not is not a problem with the standard.
peverify is not what I would consider the definate standard, but only an
implementation of it, one that is apparently not complete at that.
I am curious, have you tried running your code under a user account that
doesn't grant rights to unverifiable code(ie not an Administrator?) If this
particular problem exists in the runtime as well as in peverify, then that
may well be a significant problem (it certainly allows some ugly hacks, if
nothing else).

Also, if you could post a complete example of your IL I'll take a whack at
it with the newest verifier I have available, it might have been a bug in
the 1.x framework(which framework are you using, btw?). Until we see the 2.0
standard(assuming there is one), its impossible to say that the rule is
still in effect, but I assume it should be.
George - 16 Apr 2005 09:06 GMT
Hi Daniel,

> Which says nothing about you undrstanding that its a verification rule, your
> post came across as if you expected the code to simply not work. You never
> mentioned actually trying to verify it using peverify or any other tool.
> Remember no one can read your mind, you have to be explicit.

Sorry, you are right - I was not explicit enough.

> It should, yes, but that it does not is not a problem with the standard.
> peverify is not what I would consider the definate standard, but only an
> implementation of it, one that is apparently not complete at that.
> I am curious, have you tried running your code under a user account that
> doesn't grant rights to unverifiable code(ie not an Administrator?)

I tried after you suggested it. And the answer is the same.

> Also, if you could post a complete example of your IL I'll take a whack at
> it with the newest verifier I have available, it might have been a bug in
> the 1.x framework(which framework are you using, btw?).

I'm using peverify 1.1.4322.573

Thank you very much for having a look at the code! Here is it:

==================================

//  Microsoft (R) .NET Framework IL Disassembler.  Version 1.1.4322.573
//  Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

.assembly extern mscorlib
{
 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         //
.z\V.4..
 .ver 1:0:5000:0
}
.assembly Test113
{
 // --- The following custom attribute is added automatically, do not
uncomment -------
 //  .custom instance void
[mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool,
 //                                                                        
      bool) = ( 01 00 00 01 00 00 )
 .hash algorithm 0x00008004
 .ver 0:0:0:0
}
.module Test113.exe
// MVID: {732B486A-F0FA-451D-A4C6-FBD9B16BFF9F}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x03020000
//
// ============== CLASS STRUCTURE DECLARATION ==================
//
.class private auto ansi beforefieldinit Test
      extends [mscorlib]System.Object
{
} // end of class Test

.class private auto ansi beforefieldinit A
      extends [mscorlib]System.Object
{
} // end of class A

// =============================================================

// =============== GLOBAL FIELDS AND METHODS ===================

// =============================================================

// =============== CLASS MEMBERS DECLARATION ===================
//   note that class flags, 'extends' and 'implements' clauses
//          are provided here for information only

.class private auto ansi beforefieldinit Test
      extends [mscorlib]System.Object
{
 .method private hidebysig static void  Main() cil managed
 {
   .entrypoint
   // Code size       9 (0x9)
   .maxstack  3
   .locals init (class A V_0)
   IL_0000:  ldc.i4.1
   IL_0001:  ldc.i4.3
   IL_0002:  newobj     instance void A::.ctor(int32,
                                               int32)
   IL_0007:  stloc.0
   IL_0008:  ret
 } // end of method Test::Main

 .method public hidebysig specialname rtspecialname
         instance void  .ctor() cil managed
 {
   // Code size       7 (0x7)
   .maxstack  1
   IL_0000:  ldarg.0
   IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
   IL_0006:  ret
 } // end of method Test::.ctor

} // end of class Test

.class private auto ansi beforefieldinit A
      extends [mscorlib]System.Object
{
 .method public hidebysig specialname rtspecialname
         instance void  .ctor(int32 i,
                              int32 j) cil managed
 {
   .maxstack  3
   .locals init (class A V_0)
   ldarg 0
   ldarg.1
   ldarg.2
   add
   call       instance void A::.ctor(int32)

   // here we store the this pointer into a local var.
   // this should be allowed by verifier only if the this is initialized
   ldarg 0
   stloc 0

   ret
 } // end of method A::.ctor

 .method public hidebysig specialname rtspecialname
         instance void  .ctor(int32 i) cil managed
 {
   .maxstack  3
 ldarg.0
 ldarg.1
 ldarg.1
 call       instance void A::.ctor(int32,int32)
 ret
 } // end of method A::.ctor

} // end of class A
Matt Grice [MSFT] - 20 Apr 2005 19:27 GMT
'Initialization' in this context has only to do with the state of the
object, specifically the state of whether constructors have been called.

Your recursive example is verifiable because it will never return without
calling the base class constructor.  Of course, it will never return,
period.

The 'uninitialized this on entering a try block' restriction is implemented
in PEVerify and the x64 & Itanium JIT verifiers for Whidbey Beta2.  I
believe it is being considered for inclusion in ECMA.

> Hi,
>
[quoted text clipped - 42 lines]
>
> George
George - 20 Apr 2005 19:53 GMT
Thank you Matt,

> Your recursive example is verifiable because it will never return without
> calling the base class constructor.  Of course, it will never return,
> period.

How does the verifier know that the example will never return. Isn't the
verification performed per method? Maybe I missunderstood ...

> The 'uninitialized this on entering a try block' restriction is implemented
> in PEVerify and the x64 & Itanium JIT verifiers for Whidbey Beta2.  I
> believe it is being considered for inclusion in ECMA.

Thank you for the info. What is actually the reason for not having an
uninitialized "this" in a try block?

Thank you again for the answers!
Best,
George
Matt Grice [MSFT] - 21 Apr 2005 02:30 GMT
> Thank you Matt,
>
[quoted text clipped - 4 lines]
> How does the verifier know that the example will never return. Isn't the
> verification performed per method? Maybe I missunderstood ...

A constructor must do one of two things before returning: call another
constructor of the same class or call a constructor of the base class.
Every other constructor must also obey the same rules.  You can see that if
you have a class where no constructor calls the base class constructor
before returning, every constructor must instead call another constructor of
the same class for those constructors to be verifiable.  The result is
infinite recursion -- none of the constructors will return.

Applying the rules on a per-method basis is sufficient to determine that
either the base class constructor is eventually called *or* the constructor
never returns.  Since it operates on the per-method basis, the verifier
cannot know which of these is the case, but either one satisfies the
constraint in ECMA.

>> The 'uninitialized this on entering a try block' restriction is
>> implemented
[quoted text clipped - 3 lines]
> Thank you for the info. What is actually the reason for not having an
> uninitialized "this" in a try block?

To satisfy the requirements in 1.8.1.4 the verifier must determine that a
constructor is called on all paths from entry to exit.  This can get
complicated in the presence of exception handling.  In addition, the current
ECMA rules, while more lenient, do not actually give you much useful
flexibility.

example:
try {
   call .baseCtor
}
catch
{
}
return

This is not a verifiable constructor because there is a path from entry to
return where no qualifying constructor is called.  An exception could happen
before or during the call to .baseCtor, end up in the catch block, and
return.  To make it verifiable you would have to transform the code to
something like:

example:
try {
   call .baseCtor
}
catch
{
   call .baseCtor
}
return

This insures that a qualifying constructor is called on all paths, but it
also leaves open the possibility that .baseCtor is called twice.  This is
not illegal but it is usually undesirable.

Hope this helps,
Matt
George - 21 Apr 2005 08:10 GMT
Matt,

many thanks!! now everything is clear to me!

George

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.