Minification and Cache-busting in Asp.Net
Most users of popular libraries like jQuery tend to use a few jQuery plugins also. One project I’ve worked on has 10 jQuery plugins, plus a few scripts that are common across all pages on the site. Each script has to be downloaded, parsed, and executed before your page loads in full. So, a proliferation of Javascript includes on your pages can dramatically slow down load time, but this doesn’t have to be the case.
Another issue that often occurs when working with Javascript and CSS is some browsers are overzealous with their caching, which can result in telling someone to refresh a page to see if it’s working, and while it might work for you, their browser decided to cache the old script, making your changes not appear.
In this post, I will outline a few techniques to help alleviate a few of these problems.
How to Migrate from HP-UX to Linux: Encryption
We use some utility encryption routines in C for various purposes. When I first tried to migrate these routines from HP-UX to Red Hat Linux, I ran into a problem right away: the linker couldn’t find the libcl.a library.
There is no library by that name in Linux, and I had no idea what the linker wanted to find there. As an experiment, I edited the make file to remove the reference to –lcl. Now the linker complained that it couldn’t find the functions setkey() and encrypt().
A little research showed that, in Linux, those functions reside in the library libcrypt.a. I edited the make file again, replacing the reference to –lcl with a reference to –lcrypt.
(Under HP-UX, the libcl.a library includes not only the encryption functions but also a bunch of math functions. Under Linux, the math functions presumably reside in the library libmath.a. However I haven’t needed any of them so far, so I’m guessing.)
Now the linker was happy, but I wasn’t. Whenever I tried to encrypt anything, all I got was a string of zeros. Um, that’s not encryption. At best, it’s a really, really, really bad hash function.
At that point I fell down the rabbit hole of debugging – grepping the source, studying the code, inserting displays, Googling for clues, and trying experiments. Here’s what I found out.
The setkey() and encrypt() functions apply DES encryption to blocks of 64 bits at a time. That’s bits, not bytes. However, you don’t pass the bits as 8-character arrays. You pass them as 64-character arrays, one character for each bit. It’s the job of your application to translate back and forth between these bit arrays and whatever the data should really look like.
One reason for this arrangement is probably that not all machines use 8-bit bytes. The C language requires that a byte contain at least eight bits, but it can have more. I’ve heard of CPUs that use 9-bit bytes, and others that use 64-bit bytes. If you really want to be perverse, you could build a machine with 37-bit bytes. It may be easier for an encryption standard to support exotic architectures if it breaks everything down to the bit level.
In the HP-UX version of these functions, the bits in these arrays can be encoded as the ASCII characters ‘1’ and ‘0’. I haven’t found any documentation of that fact, but that’s how our programs were coded, and they seem to work okay.
In the Linux version of these functions, the bits in these bit arrays evidently must be encoded as the binary values 0×00 and 0×01. I haven’t found any documentation of that fact either. The man pages on both systems are ambiguous.
The best evidence is that, after I rewrote our code to pass the bit arrays with binary values instead of ASCII characters, the encryption started working on Linux. I can encrypt something and then decrypt it, and get the same thing I started with. Furthermore I can encrypt something on HP-UX, decrypt it on Linux, and get the right answer.
Out of curiosity, I tried the Linux version on HP-UX – and it worked! Evidently the HP-UX implementation of setkey() and encrypt() can accept either character values or binary values in their bit arrays, but the Linux version only accepts binary values. Once I converted the code to use binary values, I could use it on both platforms without a bunch of ugly #ifdefs cluttering up the code.
Fast Data Loading with SQL Server 2008
A common operation in many systems is bulk loading of data into a database, be it from another system, a flat file, or generated output, which may or may not involve updating existing records. A lesser known class in .Net, SqlBulkCopy, and a new feature in SQL Server 2008, MERGE can greatly increase the speed of these operations.
Password Storage Best Practices
With the several high profile security breaches so far this year, security is on the forefront of most developers minds, or it should be. Though, if one has never coded good authentication code before, it can be a rather daunting task. The Internet is rife with poor advice, old advice, or just plain wrong advice. This post will attempt to help demystify some of tools and techniques of building authentication systems.
Most authentication services have different requirements. For example, you would expect there to be more security logging into your bank than into your blogging software. At a point, you have to establish what is good enough for the data your authentication you’re protecting. Users are more likely to not use your system for every additional hoop they have to jump thorough, but if they view the data as worth it, they might be willing to be further inconvenienced (For example, two-factor authentication with a key fob for logging into a bank)
How to Migrate from HP-UX to Linux: Undefined Behavior
The C and C++ languages don’t try to define the results of every syntactically correct program. For example, if you dynamically allocate some memory, and then free it, and then try to access the memory you freed, you invoke undefined behavior. The C and C++ standards don’t specify how the program will respond.
Undefined behavior means that anything can happen, because the compiler is under no constraints. The traditional formulation is that undefined behavior can make demons fly out your nose. In practice the consequences are usually less dramatic.
If demons ever fly out your nose, you’ll know you have a bug. You can track it down and fix it. More insidious is undefined behavior that happens to be exactly what you want.
I ran across an example as I was preparing to port some code from HP-UX to Linux. The program was freeing a linked list, using code similar to the following:
Node * curr_node = first_node;
while( curr_node )
{
free( curr_node );
curr_node = curr_node->next;
}
To a long-time C coder, this code immediately looks fishy, because the loop has only two statements in it. Look a little closer. The second statement in the loop tries to access memory through a pointer that has already been freed. It invokes undefined behavior.
This program has been running for years with no obvious ill effects from this bug. Apparently HP-UX isn’t very persnickety about accessing previously freed memory. That’s legal. “Anything can happen” includes “what you want.”
When I first saw this code, I wasn’t ready to port the entire program to Linux yet, but I could experiment. I dashed off a little test program that built a linked list and then freed it, using the logic shown above. Under HP-UX this program ran to completion without incident. Under Linux, the same program stopped abruptly in the first iteration. It didn’t issue any messages, dump core, or even leave a non-zero condition code; it just stopped cold. That’s legal too. Anything can happen.
I don’t know whether this difference is attributable to the operating systems, the compilers, the libraries, or the machine architectures. I don’t care. What matters is that I can’t run this program under Linux without fixing the loop:
Node * curr_node = first_node;
while( curr_node )
{
Node * temp = curr_node->next;
free( curr_node );
curr_node = temp;
}
A few days later, another example of undefined behavior popped up, in the form of a buffer overflow. Under HP-UX the overflow had no visible effect, at least not until I started poking around with printf statements. Under Linux the code just didn’t work. Probably the variables are arranged differently in memory. In HP-UX the overflow didn’t damage anything that mattered, and in Linux it did.
These examples are just things that I stumbled across. There will be more, and I won’t catch them all so painlessly. Fancy code analyzers may help catch things in advance, but there is no substitute for vigilance.
It’s tempting to conclude that HP-UX is more forgiving of blunders than Linux is, since some things work in HP-UX but don’t work in Linux. That conclusion is premature. Maybe the two platforms are just forgiving about different things. If the bugs had done obvious damage under HP-UX they would have been fixed already.
There’s a Darwinian process at work here. Bugs survive when they’re well adapted to the environment. When the environment changes, some of those bugs will go extinct. Unfortunately, new species will probably replace them.