I am updating an old library we use at my work for some Fortify issues, its an ancient library written by some scientist between 20 and 30 years ago with a bunch of basic math functions that still gets used throughout our system. Since its so old, and presumably not written by a computer scientist, there are a number of irregularities, but it all works. However there is one section where its just freeing up memory, where I can't make heads or tails of what the syntax even means. It looks like this:
void free_vector ( double * v, int l, int h )
{
free( (char *)( v + l ) ) ;
}
I don't understand what is going on here. function is getting called a number of times elsewhere, and I don't know what its doing, and I don't want to just assume its freeing the memory properly.
I am updating an old library we use at my work for some Fortify issues, its an ancient library written by some scientist between 20 and 30 years ago with a bunch of basic math functions that still gets used throughout our system. Since its so old, and presumably not written by a computer scientist, there are a number of irregularities, but it all works. However there is one section where its just freeing up memory, where I can't make heads or tails of what the syntax even means. It looks like this:
void free_vector ( double * v, int l, int h )
{
free( (char *)( v + l ) ) ;
}
I don't understand what is going on here. function is getting called a number of times elsewhere, and I don't know what its doing, and I don't want to just assume its freeing the memory properly.
Share Improve this question edited Mar 28 at 7:46 Toby Speight 31.3k52 gold badges76 silver badges113 bronze badges asked Mar 27 at 18:03 Bryan BergeronBryan Bergeron 591 silver badge1 bronze badge 16 | Show 11 more comments2 Answers
Reset to default 8there is one section where its just freeing up memory, where I can't make heads or tails of what the syntax even means. It looks like this:
void free_vector ( double * v, int l, int h ) { free( (char *)( v + l ) ) ; }
I don't understand what is going on here.
It seems simple enough. v
is a pointer to double
and l
is an integer. v + l
is therefore standard pointer arithmetic, resulting in a pointer to l
doubles past past *v
.
Then (char *)
is a cast operator, whose effect is to convert the result of v + l
from type double *
to type char *
. This is a perfectly valid thing to do, but it is unnecessary here if there is a prototype for free()
in scope. The purpose might be to ensure correctness despite not having a prototype in scope. This might be a sign that the code has an even longer history than you imagine.
Any way around, the result of the expression has a valid type for an argument to free()
. The value might or might not be semantically valid for such a call; that depends on numerous factors not addressed in the question. Since this function is used a lot, and incorrect usage of free()
tends to lead quickly to loud program failures, my first guess would be that as this function is used, the values passed to free()
indeed are semantically valid. That is, they are pointer values that were previously returned by malloc()
, calloc()
, or realloc()
, and not yet freed.
That's weird, but not unclear.
My guess would be that this is part of a provision for selecting between C-style 0-based and Fortran-style 1-based indexing, or perhaps a more general index-range facility even than that. You should check the corresponding allocate_vector()
function, but I'd bet that it looks something like this:
double *allocate_vector(int l, int h) {
return ((double *) malloc((h - l + 1) * sizeof(double))) - l;
}
The idea is that given v = allocate_vector(low, high)
, the valid indexes i
for the expression v[i]
are low
through high
, inclusive. Observe that in that case, the + l
in your free_vector()
offsets the - l
in my guessed allocate_vector()
.
Sadly, although this quite possibly works as intended on every C implementation this code has been used with, the C language spec does not require it to work at all when l
is greater than 0. Nevertheless, your particular C implementation might guarantee that it works.
In the line
free( (char *)( v + l ) ) ;
the type cast to char *
has no effect, because the argument will be converted to void *
anyway. So this line is effectively the following:
free( v + l );
In standard C, the function free
requires that you pass it either
- the address of a previous return value of a call to a memory allocation function (
malloc
,calloc
,realloc
oraligned_malloc
), or - the argument
NULL
(which causes the function call to have no effect).
One possible reason to pass a pointer value with an offset value to free
is if this pointer value does not contain the original value returned by a memory allocation function mentioned above, but if it is rather offset by a certain value. For example, the following code is legal in C:
// dynamically allocate memory for an array of
// 5 elements of type "double"
double *p = malloc( 5 * sizeof p[0] );
if ( p == NULL )
{
// TODO: handle error
}
// make p point to the fourth element
p += 3;
// modify the fourth element using the offsetted pointer
*p = 20.5;
// free the array using the original pointer value
free( p - 3 );
It is possible that the code you are talking about is doing something similar.
However, in your posted code, this would only be legal in cases in which the argument l
is zero or a negative value. If l
is a positive value, then the program's behavior is undefined in standard C, because the program is either
- using pointer arithmetic outside the bounds of the allocated memory block, or
- passing a pointer value to
free
that was not previously returned by one of the memory allocation functions mentioned above.
For this reason, your posted code is highly suspicious and I suggest that you audit this part of the program very carefully.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744074853a4554209.html
v + l
performs pointer arithemetic, and the result is a pointer which the function thenfree
s. But that doesn't explain the meaning/purpose of the logic, and whyl
is added tov
to get the memory address to free . – wohlstad Commented Mar 27 at 18:06void
type then; the implementation ofalloc
in that book returned achar *
, andfree
took achar *
argument. – ad absurdum Commented Mar 27 at 19:09