Category Archives: Things that Annoy Me

AAA Doesn’t Like Doing Work

Since I’ve returned to the wonderful and freezing east coast in December, I’ve had two encounters with AAA while staying with my parents.

Encounter 1
Around December 20th or so our car couldn’t get up an unplowed hill in New Hampshire. It was a two-wheel drive Mazda (I forget the model), and for whatever reason we couldn’t gun it enough to get to our house.

We called AAA to see if the car could be towed up the hill. No go, they said, if we couldn’t get it up then they couldn’t get it up either. Furthermore that didn’t count as something that would be covered, since the problem was with the road, not the car.

We said, “well eventually we’ll be stuck long enough out here that we’ll run out of gas.” The reply? “Well, in that case we’d come bring you more gas.” Uh.

I can believe them that that towing the car up the hill seemed implausible. But they could have offered something, like, towing the car somewhere safe and then bringing us up the hill.

Instead, we had to walk. In 10F degree (-9.5C) snowing weather. Up a steep hill, in the dark, for what we later clocked to be 0.7 miles (1 km). While carrying all of our luggage. It felt like the desert scene from Spaceballs, but we didn’t have any food or supplies at the house, so there were more necessities than usual.

I have severe chronic asthma, which though has gotten much better over the years, still needs work. It must have taken me around fifteen minutes to breath normally again after deeply inhaling freezing cold air for so long.

Later the next day, a family acquaintance with a plow came and plowed the street, then managed to gun the car straight up the hill with no problem. Gee, I wonder if AAA could have done that.

The incident caused my parents to, a mere ten days later, get a used 2006 Toyota Highlander Hybrid for its four wheel drive.

Encounter 2
Cars are supposedly supposed to turn off their internal lights once they’ve been closed and locked. For one reason or another that didn’t happen in the Toyota Hybrid, and the battery drained. We didn’t have jumper cables for that car yet so we called AAA.

AAA refused to jump the car because it was a hybrid. They hadn’t developed a procedure for hybrids yet. Huh? Hybrids have been out for a decade. What has AAA been doing all this time?

But that’s irrelevant, because it’s a normal battery like any other car. The owner’s manual even tells you how to jump it, and it’s exactly the same as any other vehicle.

So AAA tows the car back to our house, but the guy AAA contracted wants to try jumping it anyway out of curiosity. He connects positive to positive, then negative to negative – wait what?

You’re not supposed to connect the dead negative terminal – it’s supposed to go to ground. So AAA apparently doesn’t know how to jump a normal car. The guy was nice though, was glad to know the correct procedure, and what do you know? The hybrid jumped fine.

Conclusion
I’m not really sure I have one, other than that AAA clearly isn’t going to go out of their way to help you. They have some tome of procedures and will obey it to the letter. Maybe they’re afraid hybrids will detonate into some sort of mushroom cloud explosion. Perhaps in 2050 they’ll know how to jump them (or, any car).

Valve’s Changes to the Iterative Model

Today Mike Beltzner (Firefox Director) gave a very interesting presentation on software development models and how they apply and evolve at Mozilla. When he put up a slide about the iterative model, it included a picture from Wikipedia that looked like:

“Plan -> Design -> Implement -> Deploy -> Test”

Instead of:

“Plan -> Design -> Implement -> Test -> Deploy”

This elicited a few chuckles, since obviously no one tests after deployment. I almost shouted out, “Well, Valve does that.”

But I didn’t, since that’d be just wrong. Valve doesn’t test at all.

No, I do not consider that comment flamebait. In the past few weeks patches have had to go out twice because of things like servers crashing on load or massive memory leaks.

Vista Problems (Surprise?)

I recently migrated to Vista (a story and a review for another day), but one thing has been bothering me. The “Visual Effects” settings (from My Computer Properties -> Advanced System Properties -> Performance Settings) do not stick.

If I customize the settings, they get reset on logoff or reboot. This is true no matter which account I use, Administrator or limited user. I tried to monitor the dialog box with procmon to see what registry keys were involved, but there were quite a few and they looked annoying to research.

The strange thing is that the dialog box is an administrator-only feature, which would imply that the settings are system-wide. Yet monitoring the dialog box shows all sorts of per-user settings go by.

I used the classic Windows theme for XP (I hated Luna). Aero is tolerable so I decided to give it a shot, but I don’t like all of the frilly, useless animations. For example, windows “slurping” into the task bar and menus fading in and out feels kitschy to me, and only seems to serve as some sort of visual distraction or delay. So I disabled all of these animations in the Visual Effects dialog, and soon discovered that as soon as I logged out and logged back in, I had to reapply all of the settings.

I couldn’t find any other instances of this problem on Google. Damaged Soul managed to find one but it contained a red herring and no solution. I gave up and solved it programmatically, with a small, very insecure (I was lazy) C program sitting in my Startup folder.

Select All Code:
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
 
int main()
{
	HANDLE hToken;
	ANIMATIONINFO info;
 
	if (!LogonUser(_T("Administrator"),
		_T("KNIGHT"),
		_T("blahblahblah"),
		LOGON32_LOGON_BATCH,
		LOGON32_PROVIDER_DEFAULT,
		&hToken))
	{
		exit(1);
	}
 
	if (!ImpersonateLoggedOnUser(hToken))
	{
		exit(1);
	}
 
	SystemParametersInfo(SPI_SETDISABLEOVERLAPPEDCONTENT,
		0,
		(PVOID)TRUE,
		SPIF_SENDCHANGE);
 
	SystemParametersInfo(SPI_SETCOMBOBOXANIMATION,
		0,
		(PVOID)FALSE,
		SPIF_SENDCHANGE);
 
	SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,
		0,
		(PVOID)FALSE,
		SPIF_SENDCHANGE);
 
	SystemParametersInfo(SPI_SETSELECTIONFADE,
		0,
		(PVOID)FALSE,
		SPIF_SENDCHANGE);
 
	SystemParametersInfo(SPI_SETCLIENTAREAANIMATION,
		0,
		(PVOID)FALSE,
		SPIF_SENDCHANGE);
 
	SystemParametersInfo(SPI_SETMENUANIMATION,
		0,
		(PVOID)FALSE,
		SPIF_SENDCHANGE);
 
	info.cbSize = sizeof(ANIMATIONINFO);
	info.iMinAnimate = 0;
	SystemParametersInfo(SPI_SETANIMATION, 
		sizeof(ANIMATIONINFO),
		&info, 
		SPIF_SENDCHANGE);
}

Two notes from playing with this API:

  1. SPI_SETDISABLEOVERLAPPEDCONTENT appears to do nothing? I thought it would be related to Transparent Glass, but… Transparent Glass is a user-mode (per-user?) setting. You can change it in your display preferences, and oddly enough, that will cause it to flip the switch in the Administrator-only settings! I have no idea what’s going on there. Also, transparent glass is the only “effect” setting not to be reset on logging off.
  2. SPIF_UPDATEINIFILE fails with ERROR_MOD_NOT_FOUND on Vista. Maybe it does that on previous versions too, I have no idea. Maybe I’m forgetting to link to something or maybe I’ve missed a security policy thing somewhere that fixes all of my problems.

Now that I have my hacky fix, I don’t feel like investigating the problem any further. But it’d be nice to know what’s going on here, and why those settings can’t per-user in the first place.

Don’t call me pedantic!

A few weeks ago in a class, the professor mentioned that C does not support nested functions. He wrote an example on the board that he claimed would not compile.

A student quickly typed up the program on his laptop and said, “GCC compiled it just fine.” The professor replied, “Well, I’ve never heard of that. It must be a compiler feature unless they changed the standard.”

The student then said, “Well, I added -ansi and GCC still compiles it.” The professor caved in — “I guess they changed the standard recently.”

I was sure they most certainly didn’t. This incident bothered me since I knew nested functions couldn’t possibly be in C99. When I got home I reproduced the scenario, and sure enough, the student was right. GCC was compiling completely invalid syntax even with the “-ansi” setting. After digging through the documentation, I was able to find two things:

  • GCC has its own custom extensions to the C language, which includes nested functions.
  • This custom extension is enabled by default even if you choose a language specification where it does not exist.

As if that weren’t strange enough, GCC’s option to disable its custom additions appears to be called “-pedantic.” Uh, I don’t think it’s pedantic if I want the language to conform to the actual standard. As much as I like GCC and its custom extensions (many of which are pretty cool), they should be opt-in, not opt-out, in compliance modes.

I frequently see people say “Microsoft’s stupid compiler doesn’t conform to ANSI.” Well, after this, I’m not so convinced GCC is innocent either.

That said, GCC’s nested function feature and its implementation are both very cool. Taking a look at the disassembly, it does run-time code generation on the stack. Simple example:

Select All Code:
include <stdio.h>
 
int blah(int (*g)())
{
    g();
}
 
int main()
{
    int i = 0;
 
    int g()
    {
        i++;
    }
 
    g();
    blah(g);
 
    printf("%d\n", i);
}

Does it work?

One of the most ridiculous support questions we often get is simply:

“Does it work?”

The topic can be anything related to the project. An API call. A plugin. A feature. A menu option. A user sees something, decides not to investigate it and instead asks “Does it work?” via IRC or a forum post.

Why would we have added and documented something that doesn’t work? Why not spend the time verifying whether it works (which would often take a matter of seconds) instead of spending time asking and waiting? Maybe users have become too jaded from past experiences, but in my opinion, any feature added should be assumed to be working as documented. If it doesn’t, well, then you’ve discovered a bug.

It’s not in just my projects that I’ve noticed this. For example, I observed this treasure in the EventScripts channel:

L 07:37:41 <User1> does es.event work?
L 07:42:29 <User2> yes

I don’t even use this product and it took me seconds of googling to verify that it was documented. Documentation is rarely written for no reason, so I’m going to assume it is backing something existent and working.

This is definitely at the top of my List of Useless Questions.

Asking the Wrong Audience

One thing that happens quite often in our forums and IRC channels is that someone (invariably new) will enter and ask a question completely unrelated to the topic. Typically, about competing projects or projects on the same platform.

For example:

  • Topic: AMX Mod X. Question: “How do I use EntMod?”
  • Topic: SourceMod. Question: “How can I use EventScripts?”
  • Topic: SourceMod. Question: “Can someone help me with a Mani issue?”

Onlookers tend to reply the same every time: “Visit their IRC channel or website for documentation. This channel/forum is unrelated.” The person asking the question then says, “I tried, but no one there is replying.”

The person is trying to keep their question alive in the off-chance someone random will know the answer. If you do get a reply, all the best. But if you don’t, you have to realize that nothing you’ve said changes the fact that you’re still asking the wrong audience.

Would you ask your English professor a math question because your math professor isn’t in his office? Would you hire a dentist for a plumbing job because your plumber is out of town? Of course not, that’d be silly. But sometimes, if the person doesn’t get a reply, they will become aggressive or insulting. For example, “Thanks for no help whatsoever!”

If you’re knowingly asking the wrong audience, don’t throw a tantrum when you don’t get your answer, and don’t get annoyed when you’re told a better place to look.

Using the Wrong Return Value

One thing I continually see which bugs me is using the wrong return value from a function. For example, take the following function:

Select All Code:
/**
 * Does something.
 *
 * @param error		On failure, a null-terminated error message is printed to this buffer.
 * @param maxlength	Maximum length, in bytes, of the message buffer.
 * @return		True on success, false on failure.
 */
bool DoSomething(char *error, size_t maxlength);

One thing people will start doing is this:

Select All Code:
char error[255];
error[0] = '\0';
DoSomething(error, sizeof(error));
if (error[0] != '\0')
{
	PrintErrorMessage(error);
}

This is a subtle logical fallacy. The documentation says that “failure implies a null-terminated string.” That proposition doesn’t imply that “failure implies a string of length greater than 0” or that “success implies a string of length zero.” It simply says that if the function fails, the buffer will contain a valid string.

Of course, eliminating the zeroing of the first byte would make this code completely wrong. As it stands, the code will only be incorrect when DoSomething() returns false and has no error message available.

Perhaps, the documentation could be clearer. For example:

Select All Code:
/**
 * Does something.
 *
 * @param error		On failure, a null-terminated error message is printed to this buffer.  If 
 *			no error message is available, an empty string is written.  The buffer is 
 *			not modified if DoSomething() returns successfully.
 * @param maxlength	Maximum length, in bytes, of the message buffer.
 * @return		True on success, false on failure.
 */
bool DoSomething(char *error, size_t maxlength);

However, to the astute reader, this is just clarifying the obvious: the function only modifies the input buffer when it says it will, and an empty string is a valid, null-terminated string.

Making this mistake was very common in AMX Mod X, where return values were often ill-defined, non-uniform, and coupled with strange tags. Another case of this is through callbacks. SourceMod has a callback that essentially looks like:

Select All Code:
public SomethingHappened(Handle:hndl1, Handle:hndl2, const String:error[], any:data);

The rules for determining an error depend on the inputs and values of hndl1 and hndl2. These are well-defined. However, if you don’t read these rules, or simply ignore them, it’s tempting to just check the contents of error. Unfortunately, the API does not specify that checking the error buffer is a valid method of checking for an error, and your assumption could potentially lead to a bug.

Conclusion: If a function has a return value that definitively determines success or failure, use it. Don’t rely on testing values that are merely secondary in the failure process.

I’ve Dumped TortoiseSVN

I hate TortoiseSVN. The interface is great and it makes working with SVN a lot easier, but it’s so buggy it’s unbearable. Just a few of my complaints:

  • It’s slow. After a fresh install of Windows XP and TortoiseSVN, it completely locked up Explorer while it attempted to traverse a massive repository I had.
  • It causes weird explorer behavior. In particular, it feels like the screen is getting redrawn way too much.
  • TSVNCache is a horrible idea, or at least horribly coded. I often find that I can’t eject removable media because TSVNCache is holding file locks on random files, even if explorer is closed. Why? I have no idea. The only solution has been to kill it.
  • Sometimes, files randomly won’t have the right overlay for their status. Sometimes refreshing works, sometimes you have to exit (or even kill) explorer. In worse cases, TSVNCache must be killed, and in the worst case, you have to reboot (I’ve only had this happen once).
  • On my Core 2 Duo with 2GB of RAM, TortoiseSVN adds noticeable delay to explorer. It takes a split second longer to draw everything. The bigger (or deeper) your repository gets, the longer the delay seems to be.

So, TSVN is buggy and slow. I now use the command line on Windows instead. Getting this working with SSH keys is a bit of a chore, but here’s what I did:

  • Download the Windows PuTTY installer (I installed to C:\Program Files\PuTTy). Click here to get the exact package I did.
  • Get the latest Subversion package for Windows. I chose the binaries compiled against “Apache 2.2” — the exact package was “svn-win32-1.4.5.zip.”
  • Extract the zip file to somewhere. I chose C:\Tools and renamed the main subversion folder to get C:\Tools\Subversion.
  • Go to Start -> Settings -> Control Panel -> Advanced -> Environment Variables.
  • Edit the “Path” variable under “System variables,” and append the following string to the end, using your subversion’s bin path: ;C:\Tools\Subversion\bin
  • Add a new variable under “User variables.” Call it “SVN_EDITOR” and set it to some text editor you like (mine points to C:\Windows\notepad.exe).
  • Open notepad, and open the file “Application Data/Subversion/config” where “Application Data” is the folder under your user account (i.e. “C:\Documents and Settings\dvander\Application Data\…” or just “C:\Users” on Vista).
  • Under the “[tunnels]” section, find the commented line that looks like:

    # ssh = $SVN_SSH ssh

    Replace it with:

    ssh = C:/Program Files/PuTTy/plink.exe

    Or something similar depending on where you installed plink.exe.

  • Load pageant from the same folder plink is in (C:\Program Files\PuTTy\pageant.exe for me).
  • Load your SSH keys into pageant.

If you don’t use SSH keys, or don’t know what they are, see this article.

You can now run subversion from the command line. Examples:

svn co svn+ssh://[email protected]/svnroot/sourcemm sourcemm
cd sourcemm
svn update
svn commit
...etc...

If it doesn’t work, make sure your environment is updated. For example, start a new cmd session rather than using an old one.

Note: I never had any problems with TortoiseCVS.

Weird Vista Crash – Calculator!

I don’t recommend using Vista yet (I run it on my secondary computer) and someday I might write up a full article on why it annoys me endlessly.

Today was one of those clincher moments — calc.exe crashed as I tried to evaluate a simple four-function math expression. Unfortunately I didn’t screenshot this miracle, but I couldn’t make this up if I tried. It is a very minimalistic Vista install that I only use occasionally.

Back in the Windows 3.1 days, calc.exe had a bug where certain expressions like (12.000001-12) would return a garbage answer. Who knows, maybe Microsoft managed to introduce a bug into a trivial addon that has worked since 1995? Maybe it’s the fault of something 3rd party, or a driver. If it happens again I’ll probably try to debug it. I just know that on every other Windows edition, calc.exe never crashed.

Stay away from Vista unless you’re a developer (reassessment pending a service pack).