This past week I managed to:
All of this fun activity didn’t leave much time for:
This evening I finally got to jump back into a Reporting Services frame of mind in preparation for San Fran next week. Reporting Services ships with a utility to run “scripts” from the command line: the rs (rs.exe) utility. Most Microsoft server applications expose a COM object model that admins can script against using VBScript, but Reporting Services exposes only a web service API. The “scripts” that rs.exe executes are actually little hunks of VB.NET code that invoke methods on the web service API.
Reporting Services only ships two sample scripts. One script cancels running jobs on the server (CancelRunningJobs.rss), the second script (PublishSampleReports.rss) demonstrates how to deploy reports to the report server (yes, the default extension is unfortunately “rss”). A really short script might look like the following:
Sub Main() Dim permissions As String() permissions = rs.GetSystemPermissions() For Each permission As String in permissions Console.WriteLine(permission) Next End Sub
I can save the above snippet in a text file and execute the instructions from the command line like so:
rs -i scriptname.rss -s http://localhost/reportserver
The rs utility compiles the above snippet (without option strict, so there is no need to declare permissions with a specific type) and executes the code. Obviously, there is some additional infrastructure in place to let the variable rs invoke web service methods. A little poking around with reflector reveals the utility sets up our code with imports for the System, System.Web, System.WebServices, System.WebServices.Protocols, System.IO, and Microsoft.SqlServer.ReportingServices namespaces. The utility wraps the code chunk shown above inside of a class declaration (____ScriptClass) and adds a member variable (rs) defined as type ReportingService.
What’s also interesting is an embedded resource in rs.exe by the name of StartupClass.vb. The StartupClass, stripped down to essentials (I removed the code for exception handling and for batching commands in the script.), looks like the following:
Public Module MainModule Public Sub Main(ByVal args as string()) Dim rs as new WebServiceWrapper(args(0), args(1), args(2), args(3)) Dim clientScript as new ____ScriptClass() clientScript.rs = rs clientScript.Main() End Sub End Module
What intrigues me about rs.exe is how easy it is to pull off this “scripting” technique in .NET. Think about what it would take for an application to pick up a hunk of C++ source code from the disk and just execute it in-process. It is possible, of course, but fraught with peril.
The tricks you can pull off safely in .NET just never cease to amaze me.
Lot's of stuff in the news this week:
.
Someone in the newsgroups recently asked what the numbers mean in a release mode stack trace. For instance, what can you do with the following information?
[NullReferenceException: Object reference not set to an instance of an object.] aspnet.debugging.BadForm.Page_Load(Object sender, EventArgs e) +34 System.Web.UI.Control.OnLoad(EventArgs e) +67 System.Web.UI.Control.LoadRecursive() +35 System.Web.UI.Page.ProcessRequestMain() +720
The stack trace gives us a little bit of information to go on, at least we can narrow the problem down to a specific method inside of a specific type, but +34 doesn’t seem to be particularly helpful – what does it mean? There are two answers to this question.
The first answer is: don’t worry about it. To narrow the source of the exception down to a single line of code, just build with debugging information (Project -> Properties -> Configuration Properties -> Build -> Generate Debugging Information). You should now have a PDB file output alongside your release mode assembly. With a PDB in place the runtime can give you a line number close to where the exception occurred.
[NullReferenceException: Object reference not set to an instance of an object.] aspnet.debugging.BadForm.Page_Load(Object sender, EventArgs e) in e:\dev\xprmnt\aspnet\debugging\badform.aspx.cs:16 System.Web.UI.Control.OnLoad(EventArgs e) +67 System.Web.UI.Control.LoadRecursive() +35 System.Web.UI.Page.ProcessRequestMain() +720
The above answer is the practical answer, but it doesn’t satisfy the curious person who insists that all numbers have a meaning and a purpose. +34 isn’t some random number the runtime spits out after sampling the microphone input - so where does it come from?
For reference, the Page_Load method looks like the following:
using System; using System.Web.UI; using System.Web.UI.WebControls; namespace aspnet.debugging { public class BadForm : Page { protected Label Label1; private void Page_Load(object sender, EventArgs e) { if(!IsPostBack) { string s = null; Label1.Text = s.Insert(0, "foo"); } } #region Web Form Designer generated code … } }
We already know +34 doesn’t refer to a line of code. So perhaps the number refers to an offset into the IL instructions? Here is what ILDASM shows as the instructions for Page_Load.
.method private hidebysig instance void Page_Load(object sender, class [mscorlib]System.EventArgs e) cil managed { // Code size 34 (0x22) .maxstack 4 .locals init ([0] string s) IL_0000: ldarg.0 IL_0001: call instance bool [System.Web]System.Web.UI.Page::get_IsPostBack() IL_0006: brtrue.s IL_0021 IL_0008: ldnull IL_0009: stloc.0 IL_000a: ldarg.0 IL_000b: ldfld class [System.Web]System.Web.UI.WebControls.Label aspnet.debugging.BadForm::Label1 IL_0010: ldloc.0 IL_0011: ldc.i4.0 IL_0012: ldstr "foo" IL_0017: callvirt instance string [mscorlib]System.String::Insert(int32, string) IL_001c: callvirt instance void [System.Web]System.Web.UI.WebControls.Label::set_Text(string) IL_0021: ret } // end of method BadForm::Page_Load
No, 34 bytes puts us beyond the end of the IL instructions.
Let’s go one level lower into native code. Using WindDBG and SOS, it’s easy to view a disassembly of Page_Load after the JIT compiler has partied on the method. I use WinDBG to attach to the asp.net worker process after the page has executed and do a .load sos for managed debugging.
To view a disassembled method, you first need the address of the MethodDesc structure for the method, which name2ee can yield (aspnet.dll is the unfortunate name I gave my assembly):
!name2ee aspnet.dll aspnet.debugging.BadForm.Page_Load -------------------------------------- MethodDesc: 1b873a0 Name: [DEFAULT] [hasThis] Void aspnet.debugging.BadForm.Page_Load(Object,Class System.EventArgs)
Now pass the address to the (u)nnassemble command.
!u 1b873a0 Normal JIT generated code [DEFAULT] [hasThis] Void aspnet.debugging.BadForm.Page_Load(Object,Class System.EventArgs) Begin 07f805b8, size 52 07f805b8 55 push ebp 07f805b9 8bec mov ebp,esp 07f805bb 83ec10 sub esp,0x10 07f805be 57 push edi 07f805bf 56 push esi 07f805c0 53 push ebx 07f805c1 8955f8 mov [ebp-0x8],edx 07f805c4 8bf1 mov esi,ecx 07f805c6 33db xor ebx,ebx 07f805c8 8bce mov ecx,esi 07f805ca e819a8fef9 call 01f6ade8 (System.Web.UI.Page.get_IsPostBack) 07f805cf 0fb6f8 movzx edi,al 07f805d2 85ff test edi,edi 07f805d4 752a jnz 07f80600 07f805d6 33db xor ebx,ebx 07f805d8 8bbec4000000 mov edi,[esi+0xc4] 07f805de ff357c40f906 push dword ptr [06f9407c] ("foo") 07f805e4 8bcb mov ecx,ebx 07f805e6 33d2 xor edx,edx 07f805e8 3909 cmp [ecx],ecx 07f805ea ff1564ddb779 call dword ptr [mscorlib_79980000+0x1fdd64 (79b7dd64)] (System.String.Insert) 07f805f0 8945f0 mov [ebp-0x10],eax 07f805f3 8b55f0 mov edx,[ebp-0x10] 07f805f6 8bcf mov ecx,edi 07f805f8 8b01 mov eax,[ecx] 07f805fa ff9094010000 call dword ptr [eax+0x194] 07f80600 90 nop 07f80601 5b pop ebx 07f80602 5e pop esi 07f80603 5f pop edi 07f80604 8be5 mov esp,ebp 07f80606 5d pop ebp 07f80607 c20400 ret 0x4
The method starts at address 07f805b8. Moving 34 bytes into the method lands us on the ‘cmp [ecx], ecx’ instruction. CMP is an x86 opcode for compare, which seems like an odd thing to do until you realize the funny quirks of assembly language. For instance, earlier in the method you’ll see xor edx, edx. This instruction isn’t really trying to do an exclusive OR operation (XOR). Instead, this is an old trick used to set the EDX register to 0 in the fastest manner possible: by XORing the register against itself. The more obvious “mov edx, 0” (move 0 into edx) might cost an extra half nanosecond on a 3 GHz machine.
What the cmp instruction is doing here is carrying out part of the IL’s callvirt contract (referring to the IL you’ll see we do a callvirt to the String.Insert method). We can see in the dissasembly the next instruction calls the Insert method. callvirt is documented as throwing a NullReferenceExcecption if the object reference for the instance method you want to call is null. To make a long story a tad shorter: the ecx register contains the this pointer for the string instance that we want to call Insert on, and cmp [ecx], ecx generates a compact, 2 byte instruction to check ecx for null by dereferencing the ecx register. When the instruction dereferences the null pointer in ecx – program go boom.
In conclusion, +34 does have a meaning – it’s an offset into the native instructions for the method. Debugging at the assembly level doesn’t make any sense because you should always have PDBs available, but at least we can all sleep at night knowing the number 34 holds some meaning … somewhere.
I was flipping through SDTimes this week and came across the article “Turning Architecture Into a Profession”. The Open Group intends to begin a certification program for software architects.
“While declining to discuss specifics of the program just yet, de Raeve did say architects will have to show they have a body of experience and that they’re capable of deploying an as-yet-undefined set of skills in the delivery of systems architectures in real-world situations. Among those skills are communication, conflict resolution, architecture modeling techniques, and the ability to apply methodologies and elicit shareholder requirements, he said.”
Hmm, conflict resolution.
Do you think there will be a standardized test?
I wonder what such a test would look like…
Section II: Conflict Resolution
Please review each question carefully and select the single, best answer available.
1. Harry says the company needs to standardize on a language with curly braces. Fred says he hates curly braces, and is in the parking lot with a screwdriver threatening to flatten the tires of curly brace fans. What do you do?
a) Give Fred more screwdrivers.
b) Get your car safely out of the parking lot while dialing the police.
c) Take Harry and Fred to lunch and discuss the aesthetics of braces.
2. The CEO has barged into the office demanding the company’s flagship product be “SOA compliant” in time for the next tradeshow. What do you do?
a) Call in a consultant.
b) Have the CEO buy lunch and discuss.
c) Tell the CEO you can get the software to level V SOA compliance, but you'll need a bonus.
3. Jill says the opening curly brace goes on the next line. Jack says the opening curly brace stays on the same line. What do you do?
a) Call a meeting and take a vote.
b) Adjust Jack’s thinking with a heavy, blunt object.
c) Switch to Python
4. Harry refuses to work on the new project because it’s not using domain driven design. Fred is threatening the tech writers with a screwdriver. Jack refuses to write unit tests, and Jill says your architectural diagrams look like the work of a five year old. What do you do?
a) Something is wrong? This is a good day.
b) Start a job search.
c) Lock the door and reach for some of the liquid stress reliever in the bottom drawer of your desk.
This concludes Section II.
P.S. The correct answers were B, B, B, and B.
Perhaps I've overstated the title for dramatic effect, but as a taxpayer I've certainly donated some amount of money to failed software projects for the U.S. government. I’d be curious to see a post-mortem report on some of these projects to hear what went wrong. I’m sure the list could go on and on.
Of all the agencies though, certainly NASA has the toughest job. I mean, you forget to put one tiny file into version control, and oops, $1.2 billion down the drain. I write about this story in the latest OdeToCode article - “Source Control: A Primer”.
The NASA story came to mind this week when I interviewed some candidates who work for consulting shops. Not only did one or two never use source control, but they asked what purpose it served. Hopefully, the article will reach out and touch a few people.
Ad for the day
When I first heard of an open source project by the name of DotNetNuke, I really thought I’d be looking at the source code to a first person shooter. As it turns out, DNN is everything one needs to run a website. Now there is a book dedicated to DNN ready to hit the market from my friends at Packt Publishing.
Thought for the day
I was listening to a Stephen Hawking recording during the commute today and he said: “Imagine now a star with the mass ten times the mass of the sun”. I tried. I failed.
Threat for the day
One more burst of comment spam and this blog gets a CAPTCHA control. Any objections? Any alternatives? Who are these people and why can't we stick them with sharp pins?