Can't solve memory management (valgrind) in this c program - c

My problem is as follows. I have to create a C program that concatenates all the parameters in input in one buffer and then this return this buffer. My solution works, but there are memory management issues.
How can I fix the problem?
#define RIALLOCA(buf, newsize) buf = realloc(buf, newsize);
char *mystrcat(char *buf, size_t sz, char *first, ...) {
va_list l;
va_start(l, first);
buf = malloc(strlen(buf) + 1);
if (sz < strlen(first) + 1) {
sz += (strlen(first) + 1);
}
RIALLOCA(buf, sz + 1 + 16);
strncat(buf, first, strlen(first));
char *nextString = va_arg(l, char *);
while (nextString != NULL) {
// sz += strlen(nextString);
RIALLOCA(buf, strlen(buf) + strlen(nextString) + 1 + 16);
strncat(buf, nextString, strlen(nextString));
nextString = va_arg(l, char *);
}
va_end(l);
return buf;
}
int main(int argc, char *argv[]) {
if (argc != 7) {
printf("troppi pochi argomenti\n");
return -1;
}
char *buffer = NULL;
RIALLOCA(buffer, 16); // macro che effettua l'allocazione
buffer[0] = '\0';
buffer = mystrcat(buffer, 16, argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], NULL);
printf("%s\n", buffer);
free(buffer);
return 0;
}
This is problem with Valgrind

The problem is that - when you call buf = malloc() inside mystrcat() - you are causing a memory leak. Memory had already been dynamically allocated for buf within your main().
Change
buf = malloc(strlen(buf)+1);
to
buf = realloc(buf, strlen(buf) + 1);
Also ... I agree with user3629249: providing macros for standard library functions in the way you have done seems redundant - at least in this context.

in function: mystrcat()
This statement:
buf = malloc(strlen(buf) + 1);
is not correct. Because buf is already a pointer to allocated memory AND this is not modifying the pointer buf back in the main() function but rather just the parameter on the stack.
To correct:
in main() (notice the additional '&' on parameter: buffer)
buffer = mystrcat(&buffer, 16, argv[1], argv[2], argv[3], argv[4],
argv[5], argv[6], NULL);
in mystrcat() remove this line
buf = malloc(strlen(buf) + 1);
regarding:
if(sz < strlen(first) + 1)
{
sz += (strlen(first) + 1);
}
since sz contains 16 and the first character in buf is '\0' This if() statement will never be entered.
Since the passed parameter buf is now a pointer to a pointer, due to the change in main(), the signature should be:
char* mystrcat(char **buf, size_t sz, char *first, ...)
and all references to buf should be de-referencing that parameter to access the pointer value in main()
There is plenty more, but the above are the underlying problems

Related

I can't split my function into sub functions because of a static variable

I'm still writing my own implementation of get_next_line, a function that takes a file descriptor and outputs the line of the file, then the next line and so on, since my last post, but now everything is working in my code !
The problem is, in the norms I have to follow, my code have to be less than 25 lines, and my function is actually 30. I successfully split into one sub function but I need to split it one more time but this time, I get invalid frees or invalid reads and completely wrong results.
(I have a get_next_line_utils.c that contains homemade libc functions and it has a strjoin that frees the stash in parameter because it creates a new one)
Here is my working code :
static int check_line(char *str)
{
int i;
i = 0;
if (!str)
return (-1);
while (str[i])
{
if (str[i] == '\n')
return (1);
i++;
}
return (-1);
}
/*
ft_strcut is used in one case in GNL.
When the stash contains a \n, we are cutting the string
from the \n to the end of the string, so our new stash does not
longer contain the \n ans the past line.
*/
static char *ft_strcut(char *str)
{
char *cutted_str;
int i;
int j;
i = 0;
j = 0;
while (str[i] != '\n')
i++;
cutted_str = malloc(sizeof(char) * (ft_strlen(str) - i + 1));
if (!cutted_str)
return (NULL);
i++;
while (str[i])
cutted_str[j++] = str[i++];
cutted_str[j] = '\0';
free(str);
return (cutted_str);
}
/*
I used this function to make GNL less than 25 lines.
This block of code was between the variable declaration and the while loop.
This function is checking the validity of fd, BUFFER_SIZE and the stash.
And it's initializing our stash for the rest of GNL if the verification passed.
*/
static char *stash_checking(int fd, char *stash, char *buff, int readed)
{
if (fd < 0 || BUFFER_SIZE <= 0)
return (NULL);
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
if (!buff)
return (NULL);
readed = read(fd, buff, BUFFER_SIZE);
if (readed <= 0 && !stash)
{
free(buff);
return (NULL);
}
buff[readed] = '\0';
if (!stash)
stash = ft_substr(buff, 0, ft_strlen(buff)); //It's like strdup
else
stash = ft_strjoin(stash, buff);
free(buff);
if (stash[0] == '\0')
{
free(stash);
stash = NULL;
return (NULL);
}
return (stash);
}
char *get_next_line(int fd)
{
static char *stash; //Static variable to keep the stash between calls.
char *buff; //Buffer to read the file.
char *line; //Line to return.
int readed; //Readed bytes.
readed = 0;
buff = NULL;
stash = stash_checking(fd, stash, buff, readed);
while (stash)
{
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
readed = read(fd, buff, BUFFER_SIZE);
buff[readed] = '\0';
stash = ft_strjoin(stash, buff);
free(buff);
if (readed < BUFFER_SIZE && check_line(stash) == -1)
{
line = ft_substr(stash, 0, ft_strlen(stash)); //It's like strdup
free(stash);
stash = NULL;
return (line);
}
else if (check_line(stash) != -1)
{
line = ft_substr(stash, 0, ft_strchr(stash, '\n') - stash + 1);
stash = ft_strcut(stash);
return (line);
}
}
return (NULL);
}
As you can see, I successfully split a chunk of code into a function named stash_checking to make my code shorter but it is not enough.
I tried to put the lines from if (readed < BUFFER_SIZE && check_line(stash) == -1) to the end of else if
in a sub function that I named handling_cases and I'm getting a double free() error.
static char *handling_cases(int readed, char *stash, char *line)
{
if (readed < BUFFER_SIZE && check_line(stash) == -1)
{
line = ft_substr(stash, 0, ft_strlen(stash));
free(stash);
stash = NULL;
return (line);
}
else if (check_line(stash) != -1)
{
line = ft_substr(stash, 0, ft_strchr(stash, '\n') - stash + 1);
stash = ft_strcut(stash);
return (line);
}
return (NULL);
}
char *get_next_line(int fd)
{
static char *stash; //Static variable to keep the stash between calls.
char *buff; //Buffer to read the file.
char *line; //Line to return.
int readed; //Readed bytes.
readed = 0;
buff = NULL;
stash = stash_checking(fd, stash, buff, readed);
while (stash)
{
buff = malloc(sizeof(char) * (BUFFER_SIZE + 1));
readed = read(fd, buff, BUFFER_SIZE);
buff[readed] = '\0';
stash = ft_strjoin(stash, buff);
free(buff);
line = handling_cases(readed, stash, line);
if (line)
return (line);
}
return (NULL);
}
I have tested a lot of similar things, putting all the while loop in a sub function that returns the line and many different things but I don't understand why, I'm getting some double frees, invalid write or not expected output.
I would like to understand why putting the exact chunk of code in a separate function is doing errors.
I debugged my code, and it seem's my stash is not correctly freed, or always have no values in it when I call GNL at the end of the file.
I'm sorry if this is a little confusing, my english is not perfect yet..
Any help is much appreciated !
Your approach with passing stash is kind-of correct, but you missed one thing: You need to pass a pointer to the variable to a called function. This resembles "pass by reference" in C, which only has "pass by value".
It does not matter, whether such a variable is static or not. The called function does not need to know, and you cannot make it know.
I have simplified your example and used generic names:
#include <stdio.h>
#include <stdlib.h>
static void called(int **pointer_to_pointer) {
int value = 42;
if (*pointer_to_pointer != NULL) {
value = **pointer_to_pointer;
//free(*pointer_to_pointer);
}
*pointer_to_pointer = malloc(sizeof **pointer_to_pointer);
**pointer_to_pointer = value + 1;
printf("%s(): %p -> %p -> %d\n", __FUNCTION__, (void*)pointer_to_pointer, (void*)*pointer_to_pointer, **pointer_to_pointer);
}
static void caller(void) {
static int *pointer = NULL;
int value = 23;
if (pointer != NULL) {
value = *pointer;
//free(pointer);
}
pointer = malloc(sizeof *pointer);
*pointer = value + 1;
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
called(&pointer);
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
called(&pointer);
printf("%s(): # %p: %p -> %d\n", __FUNCTION__, (void*)&pointer, (void*)pointer, *pointer);
}
int main(void) {
printf("%s()\n", __FUNCTION__);
caller();
printf("%s()\n", __FUNCTION__);
caller();
printf("%s()\n", __FUNCTION__);
}
Some notes:
Because in my environment malloc() returned exactly the same memory that was just free()ed, I needed to comment those calls to show that new memory was allocated.
The size in the calls of malloc() uses the sizeof operator with the expression that "is" the wanted object. You can keep using the parenthesized version of this operator with a data type, like sizeof (int) for this demonstration program.
Here is no error check after calling malloc(). Don't do this in production code.
__FUNCTION__ is a nice predefined preprocessor macro of GCC and Clang, which expands to the name of the current function as a C string.
printf() expects void* for its format specifier "%p", so every pointer value is correctly cast.

How to append a char to a String in C using a function

I was writing a lexical analyzer in which I need to append a char to a string (a char *). For some reason, the code below is resulting in string having a value of "(null)" when I print it to stdout. The function is given below.
void append_char(char *buffer, char c) {
if(buffer == NULL) {
buffer = malloc(sizeof(char));
if(buffer == NULL) {
fprintf(stderr, "COuld not allcocate memory to buffer\n");
}
} else {
buffer = realloc(buffer, sizeof(buffer) + sizeof(char));
}
buffer[sizeof(buffer) - 1] = c;
}
When I run the lines
char *buf = NULL;
append_char(buf, 'a');
append_char(buf, '\0');
printf("buffer: %s\n", buf);
it prints (null) to stdout. How can I fix this?
Pass by value
append_char(char *buffer, char c) does not affect the caller's buf in main(): append_char(buf, 'a');. buf remains NULL. This leads to OP's output.
Insufficient size
Insufficient size for the newly allocated string. No room for the null character.
Wrong size
With char *buffer, sizeof(buffer) is the size of a pointer, not the amount allocated beforehand.
Lost memoery
When buffer = realloc(buffer, sizeof(buffer) + sizeof(char)); fails (realloc() returns NULL) , the original value of buffer is lost. Save the result and test.
Note: OK to call realloc(NULL, ...).
char *append_char(char *buffer, char c) {
size_t old_length = buffer ? strlen(buffer) : 0;
size_t new_length = old_length + 1; // +1 for c
// Size needed for a string is its length + 1
char *new_buffer = realloc(buffer, new_length + 1); // +1 for \0
if (new_buffer == NULL) {
fprintf(stderr, "Could not allocate memory to buffer\n");
free(buffer);
return NULL;
}
new_buffer[old_length] = c;
new_buffer[old_length + 1] = '\0';
return new_buffer;
}
// Usage
buf = append_char(buf, 'a');
There are a number of problems with your program:
buffer is a local variable of append_char(). As soon as this function returns, the buffer variable becomes unusable. You need to pass in the address of buffer to write the address returned by malloc() and realloc() to buffer.
buf is a pointer to a char. sizeof (buf) does not depend on the number of characters in buf.
You do not check the return value from realloc().
You are not allocating space for the NUL terminator.
You do not call free() after you are done.
Here is one way to achieve what you are trying to do (although I am not trying to fix all the problems I mentioned above):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_char(char **buffer, char c) {
if(*buffer == NULL) {
if((*buffer = malloc(sizeof(char) + 1)) == NULL) { /* + 1 for the NUL terminator */
fprintf(stderr, "COuld not allcocate memory to buffer\n");
return;
}
(*buffer)[0] = (*buffer)[1] = '\0';
} else {
*buffer = realloc(*buffer, strlen(*buffer) + sizeof(char) + 1 /* for the NUL terminator */);
}
(*buffer)[strlen(*buffer) + 1] = '\0';
(*buffer)[strlen(*buffer)] = c;
}
int main(void)
{
char *buf = NULL;
append_char(&buf, 'a');
append_char(&buf, '\0');
printf("buffer: %s\n", buf);
}

snprintf usage for making up formatted strings

I'm trying to learn about the snprintf and found this answer with the example:
char buf[20] = "";
char *cur = buf, * const end = buf + sizeof buf;
cur += snprintf(cur, end-cur, "%s", "foo");
printf("%s\n", buf);
if (cur < end) {
cur += snprintf(cur, end-cur, "%s", " bar");
}
printf("%s\n", buf);
free(str);
The thing that is not clear to me is that we allocate a fixed hardcoded buffer size which seems suffer from buffer overflow. In the N1570 I found that (7.21.6.5)
1
#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);
2 The snprintf function is equivalent to fprintf, except that the
output is written into an array (specified by argument s) rather than
to a stream. If n is zero, nothing is written, and s may be a null
pointer.
So to me it appears as the idiomatic usage would be as follows:
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1; //How much to allocate?
char *const str = malloc(need_space * sizeof(char)); //allocate
int written = snprintf(str, need_space, "abs %s", "fgh"); //do format
printf("Need space = %d, written = %d\n", need_space, written);
printf("%s\n", str);
Or this is not common and has another problem?
The 2x call to snprintf() is a common idiom.
... has another problem?
Problems lie in the corners
Format maintenance
The below suffers from a repeated format - prone to breaking as code ages and and only one line is changed.
// Oops!
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1;
char *const str = malloc(need_space * sizeof(char));
int written = snprintf(str, need_space, "abs %s ", "fgh");
Did you notice the difference?
Better to state the format once.
#define FMT_ABS_S "abs %s"
int need_space = snprintf(NULL, 0, FMT_ABS_S, "fgh");
char *const str = malloc(sizeof *str * (need_space + 1u));
int written = snprintf(str, need_space, FMT_ABS_S, "fgh");
Volatility
Code needs to insure the values do not change (non-volatile) between the 2 calls and special concern arise in multi-threaded applications.
Error checking
Code lacked checks. Yet even with checks, how to even handle unexpected results - perhaps just bail?
static const char *fmt_s = "abs %s";
int needed_space = snprintf(NULL, 0, fmt_s, "fgh");
if (needed_space < 0) {
Handle_EncodingError();
}
char * const str = malloc(sizeof *str * (needed_space + 1u));
if (str == NULL) {
Handle_OutOfMemory();
}
int written = snprintf(str, needed_space, fmt_s, "fgh");
if (written < 0 || written > needed_space) {
Handle_Error();
}
Going twice though
2 calls can be wasteful in select situations, yet commonly the impact is less than thought. #Jonathan Leffler
Yet for me, the "what to do if allocation fails" is a show stopper anyways and code reports the error and maybe exit.
Selectively, once is enough
When the s*printf() format is tightly controlled, I see 1 call as sufficient.
// int to string
#define LOG2_N 28
#define LOG2_D 93
// Number of char needed for a string of INT_MIN is log10(bit width) + 3
#define INT_SIZE ((sizeof(int)*CHAR_BIT-1)*LOG2_N/LOG2_D + 3)
char s[INT_SIZE * 2]; // I like to use 2x to handle locale issues, no need to be stingy here.
int len = snprintf(s, sizeof s, "%d", i);
if (len < 0 || (unsigned) len >= sizeof s) {
Handle_VeryUnusualFailure();
}

Assignment makes integer from a pointer without a cast

int main(int argc, char *argv[]) {
if(argc!=3) {
printf("You must pass exactly three para \n");
return 0;
}
char *buffer = argv[1];
//printf("The length of the buffer string is %d\n",buflen);
char *mystring = argv[2];
//printf("The length of the user string is %d\n",len);
addstring(buffer, mystring);
return 0;
}
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
*dest = (char *)malloc(buflen + len + 1);
printf("The size of destination is %lu\n",sizeof(dest));
dest = strcpy(dest,buffer);
dest = (dest + buflen);
dest = strcpy(dest,mystring);
printf("The final string is %p",dest);
return 0;
}
In the above code, the function addstring(..) shoes this error Assignment makes integer from a pointer without a cast. I know I'm taking the value of a pointer and putting it in integer, but how may I do it to resolve this error?
Even after changing *dest to dest, your function addstring is not works properly.. Simply try like this
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
dest = (char *)malloc(buflen + len + 1);
printf("The size of destination is %d\n",sizeof(dest));
strcpy(dest,buffer);
strcat(dest,mystring);
printf("The final string is %s\n",dest);
return 0;
}
You have done
*dest = (char *)malloc(buflen + len + 1);
instead of
dest =malloc(buflen + len + 1);
Your program saying warning to me for this line
printf("The size of destination is %lu\n",sizeof(dest));
sizeof() return type is not long unsigned int.
So use %d or %u or %zu as a access specifier in printf() statement.
change
char *dest;
*dest = (char *)malloc(buflen + len + 1);
to
char *dest;
dest = (char *)malloc(buflen + len + 1);
EDIT: As #POW said, you need not cast the result of malloc
There are multiple issue in your code.
Please check the below code
int addstring(char *buffer, char *mystring)
{
int buflen = strlen(buffer);
int len = strlen(mystring);
char *dest;
/* No need to type-cast the malloc() */
dest = malloc(buflen + len + 1); /* *dest holds the value, dest holds the address */
printf("The size of destination is %lu\n",sizeof(dest));
strcpy(dest,buffer);
strcpy(dest+buflen,mystring);/* copy the second string to dest after buffer is copied */
printf("The final string is %s\n",dest); /*To print a string use %s, %p is to print pointer*/
return 0;
}

Weird behaviour of C strcpy

I wrote a tiny program in C. It compile perfectly and works, when I compile it through my Makefile and clang, however, in Xcode this function behaves not like it should (or it behaves like it should and clang is ignoring it).
size_t getUrlForArgAndPlatform(char **dest, const char *arg, const char *platform) {
int isLinux = strcmp(platform, "Linux");
int isOSX = strcmp(platform, "Darwin");
char *platformUrlDelimiter = malloc(6 + 1);
if (isLinux == 0) {
strcpy(platformUrlDelimiter, "linux");
} else if (isOSX == 0) {
strcpy(platformUrlDelimiter, "osx");
} else {
strcpy(platformUrlDelimiter, "common");
}
int length = (int) strlen(kBaseUrl);
length += strlen(platformUrlDelimiter);
length += strlen(arg);
length += 5;
char *buffer = (char *) malloc(length);
if (buffer == NULL) {
exit(EXIT_FAILURE);
}
strcpy(buffer, kBaseUrl);
strcat(buffer, "/");
strcat(buffer, platformUrlDelimiter);
strcat(buffer, "/");
strcat(buffer, arg);
strcat(buffer, ".md");
*dest = malloc(strlen(buffer) + 1);
strcpy(*dest, buffer);
free(platformUrlDelimiter);
free(buffer);
return strlen(buffer) + 1;
}
It works 4 times out of 10. In the other 6 times, Xcode is telling me it's failing at strcpy(*dest, buffer) with a SIGBRT. If I take a look at the debugger, I see that buffer contains the same string twice. Why?
The size you have calculated for buffer is not quite correct:
int length = (int) strlen(kBaseUrl);
length += strlen(platformUrlDelimiter);
length += strlen(arg);
length += 5;
The last part should be '+6' because you need space for 2 times "/", for ".md" AND for the terminating NUL.
(The incorrect length has already been mentioned.)
There is a lot of pointless copying going on in your code. Since you don't modify platformUrlDelimiter, there is no need to copy it twice. This is much simpler:
const char *platformUrlDelimiter = "common";
if (isLinux == 0) {
platformUrlDelimiter = "linux";
} else if (isOSX == 0) {
platformUrlDelimiter = "osx";
}
And remove the call to free (platformUrlDelimiter).
Every call to strcat() (probably) has to needlessly loop through the buffer. I would write:
int length = strlen(kBaseUrl)
+ strlen(platformUrlDelimiter)
+ strlen(arg)
+ 6;
*dest = malloc(length);
if (*dest) {
sprintf (*dest, "%s/%s/%s.md", kBaseUrl, platformUrlDelimiter, arg);
} else {
/* Error */
}
return length;
Now there is no need to use buffer at all.
Also, there's a real bug right at the end of your code:
free(buffer);
return strlen(buffer) + 1;
You must not use the value of buffer in any way after it has been freed.

Resources