I want to write a small program, which, by user input through argv, gets a segmentation error. I am quite new to C but I think the following code does the job:
int main(int argc, char *argv[])
{
int bufferSize;
char * buffer[100];
unsigned int i;
if (argc > 1) {
bufferSize = atoi(argv[1]);
for (i = 0; i < bufferSize; ++i)
*( buffer + i ) = i;
}
return 0;
}
My idea is that the program intialize (?) a pointer to a buffer of a specific size. If the user then input a number larger then the buffer size it will write to uninitialized memory, hence get a seg. fault. Is this reasoning correct whatsoever?
Ps. When compiling,I get a assignment makes pointer from integer without a castwarning, can someone maybe tell me why that happens? Thanks
The most traditional way to purposely get a segmentation fault, that I've seen, is to write to NULL, e.g. something like:
*((char *) NULL) = 0;
You can use a command line argument as a simple boolean value to see if this should be done or not.
Note that writing to NULL is not actually guaranteed to cause a crash, it's simply undefined behavior so basically anything could happen (including causing nasal demons).
The warning is because you have an array of pointers, and try to assign an integer to a pointer in the array.
char * buffer[100]; is an array of pointer which points to some garbage locations by default.
Here *( buffer + i ) = i; you are trying to deference that area which doesn't belongs to you.
My guess is that, you wanted to create a buffer. so
char buffer[100]; is enough.
I would not worry about writing to cause a segmentation fault. Reading is sufficient enough. You stand a better chance of causing a segfault if the buffer is on the heap. This application fairly reliably segfaults for negative inputs less than -10 for me.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int main(int argc, char* argv[])
{
static const int array[10] = {0,1,2,3,4,5,6,7,8,9};
int * const heapArray = malloc(sizeof(array));
memcpy(heapArray,array,sizeof(array));
const int index = atoi(argv[1]);
printf("%i\n",heapArray[index]);
free(heapArray);
return 0;
}
The problem is, the result of malloc() can be much much larger than the requested size for most systems. So even for large values it does not segfault, it just returns whatever happens to be there in memory.
ericu#eric-phenom-linux:~$ ./segfault -5
Segmentation fault (core dumped)
ericu#eric-phenom-linux:~$ ./segfault 11
0
ericu#eric-phenom-linux:~$ ./segfault 100
0
ericu#eric-phenom-linux:~$ ./segfault 100
0
ericu#eric-phenom-linux:~$ ./segfault 1000
0
ericu#eric-phenom-linux:~$ ./segfault 10000
0
ericu#eric-phenom-linux:~$ ./segfault 100000
Segmentation fault (core dumped)
Related
This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 3 years ago.
I am trying to make all possible combinations of alphabets using a number. Input NUM given by user.
The combinatitions are created by splitting input numbers upto two digits. Input Obtained as char*
I am Using C. I am getting output as Segmenation fault (core dumped), guessing because of the warning.
substr is my own function.
sample input and output
input: 11112
output:
AAAAB
AAAL
AAKB
AKAB
AKL
KAAB
KAL
KKB
My CODE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* substr(char* str,int l,int n)
{
char* c;
int len = n-l;
while(l<n)
{
*c = *(str+l);
l++;
c++;
}
*c='\0';
return c-len;
}
int printAlpha(char* str, char* word)
{
char *sub;
char* ch;
int n = strlen(str);
if(n == 0)
{
printf("%s",word);
}
else
{
sub = substr(str,0,1);
int num = atoi(sub);
str = substr(str,1,n);
ch = 'A'+(num-1);
printAlpha(str, strcat(word, ch));
sub = substr(str,0,2);
num = atoi(sub);
if(strlen(str)>=2 && num <= 26)
{
str = substr(str,2,n);
ch = 'A'+(num-1);
printAlpha( str, strcat(word, ch) );
}
}
return 0;
}
int main()
{
char* str;
char* word = '\0';
scanf("%s",str);
printAlpha(str,word);
return 0;
}
thanks in advance.
As commenters have said you need to allocate memory in c dynamically.
In c if you need to store something like an array of characters you have 2 basic szenarios:
You know how many elements your array will contain before you compile then you can use
char word[numberOfLetters]
this will work as long as you dont need to store more letters, it becomes problematic in the other case
you dont know how big your array has to be before compiling
e.g when you are doing stuff with veriable lengths. imagine storing a user input into a char array. How should you make the array? if you make it 100 chars big and the user types 101 then you will get a segfault or loose everything he typed after the 100th char
you could also deal with this by making the array huge, but then with a short input youd be wasting a lot of memory and you still have the problem that if you need 1 char more than what you chose as size it wont work.
here is where you have to use dynamic memory allocation using functions like element_ptr* =malloc(numOfElements*sizeof(element)); to request memory during runtime.
what malloc does is it returns a pointer to the address, of the memory you requested
when you dont need the memory anymore you call free(element_ptr); this will free the memory again, otherwise it will stay blocked.
best you read up on malloc in the man pages
I have a function that converts decimal to binary and returns a char * of a binary:
void decimal2binary(int decimalNum, int size, char * charPtr){
int decimalTemp = decimalNum;
int modNum;
for(int sizeTemp = size; sizeTemp >= 0; --sizeTemp){
modNum = decimalTemp >> sizeTemp;
if(modNum & 1){
strcat(charPtr, "1");
}else{
strcat(charPtr, "0");
}
}
}
When I try to test it in main, I get the correct out put as and then "Segmentation fault 11" with gcc compiler:
In int main() :
char testArr[] = "test";
char * foo = testArr;
decimal2binary(10,7, foo);
printf("%s\n", foo);
printf("asdasds\n");
Result :
test00001010
asdasds
Segmentation Fault: 11
Any ideas?
The array you pass in has a size of 5 - "test\0".
It doesn't "work" as you are writing in an invalid memory location.
More like undefined behavior.
EDIT:
If you can't tell the size of the buffer to pass in, a suggestion might be to use realloc and grow your array. Return the pointer, but remember to free the allocated memory.
You are getting segmentation fault for attempting to write on memory addresses that are not
inside your memory segment.
Use an array of bigger size or even better use pointers and keep on realloc'ing new space
as needed.
Alright guys, this is my first post here. The most recent assignment in my compsci class has us coding a couple of functions to encode and decode strings based on a simple offset. So far in my encryption function I am trying to convert uppercase alphas in a string to their ASCII equivalent(an int), add the offset(and adjust if the ASCII value goes past 'Z'), cast that int back to a char(the new encrypted char) and put it into a new string. What I have here compiles fine, but it gives a Segmentation Fault (core dumped) error when I run it and input simple uppercase strings. Where am I going wrong here? (NOTE: there are some commented out bits from an attempt at solving the situation that created some odd errors in main)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <stdlib.h>
char *encrypt(char *str, int offset){
int counter;
char medianstr[strlen(str)];
char *returnstr;// = malloc(sizeof(char) * strlen(str));
for(counter = 0; counter < strlen(str); counter++){
if(isalpha(str[counter]) && isupper(str[counter])){//If the character at current index is an alpha and uppercase
int charASCII = (int)str[counter];//Get ASCII value of character
int newASCII;
if(charASCII+offset <= 90 ){//If the offset won't put it outside of the uppercase range
newASCII = charASCII + offset;//Just add the offset for the new value
medianstr[counter] = (char)newASCII;
}else{
newASCII = 64 + ((charASCII + offset) - 90);//If the offset will put it outside the uppercase range, add the remaining starting at 64(right before A)
medianstr[counter] = (char)newASCII;
}
}
}
strcpy(returnstr, medianstr);
return returnstr;
}
/*
char *decrypt(char *str, int offset){
}
*/
int main(){
char *inputstr;
printf("Please enter the string to be encrypted:");
scanf("%s", inputstr);
char *encryptedstr;
encryptedstr = encrypt(inputstr, 5);
printf("%s", encryptedstr);
//free(encryptedstr);
return 0;
}
You use a bunch of pointers, but never allocate any memory to them. That will lead to segment faults.
Actually the strange thing is it seems you know you need to do this as you have the code in place, but you commented it out:
char *returnstr;// = malloc(sizeof(char) * strlen(str));
When you use a pointer you need to "point" it to allocated memory, it can either point to dynamic memory that you request via malloc() or static memory (such as an array that you declared); when you're done with dynamic memory you need to free() it, but again you seem to know this as you commented out a call to free.
Just a malloc() to inputstr and one for returnstr will be enough to get this working.
Without going any further the segmentation fault comes from your use of scanf().
Segmentation fault occurs at scanf() because it tries to write to *inputstr(a block of location inputstr is pointing at); it isn't allocated at this point.
To invoke scanf() you need to feed in a pointer in whose memory address it points to is allocated first.
Naturally, to fix the segmentation fault you want to well, allocate the memory to your char *inputstr.
To dynamically allocate memory of 128 bytes(i.e., the pointer will point to heap):
char *inputstr = (char *) malloc(128);
Or to statically allocate memory of 128 bytes(i.e., the pointer will point to stack):
char inputstr[128];
There is a lot of complexity in the encrypt() function that isn't really necessary. Note that computing the length of the string on each iteration of the loop is a costly process in general. I noted in a comment:
What's with the 90 and 64? Why not use 'A' and 'Z'? And you've commented out the memory allocation for returnstr, so you're copying via an uninitialized pointer and then returning that? Not a recipe for happiness!
The other answers have also pointed out (accurately) that you've not initialized your pointer in main(), so you don't get a chance to dump core in encrypt() because you've already dumped core in main().
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char *encrypt(char *str, int offset)
{
int len = strlen(str) + 1;
char *returnstr = malloc(len);
if (returnstr == 0)
return 0;
for (int i = 0; i < len; i++)
{
char c = str[i];
if (isupper((unsigned char)c))
{
c += offset;
if (c > 'Z')
c = 'A' + (c - 'Z') - 1;
}
returnstr[i] = c;
}
return returnstr;
}
Long variable names are not always helpful; they make the code harder to read. Note that any character for which isupper() is true also satisfies isalpha(). The cast on the argument to isupper() prevents problems when the char type is signed and you have data where the unsigned char value is in the range 0x80..0xFF (the high bit is set). With the cast, the code will work correctly; without, you can get into trouble.
So I have a program which takes a command line argument from the user and uses atoi to convert it to a number. It all works fine until the number that is passed from the command line is more than 2048.
Here is the simple program:
int no_of_elements_per_thread = 0;
int main(int argc, char* argv[])
{
int status;
void* thread_arg;
void* res;
int i = 0;
//initialize
no_of_elements_per_thread = atoi(argv[1]);
return 0;
}
When I run the program for different values the output is as follows:
[adeb1][open-19][~/pre2] ./pre2 2098
Segmentation fault
with smaller values:
[adeb1][open-19][~/pre2] ./pre2 210
[adeb1][open-19][~/pre2]
Interestingly if I try to do a printf with %s without doing atoi I still get segmentation fault as well with argv[1]. So it seems argv[1] is giving problem with values higher than 2048.
I am using gcc in linux if that matters.
Where is your declaration of atoi? Without #include <stdlib.h>, I would assume there is none.
You may also want to ensure argc > 1 before using argv[1].
I copied some code that simply reads a file to a string and prints the string from an older program. It was working fine, so I decided to modify it a bit. The new program is
#include <stdio.h>
#include <string.h>
int main() {
FILE *itemlist = fopen("itemlist", "r");
char *currentstring, charbuffer[2];
// char itemstart = 0;
while (fgets(charbuffer, 2, itemlist)) {
strcat(currentstring, charbuffer);
}
printf("%s", currentstring);
return 0;
}
And it works as expected. But when I uncomment the itemstart line, it gives a segmentation fault. I'm not even using it and as far as I'm concerned, initializing an char to 0 is not illegal. I thought it was an issue with types, then I changed it to a short and then to int and it was still giving a segfault.
But then I removed the = 0 part and it worked again. Then I decided to put it back, debug the binary with gdb, and the segfault was at strcat.
How is this possible?
currentstring is a dangling pointer, so strcat(currentstring, charbuffer); results in undefined behavior.
Probably uncommenting char itemstart = 0 initializes some memory to 0 and the access violation is made visible, however this is just a guess. Undefined behavior means anything can happen.
You should allocate memory for currentstring:
currentstring = malloc(10); //or whatever length you need
You need to allocate some space for currentstring.
Segfaults when uncommenting unrelated lines are made possible by the unsafeness of the C language. The end behavior of an incorrect program is determined by subtle choices made by the compiler.
When confronted to such madness, you should try to correct your code first. This is of course, not always easy. On a 8 lines program, you should be ok though.
You must allocate space for currentstring variable and control the size of it for avoid segment fault/heap corruption.
#define MAX_BUFFER_SIZE 32
//...
FILE *itemlist = fopen("itemlist", "r");
char *currentstring = malloc(MAX_BUFFER_SIZE+1);
char *tmpbuf;
char charbuffer[2];
// char itemstart = 0;
int bytesloaded = 0;
while (fgets(charbuffer, 2, itemlist)) {
if(bytesloaded + 2 > buf_size) {
/* call realloc() */
buf_size += MAX_BUFFER_SIZE;
tmpbuf = realloc(currentstring, buf_size);
if(tmpbuf == NULL) { /* Get off loop. Using break or return. */
break;
}
currentstrig = tmpbuf;
}
memcpy(currentstring + bytesloaded, charbuffer, 2);
bytesloaded += 2;
}
//...
free(currentstring);
I haven't tested,but I believe that it works.