atoi -> strtol

Goody. I have 12 instances of atoi() used in my program that I need to replace with strtol(). For those of you who don’t know, these functions convert a string of characters representing a number to an actual integer value.


The function atoi has been deprecated because it is one of those string functions that can be easily exploited with some sort of buffer overflow attack. Basically, when all of the string functions got added to C, those programmers figured that everyone would be good about error checking, and prevent bad strings from being passed to these functions. Certainly, their way was easier. Ironically, in the process of being lazy programmers they forgot one key fact: programmers are lazy. Thus there is a lot of code out there that can be exploited.

I’ll briefly explain why atoi is easier to use:

int atoi(const char *nptr);

Give it a string, it gives you an integer. What could be easier than that? Well… probably very little, but the problem is that there’s no way to do proper error checking. Something might have gone wrong if the function returns 0, but the string could also just contain the value 0. No way to know. I suppose for most applications, you have good enough control over the input that it doesn’t really matter. The problem comes when you’re taking input from a user: a malicious person could potentially mess up your program in this way, if they’re smart about it.

Here’s the function prototype for strtol (that stands for string to long, if that wasn’t clear):

long strtol(const char * restrict nptr, char ** restrict endptr, int base);

Looks kind of scary, doesn’t it? You have to give it the input string, plus a result string that contains any unprocessed text, plus the base (decimal, octal, or hexadecimal) in which the integer value in the string is expressed. On top of all that, you get a lot more possible error returns, not to mention having to check the result string to find out how many characters were actually consumed.

Here’s what a basic use of atoi looks like:

myInt = atoi(myString);

Yeah. That easy. Now here’s a use of strtol, with only basic error checking:

if (strlen(myString)) {
  myLong = strtol(myString, &myResult, 10);
  if (myString == myResult) {
    printf("invalid long conversion\n");
    exit(0);
  }
  printf("Long: %ld\n", myLong);
} else {
  printf("no value to convert\n");
  exit(0);
}

This doesn’t even include the error checking to make sure that the value is in the range you want. The first check makes sure that the input is not just an empty string. The second check after the conversion looks to see if any characters in the input string were consumed. If the input is the same as the result, that means that there wasn’t a valid integer value in the string. Believe me there’s more…

So yeah, fun times for Nick.

4 comments on “atoi -> strtol
  1. A friend of mine made some kind of random little ASCII game which allowed the user to pic a character by inputting a value from 1 to 255, which then got converted into a character. He was quite happy when he “got all the bugs out,” and asked me to try using his little program. When prompted for the above, I maliciously typed in 7 and hit Enter. 7, of course, translates into the ‘bell’ escape character, turning all of the output into a bunch of garbage and beeping. Ah, user error.

  2. metaplasmus says:

    Eex0rz. I actually ran into this same issue just a couple weeks ago, when I was beginning work on my diabolical folkdance project–I hadn’t known that atoi was deprecated and was similarly daunted by strtol. Needless to say, I decided to use Python instead.

    I’ll confess to never having seen the restrict keyword before–I wonder if it’s new in C99 or something?

  3. Nicolas Ward says:

    Yeah, it’s definitely a newer feature. Sounds like it guarantees that the pointer with the restrict keyword type is a unique pointer for the data it points to.

  4. String manipulation sucks ass in C, which is why I usually use Perl. Probably not an option for you.

    But why are you going from ASCII characters that are numbers to integers anyway?

    Note, btw, that sscanf(3) and friends may be easier to use strtol(3).

Nurd Up!