-1

A few days ago I wanted to find a safe alternative to atoi and found the following code as a response to this SO question:

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

typedef enum {
    STR2INT_SUCCESS,
    STR2INT_OVERFLOW,
    STR2INT_UNDERFLOW,
    STR2INT_INCONVERTIBLE
} str2int_errno;

str2int_errno str2int(int *out, char *s, int base) {
    char *end;
    if (s[0] == '\0' || isspace(s[0]))
        return STR2INT_INCONVERTIBLE;
    errno = 0;
    long l = strtol(s, &end, base);
    /* Both checks are needed because INT_MAX == LONG_MAX is possible. */
    if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
        return STR2INT_OVERFLOW;
    if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
        return STR2INT_UNDERFLOW;
    if (*end != '\0')
        return STR2INT_INCONVERTIBLE;
    *out = l;
    return STR2INT_SUCCESS;
}


int main(void) {
  int i;
    /* Lazy to calculate this size properly. */
    char s[256];

    /* Simple case. */
    assert(str2int(&i, "11", 10) == STR2INT_SUCCESS);
    assert(i == 11);
    printf("%i", i);

    /* Negative number . */
    assert(str2int(&i, "-11", 10) == STR2INT_SUCCESS);
    assert(i == -11);
}

Original code source


Isn't this unsafe since the out pointer is set to a variable that has been defined locally within the function?
Wouldn't that mean that once the conversion has been done and the local variable goes out of scope it could get overwritten and we couldn't rely on the value anymore?

I might just be missing something, however currently I do not understand how this is a safe way of going about this.

trbasat
  • 1
  • 1

2 Answers2

0

*out = l; doesn't set out, it sets *out. I.e., whatever it is that out is already pointing at, because it dereferences the pointer. So long as a valid address is passed in, the function will modify a non-local object.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

The out parameter is a pointer which points to the variable i in main. When you later do this:

*out = l;

This does not change out but dereferences it and changes the variable it points to, namely i in main. So when the function returns i is modified.

If out pointed to a local variable in str2int, then you would have the problem of a pointer pointing to invalid memory.

dbush
  • 205,898
  • 23
  • 218
  • 273