#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
typedef struct client
{
int threadid;
int argc;
char *argv[3];
} client;
void exit(int status);
void error(char *msg);
void *threadClient(void *socket_desc);
int main(int argc, char *argv[])
{
client info[10];
pthread_t thread[10];
printf("%s\n%s\n%s\n", argv[0], argv[1], argv[2]);
// Error happens here
for (int i=0; i<=10; i++)
{
info[i].threadid = i;
strcpy(info[i].argv[0], argv[0]);
strcpy(info[i].argv[1], argv[1]);
strcpy(info[i].argv[2], argv[2]);
info[i].argc = argc;
printf("here");
if (pthread_create(&thread[i], NULL, threadClient, (void*)&info[i]) < 0)
{
perror("could not create thread");
return 1;
}
sleep(3);
}
pthread_exit(NULL);
return 0;
}
During the loop, when I am trying to copy the info from argv to my struct I get a segmentation fault. Why does it happen?
Program received signal SIGSEGV, Segmentation fault.
__strcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:296
296 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
There are two problem here.
First, your argv array in your info structure is an array of pointers. These start out uninitialized. When you later call strcpy, giving one of these array elements as the first parameter, it expects that pointer to point to valid memory. So you end up dereferencing an uninitialized pointer. This invokes undefined behavior, which in this case manifests as a segfault.
You need to assign something to these pointers. You can either use strdup to make a copy of these strings:
info[i].argv[0] = strdup(argv[0]);
info[i].argv[1] = strdup(argv[1]);
info[i].argv[2] = strdup(argv[2]);
Or, if you don't plan on modifying these values, you can just copy the pointer values directly:
info[i].argv[0] = argv[0];
info[i].argv[1] = argv[1];
info[i].argv[2] = argv[2];
The second issue is an off-by-one error in your loop:
for (int i=0; i<=10; i++){
Because you use <=, your indexes into the array will range from 0 to 10. However, your array only has 10 elements (with indexes 0 to 9), so you're writing past the end of the array. This also invokes undefined behavior.
Change your conditional to < as follows:
for (int i=0; i<10; i++){
Your struct is defined to contain three pointers (char *argv[3]). When you create an array of those structs in the stack (client info[10]) space is reserved for these pointers, among other things. The structs aren't initalized to anything, so the pointers don't point to any sensible memory location. Hence, accessing them as with strcpy(info[i].argv[0], argv[0]); is in error.
Either allocate the space you use explicitly:
info[i].argv[0] = malloc(strlen(argv[0])+1);
strcpy(info[i].argv[0], argv[0]);
Or use strdup() to copy the strings:
info[i].argv[0] = strdup(argv[0]);
Remember to free() the space you allocated afterwards.
Also, I don't think you should declare a function called exit() yourself, it's a standard function and should be in stdlib.h.
Related
here is my code
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
int a;
for(int i=1;i<=argc;i++){
a+=atoi(argv[i]);
}
printf ("%d",a);
}
I keep getting segmentation faults but i am trying to add up all elements of the command line so for example ./a.out 5 6 7 would give 18 as the output, cheers.
The problem (with the crash) is the loop itself:
for(int i=1;i<=argc;i++)
The argc argument is the number of arguments passed to the program, including the "program name" at argv[0]. So valid indexes for the actual arguments are argv[1] to argv[argc - 1].
Furthermore the argv array is terminated by a null pointer, which will be at argv[argc].
Since you include argv[argc] in your loop you pass a null pointer to atoi which leads to undefined behavior and likely crashes.
The simple solution is to use less-than < instead of less-than-or-equal as the loop condition:
for(int i=1;i<argc;i++)
You never initialized a to 0. Also, use strtol() function.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int a = 0;
for (int i = 1; i < argc; i++) {
a += strtol(argv[i], NULL, 10);
}
printf("%d\n", a);
return EXIT_SUCCESS;
}
I'm trying to find all groups to which user belongs in my UNIX system, and that for each user.Implementation has to be in C. Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
static void error_fatal(char* msg)
{ perror(msg); exit(EXIT_FAILURE); }
int main(int argc, char** argv) {
struct group* grp;
struct passwd* pwd;
char *name;
int i = 0;
setpwent();
while((pwd = getpwent()) != NULL){
if( ( name = (char*) malloc( (strlen(pwd->pw_name)+1)*sizeof(char))) == NULL ) error_fatal("malloc");
strcpy(name, pwd->pw_name);
printf("%s:\n", name);
setgrent();
while( (grp = getgrent()) != NULL ) {
for( i=0; i < (sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0])); i++ ){
if( /*strlen(&grp->gr_mem[i][0]) == strlen(name) && */ !strcmp(grp->gr_mem[i], name) )
printf("%s\n", name);
} }
endgrent();
free(name);
}
endpwent();
return 0;
}
But I get segmentation fault after "root:" output.
I'm pretty sure the problem is in accessing list of members in the fourth field of /etc/group file (see man 5 group for details).
So, basically my problem would be to find out how many members each group has, so my counter(i in program, the last for loop) would have nice upper boundary.
Your problem is here:
for( i=0; i < (sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0])); i++ ){
struct group is defined as:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
You're assuming gr_mem is an array but it is not. It is a pointer pointing to the first element of an array. So sizeof(grp->gr_mem)/sizeof(grp->gr_mem[0]) gives you the size of a pointer, probably 8 on your system. So if a user has less than 8 groups, you'll end up reading past the end of the array gr_mem points to the start of.
Because the array pointed to by gr_mem is NULL terminated, finding that terminator tells you when the loop is done:
for( i=0; grp->gr_mem[i]; i++ ){
Running your code I detected your issue is not verifying grp->gr_mem[i] == NULL before using it in strcmp call:
if (grp->gr_mem[i] == NULL)
continue;
Adding those lines before strcmp call worked for me.
Also, don't forget to free the memory you are using. I don't know if this is your complete code, but here you should considering using free(name) within your while loop.
For example, If my program segaults, instead of gcc printing to the console "Segmentation Fault" can I have it print "Ya dun goofed"?
Segfaults are generally caused by dereferencing a garbage pointer. Therefore, while the literal answer to what you asked is that, as kaylum said, you can catch SIGSEGV in a signal handler, the better answer is that, before you use a pointer, you should ask yourself, “How do I know that this pointer is valid and that I am staying within the bounds of my array?"
If you don’t know that, your program has a bug. If you think you do, you can turn the assumption into an assertion which, since your pointer is valid, will always pass. For example:
void fill_array( unsigned fill_this_many,
size_t array_size,
int a[array_size] )
{
assert(a);
assert( array_size >= fill_this_many );
for ( unsigned i = 0; i < fill_this_many; ++i )
a[i] = f(i);
return;
}
You’ll now get a detailed message when you’re about to dereference a null pointer or write past the end of your array, which will contain more useful information for debugging than, "There was a segfault somewhere," and it might even save you from silent memory corruption too.
If you want to write your own message, you can define a wrapper such as:
#include <stdio.h>
#include <stdlib.h>
void fatal_error_helper( const char* file, int line, const char* restrict message )
{
fflush(stdout); // Don’t cross the streams!
fprintf( stderr, "\nError in %s, line %d: %s\n", file, line, message );
exit(EXIT_FAILURE);
}
#define fatal_error(message) fatal_error_helper( __FILE__, __LINE__, (message) )
int main(void)
{
int *big_array = calloc( 1073741824UL, sizeof(int) );
if (!big_array)
fatal_error("Not enough memory.");
return EXIT_SUCCESS;
}
And a contrived example of how to do bounds-checking at compile time, so as to fail gracefully if your constants change:
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 14U
#define M 5U
int main(void)
{
char message[LENGTH] = "hello, world!";
static_assert( M < LENGTH, "Tried to capitalize more letters than the array can hold." );
for ( unsigned i = 0; i < M; ++i )
message[i] = toupper(message[i]);
printf( "%s\n", message );
return EXIT_SUCCESS;
}
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
void segv_handler(int sig)
{
(void)sig;
const char *msg = "Hello signal handler!";
size_t len = strlen(msg);
write(STDERR_FILENO, msg, len);
abort();
}
int main()
{
struct sigaction act;
act.sa_handler = segv_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGSEGV, &act, NULL);
int *nullint = 0;
*nullint = 4;
return 0;
}
EDIT: I tough code is pretty much explanation how to do it. Of course there is a lot details that needs to be taken into account when writing signal handlers.
Basic limitation is that signal handler can't access any variable/structure that isn't written to atomically because handler could be called between any two instructions in your program. That means no calls to heap memory management, buffered io like printf, etc.
More details what the code does can be found from man pages stdout, sigaction and write.
Using C on Linux, I'm writing a code that stores all the information about the files in a directory using function stat() and prints them on the Terminal
The algorithm is quite simple, I made a structure array of "files" and dynamically allocated them. The structure contains a char array (string) so I dynamically allocated it too.
The thing is .. the dynamic allocation works fine but if I'm inside the while loop I can access the other element inside the structure - which is a structure stat object - but if I access it after the loop finishes, it gives me "Segmentation Fault"!
Here's the code
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <dirent.h>
struct file{
char* name;
struct stat fbuf;
};
int main(int argc, char **argv)
{
char* dir=NULL;
int k;
dir=(char *)malloc(strlen(argv[argc-1])+1);
dir=argv[argc-1];
strcpy(dir,argv[argc-1]);
DIR *curr_dir;
struct dirent *dir_inode;
int i,j=0;
char* sum=NULL;
struct file* files=NULL;
if ((curr_dir = opendir(dir)) == NULL) {
fprintf(stderr, "Can't Open %s\n", argv[1]);
exit(2);
}
while (((dir_inode = readdir(curr_dir))) != NULL) {
files=(struct file*) realloc(files,((j)+1)*(sizeof(char*)+sizeof(struct stat))); // Structure array reallocation
(files+(j))->name=(char *)(malloc(strlen(dir_inode->d_name)+1));//name allocation
for(i=0;i<strlen(dir_inode->d_name);i++)
(files+(j))->name[i]=dir_inode->d_name[i];//name storage
(files+(j))->name[i]='\0';
sum= (char *) malloc(strlen(dir)+strlen(dir_inode->d_name)+2);//To add file name to its directory
for(i=0;i<strlen(dir);i++)
sum[i]=dir[i];
sum[i]='/';
i++;
for(k=0;dir_inode->d_name[k]!='\0';k++)
sum[i+k]=dir_inode->d_name[k];
sum[i+k]='\0';//file name with directory in sum
if( stat(sum,&((files+j)->fbuf)) == -1){ // the function gets information from the file name and stores them in fbuf
printf("error stat\n");
exit(1);
}
free(sum);
if( S_ISDIR( ( (files+(j))->fbuf ).st_mode ) ){
printf("d");
}
else {
printf("-");
}
//Here the output appears fine
//The output depends on accessing fbuf in files array
printf("statOK\n");
(j)++; // index
}
printf("%d %d %d\n",files,j,files+1);
printf("%d\n",j);
printf("\n\n\n\n");
for(i=0;i<j;i++){
printf("%s\n",(files+i)->name);
printf("%d\n",files);
//Starting from here, same syntax but outside the loop it gives the error
if( S_ISDIR( ( (files+i)->fbuf ).st_mode ) ){
printf("d");
else {
printf("-");
}
}
free(files);
free(dir);
closedir(curr_dir);
exit(1);
}
The code isn't complete yet but all what I want is to access the fbuf outside the loop, then I can complete it
Any ideas?
Bad size assumption
This allocation is wrong:
files=(struct file*) realloc(files,((j)+1)*(sizeof(char*)+sizeof(struct stat)));
Here, you assumed that the size of struct file was the sum of the sizes of its two components. But in fact, you don't know how that structure is packed and aligned, so the size of struct file could be larger than what you thought. You should just be using sizeof(struct file) instead:
files=(struct file*) realloc(files,(j+1)*(sizeof(struct file)));
I am new with threads.
I am trying to make a C program that reverses the string given from the command line and create a thread that does this for each one . When I run it gives me Segmentation fault .
Here is the code:
#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
char* final[1000];
pthread_mutex_t *mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t p[];
void *reverse(void* arg){
char* s[100];
char* temp;
int i;
strcpy(s,(char*)arg);
printf("S este %s",s);
for(i=0;i<=strlen(s)/2;i++){
strcpy(temp,s[i]);
strcpy(s[i],s[strlen(s)-i-1]);
strcpy(s[strlen(s)-i-1],temp);
}
sleep(1);
pthread_mutex_lock(&mutex);
strcat(final,s);
printf("Intermediar %s",s);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main(int argc,char* argv[]) {
int i;
int n = argc;
strcpy(final,"");
for(i=1;i<n-2;i++){
pthread_create(&p[i],NULL,reverse,argv[i]);
}
for(i=1;i<n-2;i++){
pthread_join(p[i],NULL);
}
//printf("Sirul final este %s",final);
return 0;
}
Does anyone know a good site that could help me learn threads ?
Thanks !
char* final[1000];
is an array (with 1000 elements) of pointer to char, you want an array of char:
char final[1000];
the same problem with this array:
char* s[100];
temp is declared as a pointer, but you use it as an array with size 1
declare the mutex without the * ,remove the initialization and add in main:
pthread_mutex_init(&mutex, NULL);
you should also add a number to the array definition of pthread_t
You never initialize temp, so the call strcpy(temp, s[i]); causes undefined behavior.
Your treatment of s is also very confusing, the copying of arg (a string) into the memory used by s (an array of string pointers) is not valid. Just because you can cast away a warning doesn't mean you're doing something sensible.