On 08/24/2013 03:05 PM, Sharwan Joram wrote:
....
I've modified the code with the guidelines given by James and other mentors in the list, mentioned below. But it's still failing.
Not quite. As I and other have said, for best results you need to give
us a complete, compilable program. All you've given us is a:
-----------Code Snippet -------------
While the code you have given us contains defects severe enough to be
the cause of the symptoms you've observed, you had no way of being sure
that would be the case. It could very well have been that the actual
problem was in some other part of your program.
if(token != NULL){
char *temp_token = (char *) malloc (strlen(saved_token) + 1);
memcpy(temp_token, saved_token, strlen(saved_token));
Once again, you're using the value returned by malloc() before bothering
to check whether malloc() has succeeded. If malloc() failed, temp_token
would be null, and the call to memcpy() would render the behavior of
your program undefined.
idx = parametercount = detect_delim_count(temp_token, delimiters);
if (temp_token)
Now you've finally bothered checking whether the allocation succeeded.
That's ironic, because you wait until after it is used twice in ways
that would be dangerous if temp_token is null. The only code you protect
is the call to free(), and free()ing a null pointer is actually
perfectly safe.
detect_delim_count() returns the number of delimiters. The number of
parameters is inherently one more than the number of delimiters. I see
from a later message that you're well aware of that fact. Therefore, I
find it puzzling that you would store the value returned by
detect_delim_count(), in a variable named parametercount. You should
either have named the variable delimitercount, or you should have added
1 to the value returned by detect_delim_count() before storing it in
parametercount.
free(temp_token);
parameters = malloc(parametercount * sizeof(char *));
Here you allocate enough room in the parameters array to store one
pointer for each delimiter. However, what you need is enough room to
store one pointer for each parameter, which is one more than the value
currently stored in parametercount.
if ( NULL == parameters){
fprintf(stdout, "CLI: Couldn't allocate sufficient memory . Exiting \n");
exit(1);
}
for( parametercount = 0 , token = strtok(saved_token, " "); token && *token ; ++parametercount , token = strtok(NULL, " ")){
parameters[parametercount] = calloc(30 , strlen(token) + 1);
You're now allocating enough space for 30 copies of the token. I think
you should change 30 to 1, unless there's some reason, not obvious in
the code you've shown, for setting aside that much space.
The last successful call to strtok() will result in the above code
attempting to store the value returned by malloc() into parameters[idx],
but you only allocated enough memory to store idx pointers:
parameters[0] through parameters[idx-1]. You haven't allocated enough
space to store anything in parameters[idx]. Attempting to do so renders
the behavior of your program undefined. Under certain circumstances,
your program might fail immediately because of this defect. However,
judging from the symptoms you've reported, what you did was corrupt some
memory being used by some other part of the program, almost certainly
memory being used by the malloc() family to manage the heap. That's why
the subsequent call to free() failed.
if ( NULL == parameters[parametercount]){
fprintf(stdout,"CLI: Couldn't allocate sufficient memory. Exiting \n");
exit(1);
}
strncpy(parameters[parametercount], token, strlen(token));
strlen() has to examine every character in the string, to look for the
terminating null character. strncpy() needs to retrieve the value of
every character in the string. If you'd simply called strcpy() instead,
then it would only have gone through the string once.
In some contexts, strncpy(dest, src, count) can be safer than
strcpy(dest,src). That's true only when "count" is less than strlen(src)
and also less than the length of the array pointed at by dest.
strncpy(dest, src, strlen(src)) stops at exactly the same place that
strcpy() would stop - you don't get any protection at all. If
strlen(src) is bigger than the size of the array pointed at by dest,
strncpy(dest,src,strlen(src)) will still overwrite then end of that
array, just like strcpy().
}
shutdown = (currentcommand->command_handler)(client_fd, parameters, parametercount);
}
}else{
/* some more code here */
}
if (parameters != NULL){
for (parametercount = idx ; parametercount >= 0; --parametercount)
free(parameters[parametercount]);
You set parametercount initially to the same value as idx, and used
parametercount to determine how many parameters to allocate space for.
Unless code that you haven't shown has changed the value of idx since
that time, space was therefore only allocated for idx different
pointers, starting with parameters[0] and ending with parameters[idx-1].
However, the above loop starts by trying to retrieve the value of
parameters[idx] and passing it to free(). This would still be a separate
problem even if you corrected parametercount earlier to contain the
count of the parameters, rather than the count of delimiters. In that
case, parameters[idx] would refer to memory that had never been
allocated for use by your program, and which had never been written. to.
As a result, it might contain a trap representation, in which case even
retrieving the value of parameters[idx] would render the behavior of
your program undefined. Even it if were not a trap representation, it
almost certainly would not contain a value returned by a call to
malloc(). Therefore, passing that value to free() would also render the
behavior of your code undefined.
You should correct the for() loop to either of the following forms:
for(parametercount=idx-1; parametercount >=0; --parametercount)
or
for(parametercount=0; parametercount<idx; parametercount++)
The second form is slightly shorter and more idiomatic. I'd also
recommend exchanging the variable names idx and parametercount, since
you're using parameter count more like an index into the parameters
array, and less like a fixed count of parameters.