Whenever the environment variable's value is larger than its key in this method, I get a buffer overflow. Target is part of a dynamically allocated two dimensional array for tokens. Whenever I replace the token that's an environment variable with a value longer than it, it flows into the next token. I've tried adding a realloc to try and fix it, but it doesn't work or leads to a segfault.
If anyone has any suggestions or can point me at something I"m overlooking, I'd greatly appreciate it, because I have a feeling I'll be kicking myself when I find it out anyway.
The method is:
void envReplace(ENV *evlist, char *Target)
{
if (Target[0] == '#')
{
memmove(Target, Target+1, strlen(Target));
for(q = 0; q<16; q++)
{
if(evlist[q].envVariable!=NULL)
{
if(strcmp(Target, evlist[q].envVariable)==0)
{
//this is where I'd add the realloc as realloc(Target, strlen(evlist[q].Value))
strcpy(Target, evlist[q].Value);
return;
}
}
}
printf("Variable not found\n");
}
else
{
printf("A value that didn't start with # was an argument\n");
return;
}
}
The data structure ENV is:
typedef struct envStorage
{
char *envVariable;
char *Value;
}ENV;
You can pass a pointer to a pointer, like this, and then you can call realloc() inside the function, modifying the original pointer.
void func (char **to_change) {
// Changes the char *target in main()
*to_change = (char *) realloc(*to_change, 20);
sprintf (*to_change, "Blablablablabla\n");
}
int main (int argc, char **argv) {
char *target = (char *) malloc (10);
func(&target);
printf(target);
free(target);
}
In this example, func() writes to the original pointer char *target in the main() function.
What happens in your code, is that you realloc() and assign to a copy of the pointer. The pointer is copied when you call envReplace(). When this function returns, the original pointer contains the old memory address, which is no longer valid allocated memory (it was freed by realloc()).
Related
I am writing a program for ESP8266 on Arduino SDK. My C knowledge is not enough to create professional project so I am training my self about C programming concepts now.
I deep dive to pointers and I tried write a function that return one float value and one string value. I used pointers to do that. For float, everything went well but I cannot return string value.
Here is the my code:
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
sprintf(v_str, "%s", v_str);
sGross = v_str;
}
What is the point that I missed? My char value null or esp8266 restarting?
An option is to directly copy into the sGross.
dtostrf(*fGross, 5, 2, sGross);
Then you have to be sure the function calling has allocated enough memory.
void main()
{
float val1;
char val2[10];
returnMultiple(&val1, val2);
}
The end result will then be
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
If you define an interface you do not only need to specify the function signature but also how to call it.
Typical questions are:
What type of memory is used for buffers
Who will allocate the memory
Who will free the memory
If you define that the caller has to provide the buffer, your code could look like this:
void returnMultiple(float *fGross, char *sGross)
{
if (fGross == NULL || sGross == NULL)
return;
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
void callerfunc(void)
{
char buf[10];
float flt;
returnMultiple(&flt, buf);
printf("flt: %f; str: %s\n", flt, buf);
}
As no dynamic memory allocation is done, nothing needs to be freed.
You might define another return type to allow for error indications.
You assign to sGross pointer the value of local variable v_str... but that data will be destroyed as soon as the function returns (it is stored in the stack, so it will be overwritten).
What you need to do is to allocate the buffer externally. You can either
Use dynamic memory with something like char *str = malloc(10 * sizeof(char)); (remembering to free it as soon as it is no more needed).
Define externally an array of chars, like in the example below
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
/* CHANGES HERE! */
sprintf(sGross, "%s", v_str);
// No need to assign to sGross the pointer of a local variable
// sGross = v_str;
}
int main( void )
{
char testString[10];
float testFloat;
returnMultiple(&testFloat, testString);
printf("%s\n", testString);
return 0;
}
In this case I would suggest to pass not only the char pointer, but also the size of the buffer.
Another solution is allocating the char array within returnMultiple() function, returning the pointer to the char array. sGross parameter in this case would become a char ** variable.
But I suggest starting with easier solutions like the one showed in my example.
First: Your problem is with the way you return the string, not the float, so I'm reducing my example to just returning the string.
There are two ways you can implement this: Either the memory for your string is allocated by the function, or by the caller. The easy way is this:
void toString(char *str, int d) {
sprinf(str, "%d", d);
}
int main(void) {
char result[12];
toString(result, 50);
puts(result, stdout);
return 0;
}
In this case, result is a 12 byte string allocated on the stack of main. 12 bytes is big enough to store the string representation of an integer, so that's safe, if you're not sure what size the result can have, then watch out.
Second option:
void toString(char **str, int d) {
char *v_str = malloc(12);
sprintf(v_str, "%d", d);
*str = v_str;
}
int main(void) {
char *result;
toString(&result, 50);
puts(result, stdout);
free(result);
return 0;
}
In this case, we pretend that the caller doesn't know how much memory is required for the result string, and let the toString function decide. It allocates as much memory as it needs for the conversion, then returns the allocated string. The caller needs to release that memory with free. Note that we've got to pass the address &result in this situation, so toString will write the pointer to the allocated string into our result variable. Double pointers like this can seem confusing to some people who are new to C, but it's conceptually similar to how you're passing a pointer to your float variable (float *fGross).
Personally, I prefer the first version when possible, because allocating memory on the stack avoids having to manage heap memory with malloc and free, a common source of memory leaks, especially for beginners. Of course, nothing prevents you from calling that version of toString with heap-allocated memory if you need to.
I'm a newbie to C. I had extended the question from the previous question: Strange behavior when returning "string" with C (Thanks for all who answered or commented that question, by the way.)
Pretty straight forward:
Why can this work:
#include <stdio.h>
int func() {
int i = 5;
return i;
}
int main() {
printf("%d",func());
}
But not this:
#include <stdio.h>
char * func() {
char c[] = "Hey there!";
return c;
}
int main() {
printf("%s",func());
}
From the previous question, logically the int i should not exist too because the function has returned, but why can it still be returned while char c[] cannot?
(It seems to be duplicated from "Pointers and memory scope" but I would like to know more about what is the difference between returning an int and a char *.)
Problem is not returning char *, it is returning something that is allocated on stack.
If you allocate memory for your string rather than pointing to function stack, there will be no problem. Something like this:
char * func() {
char c[] = "Hey there!";
return strdup(c);
}
int main() {
char* str = func();
printf("%s", str);
free(str);
}
It is important to mention that in both cases, you are copying a value and in both cases copied value is correct, but the meaning of copied value differs.
In first case, your are copying an int value and after your return from function, you are using that int value which will be valid. But in 2nd case, even though you have a valid pointer value, it refers to an invalid address of memory which is stack of called function.
Based on suggestions in comment, I decided to add another better practice in memory allocating for this code:
#define NULL (void*)0
int func(char *buf, int len) {
char c[] = "Hey there!";
int size = strlen(c) + 1;
if (len >= size) {
strcpy(buf, c);
}
return size;
}
int main() {
int size = func(NULL, 0);
char *buf = calloc(size, sizeof(*buf));
func(buf, size);
printf("%s", buf);
free(buf);
return 0;
}
Similar approach is used in a lot of windows API functions. This approach is better, because owner of pointer is more obvious (main in here).
In the first example the return value is copied. In your second example you're returning a pointer, which will point to a memory location which no longer exists.
In the first case, you return the int value 5 from the function. You can then print that value.
In the second case however, you return a value of type char *. That value points to an array that is local to the function func. After that function returns the array goes out of scope, so the pointer points to invalid memory.
The difference between these two cases is a value that you use directly, versus a pointer value that no longer points to valid memory. Had you returned a pointer to memory allocated by malloc, then the pointer would point to valid memory.
You are trying to return pointer to local array, which is very bad. If you want to return a pointer to array, allocate it dynamically using malloc inside your func();
Then you must call free() on caller side to free up memory you allocated when you no longer need it
In the first example, you return an int, and the second you return a pointer to a char. They both return in exactly the same manner, it is just a matter of understanding the stack and how values are returned.
Even though i was declared in the function and is allocated on the stack, when the function returns it returns the value of i (which is basically copied, so when i falls off the stack the value of i is still returned.)
This is the exact same thing that happens to the char * in the second example. It will still be a pointer to a char, and it returns the 'copied' value of c. However, since it was allocated on the stack, the address it points to is effectively invalid. The pointer value itself has not changed, but what it points to has.
You would have to dynamically allocate this to avoid this situation.
The return value of function is returned by copy. In the first example, you get a copy of the integer variable from the function. In the second you get a copy of the char pointer, not a copy of the string.
The pointer references the string data that has automatic storage, so is no longer valid after the function returns. The space becomes available for use by other code and many be modified - any attempt to access it has undefined behaviour.
The point is, it is a pointer that is returned, not a string; in C a strings (and more generally arrays) are not a first-class data types.
Depending on your needs there are a number of valid ways of returning the string data; for example the following is valid:
char* func()
{
static char c[] = "Hey there!";
return c;
}
because here although the local variable goes out of scope the static data is not destroyed or de-allocated, and any reference to it remains valid.
Another alternative is to embed the string in a struct which is a first-class data type:
typedef struct
{
char content[256] ;
} sString ;
sString func()
{
sString c = {"Hey there!"};
return c;
}
Or more conventionally to copy the data to a caller buffer:
char* func( char* buffer )
{
char c[] = "Hey there!";
strcpy( buffer, c ) ;
return buffer ;
}
I have omitted code to mitigate the possibility of buffer overrun above for clarity in this last example, such code is advised.
I used this code to print some string,but it does not print any thing.What is the problem?
char* getNotFilledEncryptionParams(void)
{
char* nofilledStr;
char tmp[3];
const char * arr[]= {" P,"," Q,"," A,"," B,"," C,"," R,"," S0,","S1,","S2,","F1,","G1"};
for(i=0;i<11;i++)
{
if(filledParams[i] == 0)
{
strcpy(tmp,arr[i]);
strcat(nofilledStr,tmp);
}
}
return nofilledStr;
}
Usage:
int main(void){
char *remaining;
remaining = getNotFilledEncryptionParams();
printf("\r\n Remaining item:%s",remaining);
}
I think the problem is in const char * arr[] and I changed it,but the problem remains.
You didn't allocate any memory for noFilledStr, so its value is indeterminate and strcat(noFilledStr, tmp) is undefined.
Use malloc to allocate memory and initialize noFilledStr with the returned pointer:
char* noFilledStr = malloc(number_of_bytes);
The strings in arr are char[4], not char[3] (do not forget the null byte!). tmp is too small to hold them, so strcpy(tmp, arr[i]) writes out of bounds.
You are trying to build the string to return in the location pointed to by nofilledStr but this pointer is pointing somewhere as you do not initialize it. You could use a sufficiently large static char[] array if you do not have to deal with multiple threads. Otherwise, use malloc() and require the caller to free() the returned string when he is done with it.
This is an absolutly noob question, but I don't seem to find an appropiate answer anywhere so here it goes, given this code:
#include <stdio.h>
#include <stdlib.h>
void initialize( char * buffer)
{
buffer = malloc(1);
*buffer='a';
}
int main(void) {
char * buff;
buff = malloc(sizeof(char));
*buff = 'b';
initialize(buff);
puts("Contents of buffer are: ");
puts(buff);
return 0;
}
The output of main is always 'b', which is really weird to me. I thought that by passing a pointer to initialize I could modify the value of the pointer declared in main, but for some reason it seems to be passing the variable by value, and when returning I have the values specified in main, thus 'b'.
I would like to know why is this...should I pass a reference to a pointer instead? something like char *& ??
Regards,
Alex
The first thing you do in your function it to reassign another place in the memory to buffer with a new malloc. Then you modify this new memory location, but buff in the main function isn't modified, since it's still pointing on the old location.
If you remove the malloc, it will work :
void initialize( char * buffer) {
*buffer='a';
}
Now we are modifying the initial memory location.
In case a bug-free snippet without memory leaks is preferred, here are some alternatives to what has already been posted, more applicable to programming in the real world.
Note that the same "code module" that mallocs should also free. Do not malloc in one module and free in another, that is very bad practice!
Version 1:
#include <stdio.h>
#include <stdlib.h>
void set (char* buffer)
{
*buffer='a';
}
int main (void)
{
char* buff;
buff = malloc(sizeof(char)); /* main allocates */
*buff = 'b';
set (buff);
puts("Contents of buffer are: ");
printf("%c", *buff); /* don't use puts on single characters! */
free(buff); /* main cleans up its own mess */
return 0;
}
Version 2:
/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "my_functions.h"
int main (void)
{
char * buff;
buff = malloc(sizeof(char));
*buff = 'b';
alloc_and_set (&buff);
puts("Contents of buffer are: ");
printf("%c", *buff);
cleanup();
return 0;
}
my_functions.h
#ifndef MY_FUNCTIONS_H
#define MY_FUNCTIONS_H
void alloc_and_set (char** buffer);
void cleanup (void);
#endif /* MY_FUNCTIONS_H */
my_functions.c
#include "my_functions.h"
static char* internal_buffer = NULL; /* used to keep track of allocated data */
void alloc_and_set (char** buffer)
{
if(internal_buffer == NULL) /* make function memory leak proof */
{
internal_buffer = malloc(sizeof(char));
}
*internal_buffer = 'a';
*buffer = internal_buffer;
}
void cleanup (void)
{
free(internal_buffer); /* my_functions module cleans up its own mess */
internal_buffer = NULL;
}
You need to modify your initialize() function to take a pointer to your buffer and pass in the address of the pointer. Although it receives the buffer you pass in, you cannot change what buff is pointing to that way. Just be aware that you will have a memory leak in this case and you cannot print the contents as a string as it isn't properly null terminated.
void initialize(char **buffer)
{
*buffer = malloc(sizeof(char));
**buffer='a';
}
int main(void) {
char *buff;
buff = malloc(sizeof(char));
*buff = 'b';
initialize(&buff);
puts("Contents of buffer are: ");
printf("%c\n", *buff);
return 0;
}
Answers to the comments below:
I don't get why a need a pointer to a pointer still...is this like a reference in C++?
When I read your code, I thought that you wanted to change what the buff variable (in main()) was pointing to, a new buffer. I thought that when I saw that you were allocating a new buffer in your initialize() function. To be able to change a value of a variable from a different location (or function), you'd need the address to that variable. Since it was originally a character pointer char *, you would have needed a pointer to that character pointer, char **. And yes, this is like a reference in C++, only more verbose.
So I can modify the value of the passed variable?
If you had intended to just modify the contents of the buffer that was passed in, Krtek covers that. All you needed to do was leave out the new allocation of the buffer and modify what the buffer was pointing to.
void initialize(char *buffer)
{
/* *buffer = malloc(sizeof(char)); */ /* do not need this */
/* modify the buffer that was passed in */
*buffer='a';
}
Regarding the memory leak problem
Actually, the memory leak was caused by allocating a new buffer while not freeing the previously allocated memory. You effectively had this:
char *buff = malloc(sizeof(char)); /* allocate some memory */
buff = malloc(sizeof(char)); /* oops, memory leak */
you mean using puts with a non-null terminated string? Is this why you are using printf("%c\n", *buff)? forcing the string to end with \n?
This was a different issue here. puts() takes a null-terminated string and prints it to standard output followed by a new line. It wouldn't be a memory leak to print potentially garbage text, it's just... something else. Your buffer only contained space for a single character (without the null-terminator). You therefore shouldn't use puts() to print the contents of the buffer. You should only be printing that single character. The use of printf() with the '\n' was to end up with the same output behavior as puts().
You modified the copy of your pointer to point in another place, but your real pointer doesn't point to it.
If you wan't your code to work use this function.
void initialize( char ** buffer)
{
*buffer = malloc(1);
**buffer='a';
}
then call initialize(&buff);
When you do this
buffer = malloc(1);
The buffer variable passed originally from main is unaffected as it has been passed by value.
If you write this:
void initialize( char **buffer)
{
*buffer = malloc(1);
**buffer='a';
}
Then you will see the change.
Edit1: You need to understand * operator. buffer is a pointer in itself. *buffer is actually the location pointed to by buffer and changing it doesn't affect buffer actually.
void initialize( char * buffer)
{
// buffer is a local pointer to this function which will have
// same value as buff in main AT THIS POINT.
// now you call malloc to allocate memory and make buffer
// point to that memory. So the value of buffer got changed now.
// buff in main remains unchanges.
buffer = malloc(1);
// now you write to the memory allocated.
*buffer='a';
// key point is buff in main is still pointing where it was.
}
int main(void) {
// buff is now a wild pointer.
char * buff;
// now you allocate memory using malloc and make buff point to that memory.
buff = malloc(sizeof(char));
// you write to the memory pointed to by buff.
*buff = 'b';
// you pass buff BY VALUE to the function initilize.
initialize(buff);
// since a copy of buff (buffer) was changed, buff still points
// to a memory that has b in it.
puts("Contents of buffer are: ");
puts(buff);
return 0;
}
If you want the called function to affect the value of buff you need to pass its address:
void initialize( char ** buffer)
{
*buffer = malloc(1);
**buffer='a';
}
and call it as:
initialize(&buff);
but note that this will leak the memory allocated in main. Since you've already allocated memory in main you can just remove the malloc:
void initialize( char * buffer)
{
*buffer='a';
}
this doesn't work:
void function(char* var)
{
var = (char*) malloc (100);
}
int main()
{
char* str;
function(str);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
this does:
void function(char* var)
{
//var = (char*) malloc (100);
}
int main()
{
char* str;
//function(str);
str = (char*) malloc (100);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
Why?
You have to pass the address of the pointer to assign the address you want inside the function, otherwise you are just passing a copy of it:
void function(char** var)
{
*var = malloc (100);
}
int main()
{
char* str;
function(&str);
strcpy(str, "some random string");
printf("%s\n", str);
return 0;
}
You need to use a pointer to pointer as a parameter for that, char **.
When you pass a pointer as a parameter, it gets copied, so what you get inside the function is just another pointer pointing to the same place.
You need to receive a char ** and do:
my_alloc_fun(void **ptr){
*ptr= malloc(size);
}
void *myptr;
my_alloc_fun(&myptr);
This way, you get the address of the pointer inside the function, so that you can make the original pointer to point to the newly allocated memory.
When you call function(str), you are passing the value of str to function. This value is some uninitialized garbage value because you haven't set it to anything in main, but that's not the problem.
The problem is that function has its own pointer, var, into which it puts that garbage value so that one could say var points to the same thing (garbage) that str points to. However, they are not the same variable. They are two distinct variables, and changing var has no effect on str.
When you say var = (char*) malloc (100);, you are allocating memory somewhere and then telling var to point to it. Now var points to a different location than str. Immediately you return from that function, losing var and the location of that memory. This by the way is a memory leak.
When you return back to main, str is as it ever was - pointing to garbage.
A numerical example:
char *str; // str -> 0xfeedface (garbage)
function(str);
// inside 'function', an initialization like this occurs
char *var = str; // var -> 0xfeedface (same garbage)
var = (char*) malloc (100); // var -> 0x12341234 (alloc'd memory)
return;
// back in 'main'
strcpy(str, "some random string"); // str still points to 0xfeedface!
To do this properly, you need to change strs value. This means function needs a pointer to str, or a pointer to a pointer.
void function(char **var)
{
*var = (char*)malloc(sizeof(char) * 100);
}
int main()
{
char *str;
function(&str);
strncpy(str, "some random string", 99);
...
free(str); // important in general
}
Pointers are just like any other variable; the difference is only in what their value represents. Whereas a double has a value that represents a double-precision floating point number, and an int has a value that represents a signed integer, a pointer has a value that represents the location of another variable.
Pointers themselves are still passed by-value to other functions; so your example doesn't work for exactly the same reason that this analagous function doesn't work:
void function(int var)
{
var = 100;
}
int main()
{
int num;
function(num);
printf("%d\n", num);
return 0;
}
The answer in both cases is the same: When function() changes the value of the parameter var, it is changing only its local copy of that - it isn't changing the variable within main().
See my answer to C Programming: malloc() inside another function for an explanation about how to think about this.