Intel sponsors gamedev.net search:   
The One With Aldacron's GamesBy Aldacron      
The One With Aldacron GameDevMike The One With D

Monday, November 28, 2005
I implemented a memory tracker yesterday after a quick test showed that I had 2 fewer deallocations than allocations. I based the implementation partly on Peter Dalton's code from Game Programming Gems 2 ("A Drop-in Debug Memory Manager"). I use his log formatting and statistics tracking. The actual memory tracker I wrote is quite a bit simpler than his because it can be (his is generic and has to account for a broader range of possibilities).

It's already proven to be time well spent. I managed to find both leaks and was able to optimize several sections thanks to the statistics it dumps to a log. The optimizations decreased both the total number of allocations/deallocations and the total amount of memory used. These are small numbers now, but several of the optimizations were in core code that will come in to play later when I am working with larger resources.

Now that this is in I'm feeling more confident about the code base. Before too much longer I'll be making more 'visible' progress. That's the part I'm looking forward to.



Comments: 0 - Leave a Comment

Link



Saturday, November 26, 2005
Whenever I start a project in C one of the first functions I implement is a string copier. Safe string copying is important, and wrapping it up in a function allows me to keep it centralized and to ensure that all strings are copied in the same manner. My usual implementation looks something like this:

size_t myStringCopy(char *dst, size_t maxlen, const char *src)
{
   assert(dst);
   assert(src);
   
   strncpy(dst, src, maxlen - 1);
   dst[maxlen - 1] = 0;
   return strlen(dst);
}




This is a fairly common way to copy strings. If the source string is shorter than the destination buffer, the remaining space in the buffer will be padded with zeroes, so the copied string will always be null terminated in that case. But if the source string is the same size or longer than the destination buffer, the copied string will not be null terminated (and in the case that the source is longer the copied string will be truncated). Therefore, the line "dst[maxlen-1]=0;" is necessary to ensure that any long strings are null terminated properly.

I've always assumed that the only real weakness with this function is that there's no way to test if the 'maxlen' parameter is larger than the destination buffer. When copying to a local buffer, the sizeof operator can be used. But in this case, 'sizeof(dst);' will always return the size of a pointer rather than the size of the space pointed to. So it's up to the caller to verify that the maximum length is indeed not larger than the buffer size. This is easy enough to do:

char buf[256];
myStringCopy(buf, sizeof(buf), someString);




Recently, I was browsing through the second edition of Writing Secure Code on Safari. Having never read the first edition, I was sure to learn something new. But I didn't expect to learn that my safe string copy function isn't as safe as I had thought!

The book gives an example of using strncpy in the same manner as I use it above. Then, they mention a problem with strings that are too long for the buffer getting truncated. They go on to say, "Some people are quite happy just to truncate the buffer and continue, thinking that some code farther down will catch the error." I am one of those people. I mean, what does it matter if a string gets truncated? According to the book, it matters quite a bit.

The obvious answer is that in some cases, truncating the string is not desired behavior and will actually be an error. Rather than catch the error later on in the code, it is best to catch it at the source. I sort of handle that already by returning the length of the copied string. I can compare the return value to the length of the original string to determine if there was any truncation and handle it as I need to.

A not so obvious answer is, " the truncation might just happen in a place that causes unexpected results ranging from a security hole to user astonishment." As for user astonishment, you wouldn't want someone to get truncated quest text in an RPG would you? That would be a bug. As for security holes, I'll trust the authors to know more about the subject than me.

So the book offers up a safer alternative. With a slight change to the code, the new function looks like this:

size_t myStringCopy(char *dst, size_t maxlen, const char *src)
{
   assert(dst);
   assert(src);
   
   // null terminate the buffer before copying
   dst[maxlen - 1] = 0;

   // notice 'maxlen' and not 'maxlen-1'
   strncpy(dst, src, maxlen);

   // test for overflow
   if(dst[maxlen-1] != 0)
   {
      // handle error
   }
   
   return strlen(dst);
}




Now, in my eyes this doesn't look any safer from a security standpoint than the previous version. And I wasn't quite sure of the benefits. But, after implementing this and replacing my old version, now I am. Security aside, this is an excellent way of catching truncation. In a previous journal entry, I posted my code for setting the working directory at app startup. After changing my lsStringCopy function so that the app exits when the overflow test fails, it did so every time in that sSetWorkingDir function on the line "lsStringCopy(path, len, arg0);". The reason is that I was intentionally trying to truncate the 'arg0' argument (so that the filename would be stripped from the path).

So now, when I know I want to truncate a string, I no longer go through my string copying routine. Instead, I use memcpy or memove (as the situatation dictates):

// old code
char path[len + 1];
lsStringCopy(path, len, arg0);

// new code
char path[len + 1];
memcpy(path, arg0, sizeof(path));
path[len] = 0;




I know many people are working with C++ string objects rather than C-strings to avoid situations like this altogether, but for those who are working with C-strings I hope you find this useful. And everyone should read Writing Secure Code at some point.

Comments: 0 - Leave a Comment

Link



Wednesday, November 23, 2005
Throwing my hat into the ring - I like the new site layout & theme. It's about time they changed. What I don't understand is why some people are getting up in arms over it. I find it ridiculous to get upset over something as trivial as the changing of a color scheme and rather immature to publicly bitch about it. The proper thing to do would be to send an email to one of the staff listing your complaints and get over it. Life is too short to whine about website color themes.

Comments: 3 - Leave a Comment

Link



Thursday, November 17, 2005
For the past few years I've been thinking, "Wouldn't it be great if there were a GDC type event in Korea?" Today, while reading through messages from the MUD-DEV mailing list, I noticed one from Raph Koster. He was announcing that he had posted his keynote from the Korea Games Conference on his site. I went into a state of freakage.

A quick Google revealed that the conference was Nov 10 & 11. Not only that, but there has been one every year since 2001. How did I not know? I'm kicking myself repeatedly for letting this slip under my radar. I so had time to attend the conference both days last week. And it actually wasn't too far from my house so it would have been a convenient short subway or bus ride. At least I know now that it's held every November, so I can be on the look out for it next year.

Comments: 1 - Leave a Comment

Link



Monday, November 14, 2005
I haven't touched a line of code in Game #1 for the past few days. I took some time out to update an open source D project I'm maintaining over at dsource.org. It was in need of some loving. More importantly, I've had my nose buried in several different books covering several different programming related topics.

Since I'm a self-taught programmer, I don't have the foundation in fundamentals that can be established in CS courses. I'm strong in areas I have interest in and very weak in areas that feel more like work than play. So over the past couple of years I've been expanding my bookshelf to include a wide range of programming books that I wouldn't have purchased before because they 'weren't as interesting' as the other stuff. That's gotten quite expensive. Plus it competes with my obsession for DVDs. So I usually give priority to books related to any projects I'm working on at the time.

A few weeks ago (after finally getting a credit card for the first time in my life) I picked up a membership at O'Reilly's Safari Bookshelf. I have a 10-slot bookshelf for $20 per month. Any books I want to read from their selection I can add to the shelf. Most books take up 1 slot, but some take up 2. Each book must remain on the shelf for a minimum of 30 days and then it can be removed. I went nuts and filled all of my slots with books I didn't really need, but now that they are all eligible for removal I've been reading some good stuff that I haven't been able to buy yet. I've learned quite a bit the last few days. There are quite a few gems in there with new books added regularly. If you don't have the budget to spend a few hundred dollars on books each month, this is certainly worth looking in to.

I have also bought some books at my favorite local bookstore recently: Level of Detail for 3D Graphics, Advanced Graphics Programming Using OpenGL, and Object Oriented Game Development. All of them have taught me something new, which is what I'm after.

Once I get through all of the books I have lined up to read, I'll pick up coding again. I've now got some new ideas to implement, thanks to these books.

Comments: 0 - Leave a Comment

Link



Tuesday, November 8, 2005
One thing I find very annoying is an application that makes assumptions about the current working directory. Sometimes I want to run an app from the command line to try out some command line options real quick. When doing so, I often just open the prompt and start typing the command without changing to the app directory. More often than I would like, I start getting errors because the app can't find certain resource files. Sometimes I'll find a log file in the directory I executed the command from after the app exits. That should never happen.

Even if you don't expect your target audience to understand how to use the command line it's still worthwhile to set the current working directory to the app's installation directory (where it would normally be if run from a file browser, like Windows Explorer), or at least account for the fact the the working directory might be different (such as prepending the app directory to all file paths like the Quake games do, IIRC). This is very important particularly for loading resources. In some cases you might even want to make the default working directory configurable for power users, but that really does depend on target platform and audience (something useful on Linux perhaps in some cases, but not so much on Windows).

The way to handle this is to read the first command line argument at app startup. Before any files are loaded, parse that string to remove the final path separator ('/' or '\\') and pass the remainder on to a function that sets the current working directory. In C or C++, this might be chdir in io.h or sys/unistd.h, or the SetCurrentDirectory function from the Win32 API. This will ensure that no matter which directory your app is called from, it will always be able to load resources and such with relative paths.

Another benefit comes during development for those who work from the command line a lot. It gets tedious doing this sort of thing:

cd ../src
make
cd ../dist
game.exe


Once you start setting the working directory at startup, you can run from the Makefile directory without worrying about it. Here's some code from my current project (I'm coding to a C99 compiler specifically, so it won't compile on pre C99 without some modifications to variable declarations - unless you're using C++ of course):

static void sSetWorkingDir(const char *arg0)
{
	// find the last path separator
	char *p = strrchr(arg0, '/');
	if(!p)
		p = strrchr(arg0, '\\');
	if(!p)
	{
		/*
		 The log isn't open yet, so just do an assert here so that at least
		 if it fails in dbg mode I'll know. If it fails in the wild then I'll
		 hope there's enough error info logged from other parts of the app
		 to know the problem. Don't know what I'd do about it, though!
		*/
		LS_ASSERTF(p, "Failed to determine working directory: arg0 [%s]", arg0);
		return;
	}
	
	// determine the length of the path sans the filename
	size_t len = p - arg0 + 1;
	len = (len < MAX_OS_PATH) ? len : MAX_OS_PATH;
	
	// copy to a temp buffer
	char path[len + 1];
	lsStringCopy(path, len, arg0);
	
	// set the working directory
	bool ret = lsPlatform_SetWorkingDir(path);
	
	// same as error case above
	LS_ASSERTF(ret, "Failed to set new working directory: path [%s]\n", path);
}






All of the stuff prefixed with 'ls' comes from my utility code. LS_ASSERT is a custom assert macro that throws up a message box, logs the problem along with debug info to a file, and shuts everything down. lsStringCopy copies strings safely, and lsPlatform_SetWorkingDir calls SetCurrentDirectory on Windows.

If you want to make sure you can always load your resources when people start your game from unexpected places, you should call a function like this early during the initialization phase before any file loading is begun.

Comments: 0 - Leave a Comment

Link



Friday, November 4, 2005
Sometimes you find yourself confronted with a headscratcher regarding string input. Your app is supposed to provide some sort of feedback on the string, but isn't. For example, when the player types a command into a console in an FPS, or when parsing command line parameters to configure different options. You've checked the code over and over. You've stepped through with the debugger. Everything is as it should be but it just isn't working.

One thing that every programmer should do, but doesn't, is to bracket strings when logging them. What I mean:

// in C
printf("[%s]\n", someString);

// or Java
System.out.println("[" + someString + "]");


It doesn't matter if you use brackets, parentheses or curly braces. I prefer brackets because I use parentheses and curly braces for other things. The reason you want to do this is to catch cases where the out put should look like this:

[MyString]

But really looks like this:

[MyString ]

The brackets will allow you to catch unintended leading and trailing spaces much more easily than you otherwise would.

I saw this tip in a book on J2EE best practices 3 or 4 years ago and have applied it to all of my projects since. The reason I mention it now is that I just encountered a bug in my config file loader. The format is simple, key = value pairs. In the parser, I had overlooked the need to account for spaces on either side of the equals sign. So when requesting cofig values in code, the keys weren't matching up since all of the loaded keys had a space on the end. What could have been a long debugging session was reduced to a quick look in the log after dumping the loaded config file. Because of all of the brackets on the keys & values, I saw the problem immediately.

And if you are wondering why I'm writing config parsers when I'm using Python as a scripting language, the answer is that I've dropped scripting. I really don't need it. I can accomplish what I'm after by setting values in config files. And that stays within my goal of keeping things small and simple.

Comments: 1 - Leave a Comment

Link



Thursday, November 3, 2005
Today I settled on a business name. As a safety measure, I reserved a domain name for it through GoDaddy. I also signed up for a small webhosting package with LunarPages. The website (well, forums as it turns out) of my Dark Age of Camelot guild has been hosted there for some time now. I've been happy with the service. The new site won't be up for a while yet, but it's there waiting when I'm ready to get things moving. Next step on that end is to make sure the name I chose isn't already in use where I plan to register. I'm fairly sure it's not, but not checking up on it would be shortsighted.

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

One of the first steps I took in preparing to take the plunge was to set up a local server (the easy way - through a router) for Subversion, mysql, and Apache. Subversion for my game projects, of course, and mysql/Apache for some web apps I want to run internally and for developing my website. It's something I had been wanting to do for quite a while.

I dusted off an old box I'd been saving for the purpose and installed a recent version of Mepis. My relationship with Linux has never been a good one. I really have never understood the attraction. I've tried to learn my way around it several times via different installations. I even have an extra hard drive on my dev box with a working Ubuntu installation. I've booted into it twice since I installed it a few months ago. Using Linux for no other reason than to learn it is a chore for me. Now that I have a reason I think it's much more likely I'll learn a few things.

I have a dual montior setup on my dev box. One of the monitors is plugged into a KVM switch along with my keyboard and mouse. The KVM is shared by both the dev box and the server. So the secondary monitor on my dev box is also the only monitor on the server. Switching from system to system is easy, but I'm forcing myself not to do that for mundane stuff. In addition to svn, apache, and mysql, I also have telnetd and wu-fptd running. So for the mundane tasks I'm logging in to telnet from my dev box. File transfers for the web stuff or whatever I handle through the Windows command line ftp client. After a short time of doing this I'm finding it easier now to work with Linux command line tools and remembering their options.

The ultimate goal here is that I want to be able to learn my way around Linux well enough to set up and manage a dedicated server in the future. There's plenty of time yet before I need one, so by the time I do I should be a pseudo Linux Geek. I can never be a true Linux Geek because I honestly like using Windows better (at least on the Desktop).

Comments: 2 - Leave a Comment

Link



Wednesday, November 2, 2005
One of the reasons (among others) that I chose C over Java for Game #1 is that my C Voodoo is stronger. I've never used C professionally, but I have used it extensively for a wide variety of personal projects over the last 7 years. My relationship with Java is actually older as it was my first programming language at the ripe old age of 26. But I've never delved as deeply into the nooks and crannies of the language as I have with C.

If you look at Josh Bloch's book Effective Java Programming Guide (modeled after Myers' Effective C++ books), you'll find 57 items that many 'experienced' Java programmers aren't aware of. Out of the 50 items in the book, there were several which were news to me even after having used Java for a few years. It's really easy in Java shoot yourself in the foot (kill app performance, create memory leaks) if you don't fully understand what's going on. I recently picked up another book of Java Voodoo that really made my day.

One of the things I find attractive about Java is the built-in support for dynamic class loading. I have used it quit a bit and sometimes find myself missing it when working in other languages such as C, but I've never delved in under the hood to explore its full potential. So I was at the bookstore looking for a book on secure C/C++ programming (to aid me in my current project - never know what you might learn from such a book that you don't know already) when I stumbled across this little gem entitled, Component Development for the Java Platform.

Chapter one is an overview of Component Oriented Design vs. Object Oriented Design and how the author feels they should be used in conjunction on most projects. That was interesting and brief. Then I opened chapter two. I now know more than I ever have about class loaders and the class path. That one chapter has changed the way I view software design, particularly with Java. One of the most interesting things I got out of it was how easy Hot Swapping a class at runtime is. I'm not talking about differenct classes, but a modified version of the same class. There's very little code needed for a basic implementation of hot swapping. But even more important is that the author outlines several rules that should be followed to avoid problenms with hot swapping and class loading in general - things I never would have considered.

There's a lot of good material in this book. While he covers topics most experienced Java programmers have some familiarity with, and probably use on a regular basis, he goes beyond common knowledge to the really arcane stuff. Most of this info is most likely available around the net in one form or another, but having it all compiled into one book with along with the author's insights is quite beneficial. It's the kind of stuff you would never think of researching until you need to implement it.

Anyone who works with Java on a regular basis should get this book. I've had ideas for some time for a component-based game framework in Java. Now I can throw that out the window and come at it from a whole new direction. I'm actually pretty excited. I would love to implement some of the ideas I'm getting from this in Game #1, but that would mean starting over and abandoning the foundation I've been laying in C. This early in the project is the time to do it if I'm going to, but I need to evaluate whether these new ideas are beneficial enough to this particular project to warrant switching over.

Comments: 0 - Leave a Comment

Link


All times are ET (US)

 
S
M
T
W
T
F
S
1
5
6
8
9
10
11
12
13
15
16
18
19
20
21
22
24
25
27
29

OPTIONS
Track this Journal

 RSS 

ARCHIVES
June, 2006
February, 2006
January, 2006
December, 2005
November, 2005
October, 2005