segmentation fault core dumped c - c

I'm new to C, I got an error today which is:
segmentation fault core dumped
I used gdb to track the code, I found that the error occurs in this line:
if (!strcmp(user_pass, passwddata->passwd))
Where user_pass is a char array, and passwddata is a struct, passwd is a member of the struct, which is also a type of char array, I tried to change the code to
if (!strcmp(user_pass, "ttt"))
The error didn't occur, so I guess the error occurs on that struct, if more code is needed, I can add it, here I want to understand under what condition can such kind of error occur on a struct?
Here is the code:
int main(int argc, char *argv[]) {
mypwent *passwddata; /* this has to be redefined in step 2 */
/* see pwent.h */
char important[LENGTH] = "***IMPORTANT***";
char user[LENGTH];
//char *c_pass; //you might want to use this variable later...
char prompt[] = "password: ";
char *user_pass;
sighandler();
while (TRUE) {
/* check what important variable contains - do not remove, part of buffer overflow test */
printf("Value of variable 'important' before input of login name: %s\n",
important);
printf("login: ");
fflush(NULL); /* Flush all output buffers */
__fpurge(stdin); /* Purge any data in stdin buffer */
if (gets(user) == NULL) /* gets() is vulnerable to buffer */
{
exit(0); /* overflow attacks. */
}
printf("******************* %s\n",user);
/* check to see if important variable is intact after input of login name - do not remove */
printf("Value of variable 'important' after input of login name: %*.*s\n",
LENGTH - 1, LENGTH - 1, important);
user_pass = getpass(prompt);
passwddata = getpwnam(user);
printf("^^^^^^^^^^^^^^^^^^^^^^^^^^ %s\n", user_pass);
if (passwddata != NULL) {
/* You have to encrypt user_pass for this to work */
/* Don't forget to include the salt */
if (!strcmp(user_pass, "ttt")) {
printf(" You're in !\n");
/* check UID, see setuid(2) */
/* start a shell, use execve(2) */
}
}
printf("Login Incorrect \n");
}
return 0;
}

Most likely passwd or passwddata is NULL, in the latter case the -> is attempting to deference the NULL pointer and thus it's crashing.
By changing your code to:
if (!strcmp(user_pass, "ttt"))
You isolated the first part, so you know user_pass is OK. You can use a debugger or some checks and printf's to get the values of passwddata and passwd to close on what the problem is.
Now that you've updated the code you know the problem is with passwd. You start with an empty pointer:
mypwent *passwddata;
Later you set the pointer to the return of getpwnam, presumably this is a pointer to a structure of type mypwent that you allocated some memory for:
passwddata = getpwnam(user);
You have a check to make sure passwddata isn't null:
if (passwddata != NULL) {
if (!strcmp(user_pass, "ttt")) {
So now you've checked everything except passwd, passing a null into strcmp() will cause it to crash with that message, so I'm guessing you only allocated memory for the structure and not for the char array within the structure.

My guess would be that passwddata is NULL.
Or the buffer passwddata->passwd points to
shorter than the string in user_pass
and
not null-terminated
Together those two make strcmp access beyond the limits of the second argument's buffer and hence cause the error.

Related

How to use the H5LTget_attribute_string function?

I have asked this on the HDF Forum here but haven't received an answer (yet). So I thought I try my luck here.
I have created a small test file in Python (h5py) and want to use the H5LTget_attribute_string function to read an attribute from it. However, I'm not sure how to use this function.
My test file looks like this.
HDF5 "attr.h5" {
GROUP "/" {
DATASET "my_dataset" {
DATATYPE H5T_STD_I64LE
DATASPACE SIMPLE { ( 12 ) / ( 12 ) }
DATA {
(0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
}
ATTRIBUTE "string_attr" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_UTF8;
CTYPE H5T_C_S1;
}
DATASPACE SCALAR
DATA {
(0): "this is a string"
}
}
}
}
}
Looking at the documentation of H5LT_GET_ATTRIBUTE it seems to me that I need to allocate a buffer and pass the address of the buffer as the last parameter, after which the H5LT_GET_ATTRIBUTE function would fill the buffer. My first attempt was therefore this.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char string[1024]; // assume buffer is large enough;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
However this didn't work as expected, see the output below.
string :
pointer: 0x7ffe3f7ec770
---- reading attribute ----
string : #B�k2V
pointer: 0x7ffe3f7ec770
After some googling and experimenting I found out that the last parameter should be the address of the buffer. Then the H5LT_GET_ATTRIBUTE function will make the buffer point to the actual attribute value. The following function compiled with a warning but it gave the correct output.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char* string = NULL;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", &string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
Output
string : (null)
pointer: (nil)
---- reading attribute ----
string : this is a string
pointer: 0x559e9e3d1240
Now I am perfectly happy to use it like this, and I can cast to **char to get rid of the warning, but I would like to be sure that this is the expected behavior. Ideally the documentation should be updated.
So my questions are:
Is the second example correct?
How long is the data in the string buffer valid? That is, when is the memory released by the HDF lib? (E.g. when the file is closed)
Should I use strcpy to copy the string data before using it?
As pointed by Scot Breitenfeld (from the HDF group):
If you are reading a variable length string with H5LTget_attribute_string (H5T_VARIABLE) then you don’t need to allocate the string, just pass in a pointer and the library will handle the allocations. If you are reading a fixed length string then you need to allocate a string that is “large enough”.
So, (1) your second approach seems ok to me.
As for (2) and (3), I would bet you are responsible for freeing the buffer, so no need to copy it. However, to be sure, you can use a debugger to check if the library is accessing the buffer or, even better, use valgrind to find memory leaks (when you try not to free the buffer).
I don't do HDF5, but I do enough C to provide you some answers with a very high percentage of being what you look for.
Is the second example correct?
yes it is. first because it returns the right and expected result, second
because any library that will fill a string (aka: char *) will need you to provide the address of a pointer (aka: char **).
How long is the data in the string buffer valid?
It is valid for as long as your program runs. This memory has been allocated for you with the right size, so it is valid for the entire lifetime of your program but it is now your responsibility to free it.
If you need more details on that please respond/comment to that message saying so and we'll help you.
Should I use strcpy to copy the string data before using it?
No you don't the memory has been alocated for you, you can keep it as is :-)
Next step that I advise you to do:
Now that you found the issue in their doc you should contact them and tell them.

Pipe's write overwrites an allocated space of memory

My program it's pretty big, so I'll highlight the main problem and add some details about it.
First part of my code:
int myPipe[2]; //A global variable, so I don't have to pass it to future functions
int main(int argc, char *args[])
{
mode_t pUmask = umask(0000); //Obsolete variable to my problem
errno = 0; //Obsolete variable to my problem
char pattern[2500] = "Test1"; //Obsolete variable to my problem
int p = 0; //DEFAULT NUMBER OF PROCESSES
int deep = 0; //Obsolete variable to my problem
int n = 1; //Obsolete variable to my problem
if(pipe(myPipe))
{
perror("Pipe Error: ");
exit(-1);
}
if( (write(myPipe[1], &p, (sizeof(int)*3))) == -1) //First write works
{
perror("write: ");
exit(-1);
}
//Then a bunch of code releated to file reading
}
Second part:
{
//in another function
//The part where I create fileName
char* fileName = calloc(strlen(fileData->d_name)+4, sizeof(char));
strcpy(fileName, fileData->d_name);
}
Third part:
//in another another function
if(S_ISREG(data.st_mode))
{
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
printf("\t\tOh boy! It's a regular.\n");
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
if((read(myPipe[0], &p, (sizeof(int)*3))) == -1) //First time I read
{
perror("\t\t read: ");
exit(-1);
}
printf("fileName: %s", fileName); //SEGMENTATION FAULT
There is a bunch of code in between, but it doesn't affect the fileName at all (in fact, up until the "read", fileName was printed flawlessly), and after it a SEGMENTATION FAULT happens.
At one point by changing the printfs locations I was able to get the fileName AFTER the read, which was basically the fileName value("File1") followed by the p integer value(0), which created the new corrupted fileName("File10").
So what's happening? I reserved the space for fileName, I passed the fileName pointer to the following functions up to that read, and supposedly the fd should have it's own adress space as well. HELP.
P.s. if you need more info, I'm willing to give it to you, even the full code, but it's REALLY complicated, and I think I gave you enough proof that fileName doesn't get corrupted at all until the read part, THANK YOU.
P.p.s.
I never close either of the "MyPipe" extremes, since I have to use them multiple times, I wanted to close them at the end of the program.
The statements that write and read the pipe are causing undefined behavior. p is declared:
int p;
But when you write and read it through the pipe, you use sizeof(int)*3, so you're accessing outside the object.
Change those statements to use just sizeof p.

C string modification

I came across a confused problem when I program in C
when i use oldPacket.filename = "fallout.jpg" //i have a file called fallout.jpg,and a struct called oldPakcet with an char* type filename
The program ran very well
Now, I decide to let user to in put the filename and also check the existence of the file. I wrote the following function:
bool Searchfile(packet* ptr) {
char userinput[100];
fgets(userinput, sizeof (userinput), stdin); //non terminated input by fgets
userinput[strcspn(userinput, "\n")] = 0;
//printf("%d\n",strlen(userinput));
ptr->filename = userinput + 4;//i skip the first 4 char since the correnct format is ftp <filename>
printf("%s\n",ptr->filename);
printf("%d\n",strlen(ptr->filename));
ptr->filename[strlen(ptr->filename)] = '\0';
if (access(ptr->filename, F_OK) != -1) {
printf("exist\n");
return false;
} else {
//printf("does not exist\n");
return true;
}
}
I call this function by
while (Searchfile(&oldPacket)){
printf("Please input the file name in the format: ftp <file name> \n");
}
However the program is no longer working and it shows seg fault at
int filesize;
fp = fopen(oldPacket.filename, "rb");
fseek(fp, 0L, SEEK_END);//here is the seg fault
Anyone have some idea why this happen ?
I already printf each char of the filename and it looks correct....
Thanks in advance
You let ptr->filename point to an address of local variable userinput, and accessing this value once userinput has gone out of scope is undefined behaviour.
The reason for the segfault is probably that the value of filename, when accessed outside of Searchfile, may be garbage, such that the file will not be opened. The subsequent fseek will then be called with a NULL-value for fp...
A simple solution to overcome this would be to write static char userinput[100];, at least when you are not working in a multithreaded environment. Otherwise you'd have to reserve memory for ptr->filename and copy contents of userinput.

Parse This IP To Be The Right Length?

For something I am doing I would like to get the external IP of the PC running the program (written in C). So far I have found the best way is to connect to a site that simply displays the IP of the visitor, and then parse the webpage for the IP. The first part was easy, but when I display the buffer I read the page (which only visibly consisted of my IP) I get a few random extra symbols/characters after the IP. Here is the code I am using ATM (simplified to exclude other stuff):
HINTERNET OpenInternet = NULL;
HINTERNET GetIP = NULL;
DWORD BytesRead = 0;
char IPGrabbed[30];
OpenInternet = InternetOpen("Microsoft Internet Explorer", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (OpenInternet == NULL) {
return 1;
}
GetIP = InternetOpenUrl(OpenInternet, "http://api.externalip.net/ip/", NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (GetIP == NULL)
return 1;
if (!InternetReadFile(GetIP, &IPGrabbed, sizeof(IPGrabbed), &BytesRead))
return 1;
printf("IP: %s", IPGrabbed);
getchar();
I also tried parsing through IPGrabbed stopping at any '\n' or '\r' (because it displays the weird characters on the line below the IP when I printf() it) and then copying everything up till there to another char array, but got the same result. Could anyone help me figure out what is going on here? Thank you.
Initialise the buffer to all 0s and then read one character less then the buffer to read into provides.
This way the 0-terminator a C-"string" relies on is provided implicitly.
char IPGrabbed[30] = ""; /* Initialise the buffer to all `0`s ... */
[...]
/* ... and then read one character less then the buffer to read into provides. */
if (!InternetReadFile(GetIP, &IPGrabbed, sizeof(IPGrabbed) - 1, &BytesRead))
return 1;
fprintf(stderr, "IP: %s", IPGrabbed); /* Print to stderr, as it's not buffered so
everything appear immediately to the console. */
The result from InternetReadFile is not null-terminated, you need to add a null character to the end of the string by code after the read is successful:
IPGrabbed[BytesRead] = 0;
Edit 1
As suggested in the comment by Jonathan Potter, the above code may be subjected to a buffer overflow error if the site being accessed is returning anything longer than a IP string (maximum 16 characters).
Suggest to change the InternetReadFile to read 1 less of the buffer length instead of full buffer length to eliminate the above problem.
InternetReadFile(GetIP, &IPGrabbed, sizeof(IPGrabbed)-1, &BytesRead)

ARRAYS in C a hassle

I have been trying to program a UNIX style shell command prompt in C. Within this program I need it to keep track of the commands that have already been used, so the user can recall the last command by entering 'r'. I made a globally initialized array to hold strings. Whenever the array of characters a user entered needs to be saved, I add it to the global array. I have tried memcpy, simply copying each value using a loop, and just copying the pointer. None of these have been working. I am not super familiar with C and I am sure it is a pointer problem.
Whenever I copy the pointer of inputBuffer to my global array string (it does get copied), however upon leaving the setup function this pointer disappears? I am not exactly sure what I am doing wrong.
Test:
(1)user input --> ls
string[0] = ls
(2)user input --> r
inputBuffer = ls
string[recent] = ls
incorrectly does...
inputBuffer = r
string[recent] = r
(I have included the relevant parts of the code.)
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
#define SAVED_BUFFER 100
char *string[SAVED_BUFFER];
int p = 0;
int recent = -1;
int stringSize = 0;
void setup(char inputBuffer[], char *args[],int *background)
{
int length, /* # of characters in the command line *
/* read what the user enters on the command line */
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
start = -1;
if (length == 0)
exit(0); /* ^d was entered, end of user command stream */
if (length < 0){
perror("error reading the command");
exit(-1); /* terminate with error code of -1 */
}
if (inputBuffer[0] == 'r' && inputBuffer[1] == '\n' && stringSize > 0) {
int k;
memcpy(inputBuffer, string[recent], strlen(string[recent]) + 1);
printf("%s",inputBuffer);
printf("%s",string[recent]);
}
else {
string[p] = inputBuffer;
printf("%s", string[0]);
stringSize++;
recent++; // one behind strings current array location, to get history
p++; // current string array spot
}
}
int main(void)
{
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
while (1) { /* Program terminates normally inside setup */
background = 0;
printf("COMMAND2->");
fflush(0);
setup(inputBuffer, args, &background); /* get next command */
}
}
When you "save the input buffer" you actually only store a pointer to the inputBuffer array:
string[p] = inputBuffer;
The actual data is not copied, you just store a pointer to the global input buffer. When the next input replaces the old content of inputBuffer, you will see the new content even if you access it through string[recent].
The calls to memcpy don't actually do anything, since the passed input and output buffer all refer to the same memory.
To actually store a copy of the data you have to allocate new memory to store the copy. Since you are dealing with strings, this is most easily done with strdup(), which duplicates a string:
string[p] = strdup(inputBuffer);
Later, once you are done with such a copy and don't need it anymore you have to free the memory used by the copy:
free(string[p]);
Have you tried changing
char *string[SAVED_BUFFER];
to
char string[SAVED_BUFFER][MAX_LINE];
I think that's how you're treating it in the code

Resources