Bleeding Edge 2008: Postback 

I'm sorry it took a week, but here we go.

This is my exit content from Bleeding Edge 2008. I'm also posting complete conference contents, just in case.

Thanks go out to Dušan, Dejan, Miha, Miha and Miha.

Downloads:

Remark: PPT in Slovene only. Code international.

Thank you for attending. Hope to see you next year!

Categories:  CLR | Conferences | Microsoft | Web Services | Work
Thursday, October 09, 2008 8:42:02 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 On Instance and Static Method Signatures 

We talked today, with Miha, a C# Yoda. Via IM, everything seemed pointless. Couldn't find a good case for the cause of the following mind experiment:

using System;
class Tubo
{
  public static void Test() {}
  private void Test() {} 
}

Note: I'm using Miha's syntax in this post.

We have a static method called Test and an instance method, also called Test. Parameter models of both methods are the same, empty.

Would this compile?

It does not.

The question is why and who/what causes this. There is actually no rationale behind not allowing this thing to compile since both, the compiler and the runtime know the method info upfront.

Since the runtime has all the information it needs, it is strange that this would not be allowed at compile time. However, a (C#) compiler has to determine whether you, the programmer meant to access a static or an instance method.

Here lie the dragons.

It is illegal in most virtual machine based languages to have the same method name and signature for a static/instance method.

The following is an excerpt from a Java specification:

8.4.2 Method Signature

Two methods have the same signature if they have the same name and argument types.

Two method or constructor declarations M and N have the same argument types if all of the following conditions hold:

  • They have the same number of formal parameters (possibly zero)
  • They have the same number of type parameters (possibly zero)
  • Let <A1,...,An> be the formal type parameters of M and let <B1,...,Bn> be the formal type parameters of N. After renaming each occurrence of a Bi in N's type to Ai the bounds of corresponding type variables and the argument types of M and N are the same.

Java (and also C#) does not allow two methods with the same name and parameter model no matter what the access modifier is (public, private, internal, protected ...) and whether the method is static or instance based.

Why?

Simple. Programmer ambiguity. There is no technical reason not to allow it.

Consider the following:

using System;
class Tubo
{
  public static void Test();
  private void Test();
  public void AmbiguousCaller() { Test(); }
}

What would method AmbiguousCaller call? A static Test or instance Test method?

Can't decide?

That's why this is not allowed.

And yes, it would call the instance method if this would be allowed, since statics in C# should be called using a class name, as in Test.Test(). Note that the preceding example does not compile. Also note, that it is legal to have a AmbiguousCaller body as Test() or Tubo.Test().

There is another ambiguous reason. Local variables in C# cannot be named the same as the enclosing class. Therefore, this is illegal:

using System;
class Tubo
{
  private int Tubo;
}

It is. Do a csc /t:library on it.

Since you confirmed this fact, consider the following:

using System;
public class Tubo
{
  public static void StaticMethod() {}
  public void InstanceMethod() {}
}

public class RunMe
{
  public static void Main()
  {
    Tubo Tubo = new Tubo();
    Tubo.InstanceMethod();
    Tubo.StaticMethod();
  }
}

Focus on the Main method body. In Tubo.InstanceMethod() an instance method is called and a reference (namely Tubo) is used. In Tubo.StaticMethod() a static method is called and Tubo is not an instance reference, but class name.

It all comes down to programmer ambiguity. Given a chance, I would support this design decision too.

Categories:  CLR
Saturday, November 03, 2007 10:04:38 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 XmlSerializer, Ambient XML Namespaces and Digital Signatures 

If you use XmlSerializer type to perform serialization of documents which are digitally signed later on, you should be careful.

XML namespaces which are included in the serialized form could cause trouble for anyone signing the document after serialization, especially in the case of normalized signature checks.

Let's go step by step.

Suppose we have this simple schema, let's call it problem.xsd:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="
http://www.gama-system.com/problems.xsd"
           elementFormDefault="qualified"
           xmlns="
http://www.gama-system.com/problems.xsd"
           xmlns:xs="
http://www.w3.org/2001/XMLSchema">
  <xs:element name="Problem" type="ProblemType"/>
  <xs:complexType name="ProblemType">
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Severity" type="xs:int" />
      <xs:element name="Definition" type="DefinitionType"/>
      <xs:element name="Description" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="DefinitionType">
    <xs:simpleContent>
      <xs:extension base="xs:base64Binary">
        <xs:attribute name="Id" type="GUIDType" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:simpleType name="GUIDType">
    <xs:restriction base="xs:string">
      <xs:pattern value="Id-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-
                         [0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

This schema describes a problem, which is defined by a name (typed as string), severity (typed as integer), definition (typed as byte array) and description (typed as string). The schema also says that the definition of a problem has an Id attribute, which we will use when digitally signing a specific problem definition. This Id attribute is defined as GUID, as the simple type GUIDType defines.

Instance documents validating against this schema would look like this:

<?xml version="1.0"?>
<Problem xmlns="
http://www.gama-system.com/problems.xsd">
  <Name>Specific problem</Name>
  <Severity>4</Severity>
  <Definition Id="c31dd112-dd42-41da-c11d-33ff7d2112s2">MD1sDQ8=</Definition>
  <Description>This is a specific problem.</Description>
</Problem>

Or this:

<?xml version="1.0"?>
<Problem xmlns="http://www.gama-system.com/problems.xsd">
  <Name>XML DigSig Problem</Name>
  <Severity>5</Severity>
  <Definition Id="b01cb152-cf93-48df-b07e-97ea7f2ec2e9">CgsMDQ8=</Definition>
  <Description>Ambient namespaces break digsigs.</Description>
</Problem>

Mark this one as exhibit A.

Only a few of you out there are still generating XML documents by hand, since there exists a notion of schema compilers. In the .NET Framework world, there is xsd.exe, which bridges the gap between the XML type system and the CLR type system.

xsd.exe /c problem.xsd

The tool compiles problem.xsd schema into the CLR type system. This allows you to use in-schema defined classes and serialize them later on with the XmlSerializer class. The second instance document (exhibit A) serialization program would look like this:

// generate problem
ProblemType problem = new ProblemType();
problem.Name = "XML DigSig Problem";
problem.Severity = 5;
DefinitionType dt = new DefinitionType();
dt.Id = Guid.NewGuid().ToString();
dt.Value = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xf };
problem.Definition = dt;
problem.Description = "Ambient namespaces break digsigs.";

// serialize problem
XmlSerializer ser = new XmlSerializer(typeof(ProblemType));
FileStream stream = new FileStream("Problem.xml", FileMode.Create, FileAccess.Write);
ser.Serialize(stream, problem);
stream.Close();
           
Here lie the dragons.

XmlSerializer class default serialization mechanism would output this:

<?xml version="1.0"?>
<Problem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns="http://www.gama-system.com/problems.xsd">
  <Name>XML DigSig Problem</Name>
  <Severity>5</Severity>
  <Definition Id="b01cb152-cf93-48df-b07e-97ea7f2ec2e9">CgsMDQ8=</Definition>
  <Description>Ambient namespaces break digsigs.</Description>
</Problem>

Mark this one as exhibit B.

If you look closely, you will notice two additional prefix namespace declarations in exhibit B bound to xsi and xsd prefixes, against exhibit A.

The fact is, that both documents (exhibit B, and exhibit A) are valid against the problem.xsd schema.

<theory>

Prefixed namespaces are part of the XML Infoset. All XML processing is done on XML Infoset level. Since only declarations (look at prefixes xsi and xsd) are made in exhibit B, the document itself is not semantically different from exhibit A. That stated, instance documents are equivalent and should validate against the same schema.

</theory>

What happens if we sign the Definition element of exhibit B (XmlSerializer generated, prefixed namespaces present)?

We get this:

<?xml version="1.0"?>
<Problem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns="http://www.gama-system.com/problems.xsd">
  <Name>XML DigSig Problem</Name>
  <Severity>5</Severity>
  <Definition Id="b01cb152-cf93-48df-b07e-97ea7f2ec2e9">CgsMDQ8=</Definition>
  <Description>Ambient namespaces break digsigs.</Description>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/...20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/...rsa-sha1" />
      <Reference URI="#Id-b01cb152-cf93-48df-b07e-97ea7f2ec2e9">
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>k3gbdFVJEpv4LWJAvvHUZZo/VUQ=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>K8f...p14=</SignatureValue>
    <KeyInfo>
      <KeyValue>
        <RSAKeyValue>
          <Modulus>eVs...rL4=</Modulus>
          <Exponent>AQAB</Exponent>
        </RSAKeyValue>
      </KeyValue>
      <X509Data>
        <X509Certificate>MIIF...Bw==</X509Certificate>
      </X509Data>
    </KeyInfo>
  </Signature>

</Problem>

Let's call this document exhibit D.

This document is the same as exhibit B, but has the Definition element digitally signed. Note the /Problem/Signature/SingedInfo/Reference[@URI] value. Digital signature is performed only on the Definition element and not the complete document.

Now, if one would validate the same document without the prefixed namespace declarations, as in:

<?xml version="1.0"?>
<Problem xmlns="http://www.gama-system.com/problems.xsd">
  <Name>XML DigSig Problem</Name>
  <Severity>5</Severity>
  <Definition Id="b01cb152-cf93-48df-b07e-97ea7f2ec2e9">CgsMDQ8=</Definition>
  <Description>Ambient namespaces break digsigs.</Description>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    ...
  </Signature>

</Problem>

... the signature verification would fail. Let's call this document exhibit C.

<theory>

As said earlier, all XML processing is done on the XML Infoset level. Since ambient prefixed namespace declarations are visible in all child elements of the declaring element, exhibits C and D are different. Explicitly, element contexts are different for element Definition, since exhibit C does not have ambient declarations present and exhibit D does. The signature verification fails.

</theory>

Solution?

Much simpler than what's written above. Force XmlSerializer class to serialize what should be serialized in the first place. We need to declare the namespace definition of the serialized document and prevent XmlSerializer to be too smart. The .NET Framework serialization mechanism contains a XmlSerializerNamespaces class which can be specified during serialization process.

Since we know the only (and by the way, default) namespace of the serialized document, this makes things work out OK:

// generate problem
ProblemType problem = new ProblemType();
problem.Name = "XML DigSig Problem";
problem.Severity = 5;
DefinitionType dt = new DefinitionType();
dt.Id = Guid.NewGuid().ToString();
dt.Value = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xf };
problem.Definition = dt;
problem.Description = "Ambient namespaces break digsigs.";

// serialize problem
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add(String.Empty, "http://www.gama-system.com/problem.xsd");

XmlSerializer ser = new XmlSerializer(typeof(ProblemType));
FileStream stream = new FileStream("Problem.xml", FileMode.Create, FileAccess.Write);
ser.Serialize(stream, problem, xsn);
stream.Close();

This will force XmlSerializer to produce a valid document - with valid XML element contexts, without any ambient namespaces.

The question is, why does XmlSerialzer produce this namespaces by default? That should be a topic for another post.

Categories:  CLR | XML
Wednesday, September 19, 2007 9:57:57 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 CoreCLR Exposed 

Jamie Cansdale of TestDriven.NET fame just posted an intro post describing the hosting of Silverlight's CLR - CoreCLR.

Having the ability to host the runtime inside a Win32/.NET process brings up new possibilities, especially running Silverlight apps outside the browser or developing test harnesses/unit tests for Silverlight intended object models.

Silverlight 1.1 alpha and CoreCLR currently expose a very trimmed down version of the Framework's BCL. This will change by RTM, but be aware that its sweet spot is still the browser.

I can imagine a world where Silverlight apps will not only be media/presentation related. Currently, the competing platform, though having a strong install base, has not reached into that space.

You could arm Flash developers with rocket launchers, but they would still lose a battle war against .NET developers armed with chopsticks. Every day of the week and twice on Sunday. I believe the number of souls will significantly influence the outcome in this case.

Categories:  Architecture | CLR | Silverlight
Saturday, May 12, 2007 9:42:30 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Hassle Free Setups and Market Penetration 

Harry Pierson is discussing the correlation between market penetration and hassle free installation experience and hits the nail on its head.

Big market success of Adobe Flash, its omnipresence and high install base can definitely be traced back to flawless install experience. In fact, it's so perfect, that most users don't even know which version they're running. They don't care (me included). And they shouldn't care.

The first thing any platform needs to achieve is simple and effective installation experience. I don't want to manually download platform installers to use certain web services. It has to auto-install and has to be safe. This is what Flash does perfectly.

All current virtual machine based platforms can be installed independently. Or they can be flawlessly smuggled in by a host application setup program. The problem is, that we can't compare CLR (or JVM) based platforms to Windows (as a platform), since the user can't run five of the latter at the same time.

Flash 9 market penetration is currently at ~40%. Flash 8 penetration is ~90%, while Flash 6 penetration is ~96%.

WPF/E will have the same install experience. Bet on it. If it wants to succeed, it will also have to allow multiple versions to coexist gracefully.

Categories:  CLR | Other
Sunday, March 11, 2007 9:37:09 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Article: Type Systems Compared, XML, CLR 

I'm going to publish a series of my articles, which went out the door a couple of months ago.

All articles are in Slovene language.

Here goes the first one.


Naslov:

Tipski sistem XML <> Tipski sistem CLR

Tipski sistem XML <> Tipski sistem CLR

Categories:  Articles | CLR | XML
Thursday, June 01, 2006 2:38:54 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Corflags.exe in 64-bit Environment 

There's a nice little (and dangerous) tool present in every .NET Framework SDK.

It's called corflags.exe. If you run it, you might get something like this:

C:\corflags testme.exe

Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  2.0.50727.42
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 1
ILONLY    : 1
32BIT     : 0
Signed    : 0

What this tells you (via the CLR Header) is that testme.exe assembly hides a .NET Framework 2.0 compiled code. All 2.0 framework code will have 2.5 header version, while all 1.0/1.1 compiled code will have 2.0 header version. It's a bit of a mess, but noone can change history.

Next important value is PE. It tells you whether this assembly is a 32-bit or 'any cpu' compiled assembly. If PE value should be 'PE32+' than you could conclude that this is a 64-bit capable assembly.

The 32BIT property, contrary to its name, does not represent bitness of the assembly. In this case, 32BIT property holds a value of 0, which would mean that this is a 64-bit assembly. Actually this assembly can be run anywhere, since it was compiled with agnostic setting of 'any cpu'. If I wanted to, I could turn this knob using the following:

corflags.exe /32BIT+ testme.exe

Now, this assembly would always execute under WoW64 (emulated 32-bit environment on a 64-bit box). In a case where this execution would not be possible - ie. run against an ia64 box - one would get a BadImageFormatException exception.

There is no way (for now) to demand execution in a 64-bit process because this thing is not controled by a metadata flag. Rather it's controled at compile time and compiler has to emit PE32+ compatible code.

Recap: CLR Header property denotes compiler version which was used to produce the assembly. PE property tells you whether this assembly is either 32-bit (PE32), 'any cpu' (PE32) or 64-bit (PE32+). If the 32BIT property is set it mandates execution in a 32-bit process, if the platform allows it.

Categories:  CLR
Wednesday, December 28, 2005 11:22:51 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Running 64-bit Managed Code 

If you happen to be in the 64-bit world (read running a 64-bit OS on the x64 box, not IA64), there are two options on how your managed code runs.

It can run:

  • In a 32-bit process (loads x86 CLR)
  • In a 64-bit process (loads x64 CLR)

The high order bit here is the flag under which the image was compiled. Since you cannot compile for 64-bit architecture in .NET Framework 1.0/1.1, and 2.0 is your only choice, let's focus on Visual Studio 2005/.NET Framework 2.0 features.

If you look under the hood on a x64 box, you will find that VS 2005 installer will drop TWO frameworks on your machine.

The 32-bit framework will install in c:\windows\microsoft.net\framework directory, the 64-bit framework will install in c:\windows\microsoft.net\framework64 directory.

If you installed .NET Framework SDK, you will get two SDKs too. One will be in c:\program files\microsoft.net\sdk\v2.0 64bit (64-bit), the other in c:\program files (x86)\microsoft visual studio 8\sdk\v2.0 (32-bit, installed in VS 2005 base directory).

What happens at load time is the CLR runtime host decides on which CLR it needs to load based on the CLR metadata flags. Normally, if you do not change the defaults in VS 2005, your assemblies will be compiled using the 'anycpu' (also known as MSIL flag) which will allow the runtime to host the managed app in a 64-bit process on a x64 box and in a 32-bit process on a x86 box.

You can, however,  control and override this default behaviour even after your code has been compiled. There's a handy tool called corflags.exe present in the SDK that allows you to force 'anycpu' compiled code to use 32-bit process in 64-bit world.

More on that in another blog entry.

Categories:  CLR | Work
Wednesday, December 28, 2005 1:14:51 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Assembly binding log viewer bug 

It seems to me that either fuslogvw.exe or fusion.dll has a serious bug.

If you try to do some CLR assembly resolver logging using the above mentioned tehnology you can end up with an empty fuslogvw.exe window.

If that's the case and you have set ForceLog [1] registry key to 1 and LogFailures to 1 and still only get the empty window, try deleting temporary internet files directory. As it seems, Fusion has a problem when certain number of files exist in there.

After purging the internet temp files directory, things returned to normal.

[1] HCLM/Software/Microsoft/Fusion/ForceLog, DWORD

Categories:  CLR
Monday, April 11, 2005 9:54:52 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Inside CLR Workshop 

I had an 'Inside CLR' workshop today. Some attandees had really good questions and some good comments.

I really liked the comment that in-memory instance representation layout can be controlled using the StructLayoutAttribute attribute. I was sure that it's compiler default was AutoLayout, specified by Auto attribute in type metadata. One always learns new things when talking about deep subjects.

I am redelivering this workshop in a few months.

Categories:  CLR
Tuesday, December 09, 2003 7:17:49 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Mono lives... 

I just installed Mono 0.25 on a Red Hat 9 box.

This is it's output. Investigative work follows.

Categories:  CLR
Saturday, August 02, 2003 1:26:52 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Back for good 

Well, been there, done that.

When I came home at least one thing in blogspace was worth reading: new Chris Brumme article.

Categories:  CLR
Tuesday, July 15, 2003 11:08:51 AM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 Chris Brumme 
I admire this guy. Not only he writes five pages of first class material from his vacation in Maui, he also does it besides the pool.
Categories:  Work | CLR
Monday, June 23, 2003 9:18:30 PM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 SSCLI 
Finally. Rotor unleashed.
Categories:  CLR
Sunday, June 22, 2003 6:15:09 AM (Central Europe Standard Time, UTC+01:00)  #    Comments

 

Copyright © 2003-2014 , Matevž Gačnik
Recent Posts
RD / MVP
Feeds
RSS: Atom:
Archives
Categories
Blogroll
Legal

The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.

My views often change.

This blog is just a collection of bytes.

Copyright © 2003-2014
Matevž Gačnik

Send mail to the author(s) E-mail