Dai
Dai

Reputation: 155428

Avoiding freeing a string literal

If you have a function in C that takes ownership of whatever is passed into it, such as a function that adds a struct to a vector buffer by-value, and this struct value contains a member pointer to a character array (a string).

During the buffer's cleanup routine, it should release the strings that it owns, but what if some strings are allocated at runtime, but others are allocated at compiletime using a string literal.

There is no safe and standard (non-proprietary) way to detect if a char* points to read-only memory, so what is this hypothetical freeVector function to do with a pointer to a char buffer?

struct Element {
    int   id;
    char* name;
}

struct Vector {
    size_t maxIndex;
    size_t length;
    struct Element buffer[];
}

void addToVector(struct Vector* vector, struct Element element) {
    // lazy-reallocation logic here if maxIndex => length
    vector->buffer[ vector->maxIndex++ ] = element; // by-value copy
}

void freeVector(struct Vector* vector) {
    for(size_t i = 0; i < vector->maxIndex; i++ ) {
        free( vector->buffer[ i ].name ); // segfault/AV if name is a literal
    }
}

Upvotes: 3

Views: 283

Answers (1)

Gene
Gene

Reputation: 46990

The blessing and the curse of C is that it lets this totally up to you. Two choices are to allocate everything on the heap and to define a fat pointer type that includes a bit to say whether each instance needs freeing. A clever albeit non-portable implementation might use a low order bit of the pointer itself because for many architectures the bottom 2 bits or more of all pointers are always zero. Garbage collectors have used this trick to distinguish pointers from unboxed discrete types (fixnums in the biz) almost forever.

If you allow more than one pointer to the same object (think graph data structure), then things get more complex or interesting depending on your point of view. For this, you'll probably need a garbage collection scheme: obstacks, reference counting, mark and sweep, arena copying, etc. Other languages tend to give you one of these as a built-in or (as in C++) language features deliberately meant to support implementing one or more yourself. With C, not so much...

Upvotes: 3

Related Questions