malloc'd pointer resetting itself to NULL? - c

I am getting some pretty strange behavior using malloc. I am never allocating more than 4kB, so this seems especially strange to me. My main looks something like:
int main(int argc, char **argv)
{
char *buf;
char *raw = malloc(1024);
fgets(raw, 1024, stdin);
parse(raw, &buf); // Process raw input, get parse length
printf("raw: 0x%p\n", raw); // Outputs 0x00000000
if(raw != NULL)
{ // Only prints when less than 10 characters are entered
free(raw);
printf("raw is not NULL\n");
}
free(buf);
return 0;
}
When I enter less than 10 characters this works okay, when I enter exactly 10 characters I get a segmentation fault, and when I enter more than 10 the output shows that raw is NULL. It should be noted that the size of raw is 1024 malloc'd bytes, so I should have more room to work with.
The parse function is:
int parse(char *src, char **dst)
{
int num_valid = 0, len = strlen(src), j = 0;
// Count number of valid characters
for(int i = 0; i < len; i++)
{
if(src[i] == 'A')
++num_valid;
}
*dst = malloc(num_valid);
for(int i = 0; i < len; i++)
{
if(src[i] == 'A')
*dst[j++] = src[i];
}
// For debugging:
printf("src: 0x%p\n", src); // outputs correct address
return num_valid;
}
This function outputs the correct address, and properly allocates and fills dst. I modified the code here slightly, this is basically a very reduced form of my code. I compiled and ran it (gcc test.c -Werror -Wall) with the same results. It is only after this function returns that my raw pointer becomes NULL, or I get a segfault.
Can someone point me in the right direction? Tell me what exactly I am doing wrong? I've been debugging this little piece of code since yesterday and it is driving me mad.

This doesn't mean what you think it means:
*dst[j++] = src[i];
You meant
(*dst)[j++] = src[i];
What you wrote means:
*(dst[j++]) = src[i];
dst[1] is whatever happens to follow the variable buf, so you're using an address from a random memory location and overwriting whatever it might point to; that's undefined behaviour.
As #pm100 points out in a comment, keeping the buffer in a temporary variable is generally better style:
char* buf = malloc(num_valid);
if (!buf) { /* Handle allocation failure */ }
*dst = buf;
/* ... */
/* In loop */
buf[j++] = src[i];

Related

Manipulation array in function - c - Segmentation fault

So I started to learn how to code a few weeks ago, and this site helped me so much, thank you for that. But this time I got stuck and can´t really figure out why...Hope you can help me.
Basically I have a function prototype I have to use in my program and I have my troubles with it. The function should receive a string and then only copy every second char of that string and return the result...
This is what I've got so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define max_size 1000
char * everySecondChar(char * dest, char * input);
int main() {
char inputstr[max_size] = {0};
char *input[max_size] = {0};
char *dest[max_size] = {0};
char temp[max_size] = {0};
int i = 0;
while (fgets(inputstr, max_size, stdin) != NULL)
{
input[i] = strndup(inputstr, max_size);
strcat(temp,inputstr);
i++;
}
input[0] = strndup(temp, max_size);
printf("Inputted text:\n%s", *input);
printf("\n");
printf("\n");
printf("Resulting string:\n");
everySecondChar(*dest, *input);
printf("%s", *dest);
return 0;
}
char * everySecondChar(char * dest, char * input)
{
int i = 0;
for(i = 0; i < max_size; i+=2) {
strcat(dest,input);
}
return dest;
}
I know this is probably a 1-min challenge for the most of you, but I am having my troubles whenever I see those nasty * in a function prototype :(
Congrats on getting started with programming!
To your question: there's quite a few things that could be addressed, but since there seems to be some more basic confusion and misunderstanding, I'll address what makes sense given the context of your issue.
First, you're using strcat which concatenates strings (e.g. adds to the string), when you just need simple character assignment.
Next, you have a lot of pointers to arrays and there seems to be some confusion regarding pointers; in your main function, you don't need all of the temporary variables to do what you're wanting.
You could have simply:
char inputstr[MAX_SIZE] = {0};
char dest[MAX_SIZE] = {0};
You could have less (realistically) but we'll stick with the basics for now.
Next, you're looping to get user input:
while (fgets(inputstr, max_size, stdin) != NULL)
{
input[i] = strndup(inputstr, max_size);
strcat(temp,inputstr);
i++;
}
Here, you don't check if i exceeds max_size which your input variable has been allocated for; if i exceeds max_size when you go to assign input[i] to the memory location returned by strndup (which calls malloc), you are writing beyond your memory bounds, which is also known as a buffer overflow. This is potentially where your segmentation fault is happening. You could also have some issues when you do strcat(temp,inputstr); since strcat:
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
If you're simply just trying to get what the user entered, and print every 2nd character with your function, you don't need to loop:
if (fgets(inputstr, MAX_SIZE, stdin) != NULL) {
everySecondChar(dest, inputstr);
printf("Inputted text:\n%s\n\nResulting string:\n%s\n", inputstr, dest);
}
Lastly, in your everySecondChar function, you're using strcat again when all you need to do is simple assignment (which does a 'copy'):
char * everySecondChar(char * dest, char * input)
{
int i, j;
for(i = 0, j = 0; i < MAX_SIZE; ++i, ++j) {
if (input[i] == 0) break; // end if string?
dest[j] = input[i++];
}
return dest;
}
Putting all of it together, you get:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 1000
char * everySecondChar(char * dest, char * input);
int main(void)
{
char inputstr[MAX_SIZE] = {0};
char dest[MAX_SIZE] = {0};
printf("Enter some text: ");
if (fgets(inputstr, MAX_SIZE, stdin) != NULL) {
everySecondChar(dest, inputstr);
printf("Inputted text:\n%s\n\nResulting string:\n%s\n", inputstr, dest);
}
return 0;
}
char * everySecondChar(char * dest, char * input)
{
int i, j;
for(i = 0, j = 0; i < MAX_SIZE; ++i, ++j) {
if (input[i] == 0) break; // end if string?
dest[j] = input[i++];
}
return dest;
}
That aside, I'll address some other things; typically if you have a constant value, like your max_size variable, it's considered "best practice" to capitalize the entire thing:
`#define MAX_SIZE 1000`
I am having my troubles whenever I see those nasty * in a function prototype :(
Those nasty *'s in your function prototype (and variable declarations) are known as a pointer qualifier; it indicates that the type of the variable is a pointer to the type specified. A pointer isn't something to be scared of, you're learning C, it's highly important you understand what a pointer is and it's utility.
I won't dive into all of the specificities of pointers, aliases, etc. etc. since that is beyond the scope of this Q&A, but WikiBooks has a great intro and explanation covering a lot of those concepts.
Hope that can help!

Char* returns garbage value after malloc?

this function ideally takes a string and returns the letters past the first word (or "command") based on an integer. I.e:
input: "write 1234" //valLen = 4 and inputStr = "write 1234"
output: "1234"
"Extractor Function":
char* ExtractValue(unsigned int *valLen, char *inputStr)
{
int sizeToAllocate = strlen(inputStr) - (strlen(inputStr) - *valLen) + 1;
unsigned int i = 0;
int count = 0;
/* memory aloc */
printf("Assigning %d bits of space...\n", sizeToAllocate);
char *outStr = (char*)malloc(sizeToAllocate);
if (!outStr)
{
perror("Error allocating memory");
abort();
}
/*sets final string to value entered*/
for (i = 0; i < strlen(inputStr); i++)
{
if (strlen(inputStr) - i <= *valLen)
{
outStr[count] = inputStr[i];
count++;
}
}
return outStr;
}
And it works for the most part; however, the return string is always proceeded by garbage values for some reason. It seems as if malloc() initializes outstr to already used memory (with a bunch of gibberish in it) and the for loop adds characters to the beginning of it. An example would be:
input: "write 1234"
output: "1234══²²²²¼"
Why would it do that? Any explanations greatly appreciated, thanks!
You answered your own question already! malloc just allocates memory and doesn't bother clearing out whatever was there before. You can use calloc to get a block of memory that's been zeroed out, or modify your loop to add a null character at the end of the string.
/*sets final string to value entered*/
for (i = 0; i < strlen(inputStr); i++)
{
if (strlen(inputStr) - i <= *valLen)
{
outStr[count] = inputStr[i];
count++;
}
}
/* null terminate the string */
outStr[count++] = "\0";

Trouble while reading from socket

I am trying to read characters from a socket; here is the function I created for this, largely inspired from Here, where I remove some unrelevant parts here (this sample is compiling correctly).
int process(int socketfd, void *buffer, int n)
{
int totread = 0;
char ch;
int numread;
for(;;)
{
numread = read(socketfd, &ch, 1);
if(numread == 0) {
if (totread == 0) {
return 0;
} else {
break;
}
} else {
if(totread < n-1) {
totread++;
printf("totread: %d\n", totread);
printf("Here is OK, ch value gets printed %c\n", ch);
*buffer++ = ch;
printf("With help provided, this line gets printed\n");
printf("But the value <%s> of buffer, is blank (<> output)\n, buffer);
}
if (ch == '\n') {
printf("%c\n", ch);
printf("%s\n", buffer);
break;
}
}
}
return totread;
}
I can't understand why the second line does not get printed.
Obviously, the *buf++ = ch instruction is faulty; But it looks like correct. It simply affects the character read to the next value of the array of characters buf. I don't see errors or warnings at compile time, the client disconnects after the first line gets printed, and the second one is not reached.
EDIT
Here is how I initialize my buffer:
char *buffer = "";
int l = process(newsockfd, buffer, 100);
printf("Number read (function network) %d\n", l);
This is probably not the appropriate way to do it; I have also tried specifying a fixed length such as char buffer = [255]; The function does not exit then but nothing get printed. I'm quite a newbie in C programming, many thanks for your help!
int process(..., void * b, ...
{
...
*b++ = ...
Dereferencing and/or incrementing a void-pointer is not valid C. The compiler should have at least warned you about this.
Recompile your code with all warnings on (for gcc pass the options -Wall -Wextra -pedantic for this). Then fix the code until no more warning are issued.
Referring your edit on how the function in question is called:
This
char *buffer = "";
does not declare a buffer, but just a pointer. This pointer points to a string literal of size 1. String literals a constant by definition.
To summarise: You provide to your process()-function a pointer to constant memory of size 1.
Issues with this:
You cannnot read into constant memory.
An even if 1. would not apply you could only read in 1 byte.
To fix this change the code as follows:
char buffer[100] = ""; /* Define a buffer of 100 characters size and
initialise it to all `0`s. */
int l = process(newsockfd, buffer, 100);
As per process() blocking, you need to look at the read() function: If it gets called but the sender does not send anything it simply does not return as long as the connection is still up.
And: Make process() handle the value passed in as n.
Try changing the first line to
char *buf = (char *) buffer;
and compile using gcc with -Werror on

Modify pointer value in Linux kernel

Firstly, I've create a simple program in C
unsigned char * text ="Test program";
int _size = strlen(text);
unsigned char * str = malloc(sizeof(text));
memcpy(str, text, _size);
printf("Before(%d): %s\n", _size, str);
for(i=0;i < _size; i++) {
str[i] -= 13; //rot13
}
printf("After: (%d): %s\n", strlen(str), str);
It runs properly. However, when I move this code to Linux kernel, it seems to fail to work
unsigned char * str;
len = min(count, log->size - read->off);
/* Allocate the memory for storing plain text */
str = kmalloc(len, GFP_KERNEL);
if(str == NULL) {
printk(KERN_ERR "logger: failed to allocate buffer\n");
return -ENOMEM;
}
memcpy(str, log->buf + read->off, len);
/* Start: Add a simple rot13 encryption here */
for(i=0;i < strlen(str); i++)
str[i] -= 13; //rot13
/* End: Add a simple rot13 encryption here */
if (copy_to_user(buf, str, len))
return -EFAULT;
if(str != NULL) {
kfree(str);
}
The problem comes from following code
for(i=0;i < strlen(str); i++)
str[i] -= 13; //rot13
Because if it's removed, program runs as original case. Did I miss something here?
The problem: sizeof(text) returns the size of the pointer, and not the length of the string text points to. Also remember that all string have an extra character that terminates the string. This all means that you write to, and read from, beyond the memory you allocated, and that is undefined behavior which means anything could happen.
Also, literal strings are actually constant (const char *).
And lastly, you might want to read about ROT13, as what you're doing is not ROT13 encryption.
You haven't terminated str with a '\0' so you're most likely just running off the end of the buffer and stomping over memory.
Change:
str = kmalloc(len, GFP_KERNEL);
to:
str = kmalloc(len + 1, GFP_KERNEL); // allocate additional char for terminator
and change:
memcpy(str, log->buf + read->off, len);
to:
memcpy(str, log->buf + read->off, len);
str[len] = '\0'; // put terminator at end of string
If you are dealing with strings try using strncpy() instead of memcpy. 'coz that will put a NULL char at the end automatically and you are safe from buffer over runs. But in this case, i'm not very sure what exactly is the problem, unless you give more details about the issue.
And for any kernel programming errors, the key is to add debugs/printks and collect as much as data about what is happening. If thats not helping you debug yourself, that will help others to help you better.

Why am I getting a segmentation fault?

I'm trying to write a program that takes in a plaintext file as it's argument and parses through it, adding all the numbers together and then print out the sum. The following is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static int sumNumbers(char filename[])
{
int sum = 0;
FILE *file = fopen(filename, "r");
char *str;
while (fgets(str, sizeof BUFSIZ, file))
{
while (*str != '\0')
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
str++;
}
}
fclose(file);
return sum;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Please enter the filename as the argument.\n");
exit(EXIT_FAILURE);
}
else
{
printf("The sum of all the numbers in the file is : %d\n", sumNumbers(argv[1]));
exit(EXIT_SUCCESS);
}
return 0;
}
And the text file I'm using is:
This a rather boring text file with
some random numbers scattered
throughout it.
Here is one: 87 and here is another: 3
and finally two last numbers: 12
19381. Done. Phew.
When I compile and try to run it, I get a segmentation fault.
You've not allocated space for the buffer.The pointer str is just a dangling pointer. So your program effectively dumps the data read from the file into memory location which you don't own, leading to the segmentation fault.
You need:
char *str;
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it.
or just:
char str[BUFSIZ]; // but then you can't do str++, you'll have to use another
// pointer say char *ptr = str; and use it in place of str.
EDIT:
There is another bug in:
while (fgets(str, sizeof BUFSIZ, file))
The 2nd argument should be BUFSIZ not sizeof BUFSIZ.
Why?
Because the 2nd argument is the maximum number of characters to be read into the buffer including the null-character. Since sizeof BUFSIZ is 4 you can read max upto 3 char into the buffer. That is reason why 19381 was being read as 193 and then 81<space>.
You haven't allocated any memory to populate str. fgets takes as its first argument a buffer, not an unassigned pointer.
Instead of char *str; you need to define a reasonably sized buffer, say, char str[BUFSIZ];
Because you've not allocated space for your buffer.
A number of people have already addressed the problem you asked about, but I've got a question in return. What exactly do you think this accomplishes:
if (isdigit(*str))
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
}
What's supposed to be the point of two successive if statements with the exact same condition? (Note for the record: neither one has an else clause).
You have declared char* str, but you have not set aside memory for it just yet. You will need to malloc memory for it.
Many memory related errors such as this one can be easily found with valgrind. I'd highly recommend using it as a debugging tool.
char *str;
str has no memory allocated for it. Either use malloc() to allocate some memory for it, or declared it with a predefined size.
char str[MAX_SIZE];
Your program has several bugs:
It does not handle long lines correctly. When you read a buffer of some size it may happen that some number starts at the end of the buffer and continues at the beginning of the next buffer. For example, if you have a buffer of size 4, there might be the input The |numb|er 1|2345| is |larg|e., where the vertical lines indicate the buffer's contents. You would then count the 1 and the 2345 separately.
It calls isdigit with a char as argument. As soon as you read any "large" character (greater than SCHAR_MAX) the behavior is undefined. Your program might crash or produce incorrect results or do whatever it wants to do. To fix this, you must first cast the value to an unsigned char, for example isdigit((unsigned char) *str). Or, as in my code, you can feed it the value from the fgetc function, which is guaranteed to be a valid argument for isdigit.
You use a function that requires a buffer (fgets) but you fail to allocate the buffer. As others noted, the easiest way to get a buffer is to declare a local variable char buffer[BUFSIZ].
You use the str variable for two purposes: To hold the address of the buffer (which should remain constant over the whole execution time) and the pointer for analyzing the text (which changes during the execution). Make these two variables. I would call them buffer and p (short for pointer).
Here is my code:
#include <ctype.h>
#include <stdio.h>
static int sumNumbers(const char *filename)
{
int sum, num, c;
FILE *f;
if ((f = fopen(filename, "r")) == NULL) {
/* TODO: insert error handling here. */
}
sum = 0;
num = 0;
while ((c = fgetc(f)) != EOF) {
if (isdigit(c)) {
num = 10 * num + (c - '0');
} else if (num != 0) {
sum += num;
num = 0;
}
}
if (fclose(f) != 0) {
/* TODO: insert error handling here. */
}
return sum;
}
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++)
printf("%d\t%s\n", sumNumbers(argv[i]), argv[i]);
return 0;
}
Here is a function, that does your job:
static int sumNumbers(char* filename) {
int sum = 0;
FILE *file = fopen(filename, "r");
char buf[BUFSIZ], *str;
while (fgets(buf, BUFSIZ, file))
{
str=buf;
while (*str)
{
if (isdigit(*str))
{
sum += strtol(str, &str, 10);
}
str++;
}
}
fclose(file);
return sum;
}
This doesn't includes error handling, but works quite well. For your file, output will be
The sum of all the numbers in the file is : 19483

Resources