C—segfault when modifying data - c

Relating to an earlier question I had about displaying the contents of specific data addresses, I'm now trying to modify the contents of individual addresses. It seems like a simple enough task, but I get a segfault every time I try. I'm using the following function:
int mem_set(Cmd *cp, char *arguments)
{
int address = 0, value = 0;
char *location;
if(sscanf(arguments, "%x %x", &address, &value) == 2)
{
location = (char*)address;
*location = value;
}
else printf("Invalid input.\n");
return 0;
}
I'm supposed to be able to change an item in a table (in this very file) from 's' to 'x' by finding its address and replacing it with the proper hex value, but I get a segfault when it gets to *location = value;. Any ideas?
Thanks!

You are assigning an integer to a pointer here
location = (char*)address;
it should be
location = (char*)&address;
you need to take the address of address isntead of it's value.
Whether this will do what you are trying to do, is something else, but this is the reason your program is invoking undefined behavior, which might lead to a SEGMENTATION FAULT.

Related

Why does a function share the same struct instance?

The user specifies the number of lines in the output in the arguments (as the size of the page in pagination), by pressing the key he gets the next lines. How it works now:
Let's say the user chose to receive 1 row at a time:
first string
first string
second string
first string
second string
third string
struct result {
char part[32768];
int is_end_of_file;
};
struct result readLines(int count) {
int lines_readed = 0;
struct result r;
if (count == 0) {
count = -1;
}
while (count != lines_readed) {
while (1) {
char sym[1];
sym[0] = (char) fgetc(file);
if (feof(file)) {
r.is_end_of_file = 1;
return r;
}
strcat(r.part, sym);
if (*"\n" == sym[0]) {
break;
}
}
lines_readed++;
}
return r;
}
int main(int argc, char *argv[]) {
file = fopen(argv[1], "r");
while (1) {
struct result res = readLines(atoi(argv[2]));
printf("%s", res.part);
if (res.is_end_of_file) {
printf("\nEnd of file!\n");
break;
}
getc(stdin);
}
closeFile();
return 0;
}
I know that when I define a struct in the readLines function, it is already filled with previous data. Forgive me if this is a dumb question, I'm a complete newbie to C.
I'm not sure what is the question here, however I'll do my best to address what I understand. I assume the problem lies somewhere around the "previous data" you mentioned in the title and in the comments to the question.
Let's first set an example program:
#include <stdio.h>
struct result {
char part[10];
};
int main (int argc, char *argv[]) {
struct result r;
printf(r.part);
return 0;
}
The variable r has a block scope, so it has automatic storage duration. Since it has automatic storage duration, and no initializer is provided, it is initialized to an indeterminate value (as mentioned by UnholySheep and n. 1.8e9-where's-my-share m. in the comments to the question). I don't yet get all the C intricacies, but based on this, I guess you cannot rely on what the value of r will be.
Now, in the comments to the question you try to understand how is it possible that you can access some data that was not written by the current invokation of your program. I cannot tell you exactly how is that possible, but I suspect it is rather platform-specific than C-specific. Maybe the following will help you:
What is Indeterminate value?
What happens to memory after free()?
Why memory isn't zero out from malloc?
Going further, in the line
printf(r.part);
first we try to access a member part of r, and then we call printf with the value of this member. Accessing a variable of an indeterminate value results in undefined behavior, according to this. So, in general, you cannot rely also on anything that happens after invoking r.part (it doesn't mean there is no way of knowing what will happen).
There is also another problem with this code. printf's first parameter is interpreted as having the type const char *, according to man 3 printf, but there is provided a variable that has the type struct result. Indeed, there is produced the following warning when the code is compiled with gcc with the option -Wformat-security:
warning: format not a string literal and no format arguments [-Wformat-security]
Unfortunately, I don't know C well enough to tell you what precisely is happening when you do such type mismatch in a function call. But as we know that there already happened undefined behavior in the code, this seems less important.
As a side note, a correct invokation of printf could be in this case:
printf("%p", (void *)r.part);
r.part is a pointer, therefore I use the %p conversion specifier, and cast the value to (void *).

Segmentation fault: 11 when trying to perform char[] lookup in C

char getType()
{
typedef struct typelookup { const char *opcodebits; char instype; } typelookup;
typelookup table[] = {
{"000000",'r'},
{"000010",'j'},
{"000011",'j'},
{ NULL }
};
for (typelookup *t = table; t->opcodebits != NULL; ++t) {
if (strcmp(t->opcodebits, opcode) == 0) {
return t->instype;
}
}
return 'i';
}
I need to be able to perform a lookup based on a string. The string is contained in a static array and if the string is in the lookup table, I want to be able to return a character which will define which type of MIPS instruction the binary refers to, hence the r, j and i as return values. This code compiles ok but when it comes to running the code I always get a "segmentation error: 11". Can anybody enlighten me as to what I'm doing wrong? Been trying to fix this error for longer than I care to admit.
What is opcode? Does the char array pointed to by opcode contain a terminating zero? If not, strcmp may keep comparing beyond the end of t->opcodebits, run out of bounds, and suddenly hit a non-readable virtual address.
I apologise for my answer sounding like a lot of additional questions. :-)

Segmentation fault on malloc

After running this function many (not sure exactly how many) times, it seg faults on a simple memory allocation. Why would this suddenly happen? I did notice something strange in GDB. In the function that calls it, normally there's 6-digit long hex value for wrd (wrd = 0x605140 for example), however on the call where it crashes, the hex value is only two digits long. (wrd=0x21). I also checked the wrd->length, and it's 3.
The line that it crashes on is...
char *word_temp = malloc(wrd->length * sizeof(char));
EDIT:
Here's the code that creates the wrd...
while(fgets(input, 100, src) != 0)
{
int i = 0;
while(input[i] != '\0')
{
i++;
}
struct word *wrd = malloc(sizeof(struct word));
wrd->letters = input;
wrd->length = i;
If I'm getting an overflow, how do I fix that?
Looks like wrd->length does not include the terminating '\0'.
Fix 1, allocate word_temp like this:
char *word_temp = malloc( wrd->length + 1 );
Fix 2, include the '\0' by modifying you length count loop:
int i = 0;
while(input[i++] != '\0') {}
This will increase i one more time than code in the question, which is easy to see if you consider case of input being empty.
Note that you need to do either fix 1 or fix 2, not both. Choose which ever works with rest of your code.
You probably have a second issue with this line:
wrd->letters = input;
It does not copy input, it copies the pointer. If you change contents of input, contents of wrd->letters changes too, because they point to same memory location. Also if input is a local char array, then once it goes out of scope, wrd->letters becomes a dangling pointer, which will be overwritten by other data, and modifying it after that will result in memory corruption.
Possible fix (depending on rest of your code) is to use strdup:
wrd->letters = strdup(input);
Remember that it is now allocated from heap, so when done, you must remember to do
free(wrd->letters);
About wrd being 0x21, that indicates either memory corruption, or that you actually have two separate wrd variables, and one one is left uninitialized.
For example, maybe wrd is a function parameter struct word *wrd, in which case you only modify the local value in function, it does not get passed back to the caller. To modify the pointer of caller, you need to have pointer to pointer: struct word **wrd and then do (*wrd) = malloc... and (*wrd)->letters... etc.

List to list assignment becomes garbage

I'm having some trouble with the following:
void BuildList(cs460hwp hw)
{
FILE* fp;
fp = fopen("HW2input.dat", "r");
if(fp == NULL)
{
printf("Couldn't open the file.");
return;
}
int numStudents;
int i;
bool success;
char* dueDate = malloc(9*sizeof(char));
char* course = malloc(7*sizeof(char));
char* wsuid = malloc(9*sizeof(char));
char* subDate = malloc(9*sizeof(char));
double points1 = 0;
double points2 = 0;
cs460hwp stuInsert = NULL;
fscanf(fp, "%d", &numStudents);
fscanf(fp, "%s", dueDate);
for(i = 0; i < numStudents; i++)
{
stuInsert = malloc(sizeof(cs460hwp));
fscanf(fp, "%s %s %s %lf", course, wsuid, subDate, &points1);
strcpy(stuInsert->course, course);
strcpy(stuInsert->wsuid, wsuid);
strcpy(stuInsert->subdate, subDate);
stuInsert->points1 = points1;
stuInsert->points2 = CalculatePoints(dueDate, subDate, points1);
stuInsert->nextPtr = NULL;
if(hw == NULL)
{
hw = stuInsert;
}
else
{
stuInsert->nextPtr = hw;
hw = stuInsert;
}
}
free(course);
free(wsuid);
free(subDate);
free(dueDate);
PrintGrades(hw);
fclose(fp);
}
struct hwpoints
{
char course[7];
char wsuid[9];
char subdate[9];
double points1;
double points2;
struct hwpoints *nextPtr;
};
typedef struct hwpoints *cs460hwp;
My goal here is to insert every entry to the top of the list. However, whenever I try to assign anything to nextPtr (such as in the else clause), it gets filled with garbage values. They're mostly truncated versions of old data, which leads me to believe they're being taken from the heap. I've been reading (a lot), but I'm having trouble finding advice on this particular problem.
nextPtr always becomes junk, and nextPtr->nextPtr causes a segfault. For every iteration of the loop. hw remains fine, but its pointer value never gets updated properly.
Even when I've attempted to move the memory allocation for the struct into a function, I've had the same (or similar) issues.
Can anyone point me in the right direction?
Two problems.
1) As pb2q mentioned, you are passing a pointer to a struct and trying to assign what the arg points to. That's allowed by the compiler, but it doesn't do anything for you outside the function. It might be OK in your case if:
void main()
{
cs460hwp hw = NULL;
BuildList(hw);
return;
}
Is the whole of your function. I don't know the assignment so you need to figure out if that's acceptable to you or not.
2) The much bigger problem:
stuInsert = malloc(sizeof(cs460hwp));
Did you check what sizeof(cs460hwp) comes out to be? it's 4. You're allocating enough memory for the size of a pointer, not the size of your structure. I'm pretty sure this is not what you want to do and this is what is killing you. Just for kicks, replace it with malloc(100) and see if your problem goes away. If so you just need to figure out what size you really want. ;)
A problem with your BuildList function is that you're passing a pointer to a struct hwpoints, and you're trying to re-assign what the argument points to. Since function arguments in C are pass-by-value you're only changing the copy of the pointer that your function receives, and those changes won't be reflected in the caller.
You can use this pointer to modify the contents of the list: you can change e.g. hw->course or hw->nextPtr, you can move elements around in your list. But you can't change what the head, hw points to, so you can't insert elements at the beginning of the list.
If you want to change your head pointer, as in these statements:
hw = stuInsert;
// ...
hw = stuInsert;
Then you'll need to pass a pointer to the pointer:
void BuildList(cs460hwp *hw)
And de-reference it as necessary in the body of the function.
I can't be sure that this is the cause of the output that you're observing, which may be due to other problems. But if, after some number of calls to BuildList, beginning with a head pointer equal to NULL, you're trying to print your list assuming that it has valid nodes, you could see garbage data.
Thanks to #Mike's answer, we see also that you're not allocating enough space for your list nodes:
stuInsert = malloc(sizeof(cs460hwp));
Will only allocate enough space for a pointer, since cs460hwp is typedef'd to be a pointer to struct hwpoints. You need to allocate enough space for the structure, not a pointer to it:
stuInsert = malloc(sizeof(struct hwpoints));

C: Passing a variable to a function gives wrong return

I am using some C with an embedded device and currently testing some code to read file details from an SD card. I am using a proprietary API but I will try to remove that wherever possible.
Rather than explaining, I will try to let me code speak for itself:
char* getImage() {
int numFiles = //number of files on SD card
for(int i=0; i<numFiles;i++) {
\\lists the first file name in root of SD
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
return temp;
}
}
return NULL;
}
void loop()
{
\\list SD contents
USB.println(SD.ls());
const char * image = getImage();
if(image != NULL) {
USB.println("Found an image!");
USB.println(image);
int byte_start = 0;
USB.print("Image Size: ");
**USB.println(SD.getFileSize(image));
USB.println(SD.getFileSize("img.jpg"));**
}
The two lines at the bottom are the troublesome ones. If I pass a literal string then I get the file size perfectly. However, if I pass the string (as represented by the image variable) then I am given a glorious -1. Any ideas why?
For clarity, the print out of image does display the correct file name.
EDIT: I know it is frowned upon in C to return a char and better to modify a variable passed to the function. I have used this approach as well and an example of the code is below, with the same result:
char * image = NULL;
getSDImage(&image, sizeof(image));
void getSDImage(char ** a, int length) {
int numFiles = SD.numFiles();
for(int i=0; i<numFiles;i++) {
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strcpy(*a, temp);
}
}
}
EDIT 2: The link to the entry is here: SD.ls and the link for the file size function: SD.getFileSize
From the return, it seems like the issue is with the file size function as the return is -1 (not 0) and because a result is returned when listing the root of the SD.
Thanks!
UPDATE: I have added a check for a null terminated string (it appears that this was an issue) and this has been addressed in the getSDImage function, with the following:
void getSDImage(char ** a, int length) {
int numFiles = SD.numFiles();
for(int i=0; i<numFiles;i++) {
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strncpy(*a, temp, strlen(temp)-1);
*a[strlen(*a)-1] = '\0';
}
}
}
This seems to work and my results to standard output are fine, the size is now not shown as the error-indicating -1 but rather -16760. I thought I should post the update in case anyone has any ideas but my assumption is that this is something to do with the filename string.
There are several things that could be wrong with your code:
1) You might be passing "invisible" characters such as whitespaces. Please make sure that the string you are passing is exactly the same, i.e. print character by character including null termination and see if they are the same.
2) The value that is getting returned by API and latter used by other API may not be as expected. I would advise that (if possible) you look at the API source code. If you can compile the API itself then it should be easy to find the problem (check what API getFileSize() gets from parameters). Based on the API documentation you have sent check the value stored in buffer[DOS_BUFFER_SIZE] after you get -1 from.
EDIT (after looking at the API source code):
On line 00657 (func find_file_in_dir) you have:
if(strcmp(dir_entry->long_name, name) == 0)
it seems as the only reason why you would have different reply when using string literal as opposed to the getting name from your function. So it is very likely that you are not passing the same values (i.e. you are either passing invisible chars or you are missing string termination).
As final note: Check the content of buffer[DOS_BUFFER_SIZE] before each code to SD API.
I hope this helps.
Kind regards,
Bo
This:
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strcpy(*a, temp);
}
is broken, it's not allocating room for the terminator and is causing a buffer overflow.
You should use:
*a = malloc(strlen(temp) + 1);
There's no need to cast the return value of malloc() in C, and sizeof (char) is always 1.

Resources