Why segmentation fault using atoi command line arguments - c

I need to pas two command line arguments and I tried the following:
#include <stdio.h>
#include <stdlib.h>
void power(int base, int exp){
int res=1;
while(exp!=0){
res *= base;
--exp;
}
printf("Res = %d",res);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage %s arg2 arg2\n(EG: %s 2 3)\n",argv[0],argv[0]);
exit(1);
}else{
power(atoi(argv[1]),atoi(argv[2]));
}
printf("\n");
return 0;
}
Output:
michi#michi-laptop:~$ ./power
Usage ./power arg2 arg2
(EG: ./power 2 3)
michi#michi-laptop:~$ ./power 2 3
Res = 8
Everything until here is ok, but if when save argv[1] and argv[2] in variable like this:
int base = atoi(argv[1]);
int exp = atoi(argv[2]);
I get Segmentation fault
code:
#include <stdio.h>
#include <stdlib.h>
void power(int base, int exp){
int res=1;
while(exp!=0){
res *= base;
--exp;
}
printf("Res = %d",res);
}
int main(int argc, char *argv[]) {
int base = atoi(argv[1]);
int exp = atoi(argv[2]);
if (argc != 3) {
printf("Usage %s arg2 arg2\n(EG: %s 2 3)\n",argv[0],argv[0]);
exit(1);
}else{
power(base, exp);
}
printf("\n");
return 0;
}
But when I use Atoi inside printf everything is OK:
#include <stdio.h>
#include <stdlib.h>
void power(int base, int exp){
int res=1;
while(exp!=0){
res *= base;
--exp;
}
printf("Res = %d",res);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage %s arg2 arg2\n(EG: %s 2 3)\n",argv[0],argv[0]);
exit(1);
}else{
power(atoi(argv[1]), atoi(argv[2]));
}
printf("\n");
return 0;
}
My question is:
is this issue happen because of Atoi?
is this issue happen because I try to access argv[1] and argv[2] and they are not exists when I type ./program?
If I type ./program 2 3 everything is ok, which makes me think that segmentation fault happens because I try to access a memory location which doesn't belong to me at that point.

is this issue happen because I try to access argv[1] and argv[2] and they are not exists when I type ./program?
Yes, the problem is that you are trying to access the command lines arg's before verifying whether they are present or not.
In the second example code snippet, assign the values to the variables base and exp only after making sure that the input is available.
int base;
int exp;
if (argc != 3) {
printf("Usage %s arg2 arg2\n(EG: %s 2 3)\n",argv[0],argv[0]);
exit(1);
}else{
/* Assign the values here, as it is verified that arg's are obtained from cmd line*/
base = atoi(argv[1]);
exp = atoi(argv[2]);
power(base, exp);
}
In the above program it is made sure that I reference the args (argv[1] and argv[2]) only if they are passed as commandline arguments when the program is executed.

is this issue happen because I try to access argv[1] and argv[2] and
they are not exists when I type ./program?
It is because you're not checking for null. argv[1] and argv[2] could be null if no argument is passed in. This causes segmentation fault.
int base = atoi(argv[1]);
int exp = atoi(argv[2]);
Instead, try this
int base = 0;
int exp = 0;
if(argv[1] && argv[2])
{
int base = atoi(argv[1]);
int exp = atoi(argv[2]);
}
Or you could check the argument count to make sure you have 2 arguments passed in.
if(argc > 2)
{
int base = atoi(argv[1]);
int exp = atoi(argv[2]);
}

When you call atoi on argv[ > 0] when there's no argument, you're accessing out of bounds memory, which is Undefined Behavior.
By the C Standard definition, accessing out of bounds memory is Undefined Behavior.
Might Interest you
How dangerous is it to access an array out of bounds?
Undefined, unspecified and implementation-defined behavior

Related

using atoi to convert command-line arguments to int, is only returning the first digit entered

I have to use command line arguments to set up a map for a snake game for my uni assignment. We were not specifically told to use atoi to help convert the command line argument from string to int, However I thought the simple nature of atoi would do the trick. On testing I discovered it is only taking the first digit.
int main(int argc, char *argv[])
{
int isUserInput;
char arg1, arg2, arg3;
arg1 = argv[1][0];
arg2 = argv[2][0];
arg3 = argv[3][0];
isUserInput = checkUserArg(arg1, arg2, arg3);
int checkUserArg(char arg1, char arg2, char arg3)
{
int validation;
int rowMap, colMap, snakeLength;
rowMap = atoi(&arg1);
colMap = atoi(&arg2);
snakeLength = atoi(&arg3);
if ((rowMap < 5) || (colMap < 5) || (snakeLength < 3))
{
validation = FALSE;
}
else if ((rowMap >= 5) || (colMap >= 5) || (snakeLength >= 3))
{
if (snakeLength < colMap)
{
validation = TRUE;
}
else
{
validation = FALSE;
}
}
else
{
validation = FALSE;
}
return validation;
}
User has to enter 3 command line arguments (./file num1 num2 num3). I used atoi to convert the string command line arguments to int, but while testing I printed the numbers back and it won't convert the second digit only the first, e.g 1-9 works, but anything from 10 onwards only shows the first digit.
Any thoughts on why this is?
Cheers.
There are multiple problems in your code:
atoi is only using the first digit because you explicitly extract the first digit and pass it as a char. The function call actually has undefined behavior as &arg1 is the address of a single char, not that of a null terminator C string.
checkUserArg converts the arguments using atoi which has undefined behavior if the value converted exceeds the range of type int. Using strtol is recommended and allows for finer checks.
checkUserArg should return the converted values to the caller via pointer arguments.
the second test in checkUserArg is redundant: if the first test is false, then all 3 comparisons in the second test will be true.
instead of TRUE and FALSE, you should use definitions from <stdbool.h>.
Here is modified version:
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool convertArg(const char *arg, int *vp) {
char *p;
long num;
errno = 0;
num = strtol(arg, &p, 10);
if (errno || p == arg || *p != '\0' || num < INT_MIN || num > INT_MAX) {
*vp = 0;
return false;
} else {
*vp = (int)num;
return true;
}
}
int main(int argc, char *argv[]) {
int rowMap, colMap, snakeLength;
if (argc != 4) {
fprintf(stderr, "program needs 3 arguments\n");
return 1;
}
if (!converArg(argv[1], &rowMap) || rowMap < 5) {
fprintf(stderr, "invalid rowMap argument\n");
return 1;
}
if (!converArg(argv[2], &colMap) || colMap < 5) {
fprintf(stderr, "invalid colMap argument\n");
return 1;
}
if (!converArg(argv[3], &snakeLength) || snakeLength < 3 || snakeLength >= colMap) {
fprintf(stderr, "invalid snakeLength argument\n");
return 1;
}
[...]
}
A single character is not a string. A string is an array of characters with null termination at the end.
You should do something like this instead:
bool checkUserArg (const char* arg1, const char* arg2, const char* arg3);
const since we shouldn't modify the args. Now this function can call atoi using the parameters directly.
However atoi is a broken function by design that should never be used, because it does not have well-defined error handling. Using it directly on argv is dangerous. You should always use strtol instead of atoi, it's a safer and more powerful function.
Example:
#include <stdlib.h>
#include <stdbool.h>
int main (int argc, char *argv[])
{
if(argc != 4)
{
// error handling!
}
if(checkUserArg(argv[1], argv[2], argv[3]) == false)
{
/* error handling */
}
...
bool checkUserArg (const char* arg1, const char* arg2, const char* arg3)
{
const char* endptr;
...
rowMap = strtol(arg1, &endptr, 10); // 10 for decimal base
if(endptr == arg1) // if these compare equal, the conversion failed
{
return false;
}
...
return true;
}

My program only works when I declare an extra array

I'm building a simple shell for a class. There are two programs in my shell directory, called "alomundo" and "echo". "./alomundo" prints "Alo mundo!" to console, and ./echo executes the ubuntu echo with given args.
The thing is my program only works if I declare the char aux[15]. Notice I don't use it aux for nothing. Can anyone understand whats wrong?
An example input would be
./shell echo a b, alomundo, echo abc
The correct output is
a b
Alo mundo!
abc
The output when char aux[15] is not declared is just:
Alo mundo!
abc
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char aux[15]; // <---- GRRRR
int child; // will hold the childs PID after fork()
int i = 0; // counter to loop through this mains *argv[]
int t = 0; // auxiliar counter to loops
int arg_len; // will hold the length of each argument while the argument is being processed
int args = 0; // current number of arguments in the argv1 vector
int send = 0; // boolean to check if the command should be executed in the current loop or not
char *command; // string to hold the main command name
char *argv1[15]; // vector to hold the arguments passed to execve
for(i=1; i<argc; i++) {
arg_len = strlen(argv[i]);
argv1[args] = (char *) malloc(sizeof(char) * 25);
for(t=0; t<25; t++) {
argv1[args][t] = '\0';
}
if (argv[i][arg_len-1] == ',') {
argv[i][arg_len-1] = '\0';
send = 1;
}
else if (i == (argc-1)) {
send = 1;
}
if (args == 0) {
command = (char *) malloc(sizeof(char) * 255);
strcpy(command, "./");
strcpy(argv1[args], "./");
strcat(command, argv[i]);
}
strcat(argv1[args], argv[i]);
args++;
if (send) {
child = fork();
if (child == 0) {
argv1[args+1] = 0;
execve(command, &argv1[0], envp);
return 0;
}
else {
waitpid(child);
free(command);
for (t=0; t<args; t++) {
free(argv1[t]);
argv1[t] = NULL;
}
args = 0;
send = 0;
}
}
}
return 0;
}
waitpid(child) seems wrong. Try:
// ...
#include <sys/wait.h>
// ...
pid_t child;
int wstatus;
// ...
else {
wait(&wstatus);
envp is not declared. Try:
// ...
int main(int argc, char *argv[], char *envp[]) {
// ...
Off-by-one error in argv1 processing. Try:
// ...
if (child == 0) {
argv1[args] = 0;
execve(command, argv1, envp); // why use &argv1[0] ?
// ...
I think (3) is the culprit.
Compiling with different levels of optimisation (-O, etc) seems to affect whether or not the erroneous +1 causes a problem.

Trying to pass integer argument to thread

Hi I am having trouble passing an integer argument to a thread and calculation the factorial using that integer. Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <ctype.h>
void * factorial(void * number) {
int factorial = 1;
int counter = 1;
int newnum = *((int*)number);
printf("%d", newnum);
pthread_exit(NULL);
}
void * sumup( void * number) {
}
int main(int argc, char *argv[]) {
if(argc != 2) {
printf("Argument number error\n");
exit(1);
}
pthread_t thread1;
pthread_t thread2;
int i;
for(i = 0; i < argc; i++){
printf(argv[i]);
printf("\n");
}
int rc;
void * t = argv[1];
rc = pthread_create(&thread1, NULL, factorial, (void*)t );
if (rc != 0) {
printf("There was an error creating the thread\n");
exit(1);
}
pthread_exit(NULL);
exit(0);
}
Right now i am just trying to print the integer sent to get it working properly but here is my output:
./Task1
5
1162608693
It should printing out 5 instead of 1162608693
argv table stores pointers to characters. By doing:
void * t = argv[1];
int newnum = *((int*) t );
what you are trying to print is integer value of string "5". You are passing address of string:
'5' '\0'
casted to pointer to int, therefore you try to read integer value of first sizeof(int) bytes which yields:
5 0 [and you read sizeof(int)-2 bytes out of range]
which results in undefined behavior.
SOLUTION
To convert to integer a string passed as argument to your program use atoi or strtol which does better error checking.

incompatible pointer compiler error

I have this assignment where we expected to write a program that takes
a positive integer number as a command line argument and prints the
smallest prime number bigger than the given number.
The main function shouldn't be edited, however, you may create a
header file for defining needed functions.
So far this is what I came up with, I just can't find out what
is wrong with my program. Help is appreciated.
main function: I can't edit the main function, however, you can create a header
#include "slow-prime.h"
int main(int argc, char *argv[]) {
int num;
int nxt;enter code here
int ret = EXIT_FAILURE;
if (argc < 2) {
printf("error: missing command line argument\n");
goto ERROR;
if (get_number(argv[1], &num)) {
printf("error: %s not a number\n", argv[1]);
goto ERROR;
}
next_prime(num, &nxt);
printf("%d\n", nxt);
ret = EXIT_SUCCESS;
ERROR:
return ret;
}
}
needed functions are created in the slow-prime.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// define true and false
#define true 1
#define false 0
// check whether the numer is prime or mnot
int isPrime(int num){
if (num < 2) {
return false;
}
for (int i = 2; i <= num / i; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
// get number
void get_number(char *argv[], int num) {
num = atoi(argv[1]);
}
// loop through the numbers/ and pick the one
void next_prime(int num, int next){
for(int i = 2; i < 80; i++){
if (isPrime(i) == true){
next = i;
if (next > num) {
return exit(0);
}
}
}
}
Error Message:
error
You have:
void get_number(char *argv[], int num) {
and you are calling the function using:
if (get_number(argv[1], &num)) {
You are passing the wrong types for both arguments.
argv[1] is of type char*.
&num is of type int*.
I think you should to use:
void get_number(char *arg, int *num) {
and change the implementation slightly.
void get_number(char *arg, int *num) {
*num = atoi(arg);
}
Also, given that get_number returns void, you cannot use it in the conditional of an if statement. You'll need to change its return type to something else, an int perhaps. In that case, using atoi might not be appropriate. atoi returns 0 when it cannot convert the string to an int. If 0 a valid value for you, then atoi is not a good choice. However, you can use sprintffor all cases.
If 0 is not a valid number, you can use:
int get_number(char *arg, int *num) {
*num = atoi(arg);
return *num;
}
If 0 is a valid number, you can use:
int get_number(char *arg, int *num) {
return (sprintf(arg, "%d", num) == 1);
}

Passing array of FILE type to function = Segmentation fault

Following code passes a pointer to an array of type FILE, in to a function, causing a segmentation fault when the array is accessed (gcc, on Ubuntu 12.04 LTS).
In main, have the following code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
FILE **ptr_rdfile;
//Function declares
FILE ** open_files(int argc, char *argv[]);
int parse_files(FILE **ptr_rdfile[], int argc, char *argv[]);
//check for required input
if( argc < 2 )
{
printf( "Error - must enter at least one binary filename to read in.\n" );
return 1;
}
if( argc > 5 )
{
printf( "Error - maximum number of binary filenames %d.\n", MAX_FILES );
return 1;
}
//open files specified on cmd line
ptr_rdfile = open_files(argc, argv);
if( ptr_rdfile == NULL )
{
printf( "Exiting program\n" );
return 1;
}
//parse file contents into corresponding array of structs, print to stdout
if( parse_files(&ptr_rdfile, argc, argv) !=0 )
{
printf( "Parse Failed - Exiting program\n" );
return 1;
}
Function open_files is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
FILE ** open_files(int argc, char *argv[])
{
int i;
FILE **ptr_rdfile;
ptr_rdfile = malloc( sizeof(FILE *) * (argc-1));
if( ptr_rdfile == NULL )
{
printf("Error: Not enough memory\n");
getchar();
return NULL;
}
i=1;
for( i=1; i<argc; i++)
{
errno=0;
ptr_rdfile[i-1] = fopen(argv[i],"rb");
//printf( "ptr_rdfile[%d]:%p\n", (i-1), ptr_rdfile[i-1]);
if (!ptr_rdfile[i-1])
{
printf( "Unable to open file - is file name correct??? Errno = %d, %s.\n", errno, strerror(errno) );
return NULL;
}
}
return ptr_rdfile;
}
Function parse_files is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int parse_files(FILE **ptr_rdfile[], int argc, char *argv[])
{
unsigned int j;
signed int i;
struct prod_rec
{
int ver;
char type_code[20];
unsigned int unit_ID;
float price;
};
struct prod_rec prod[argc];
i=0;
for( i=0; i<argc-1; i++)
{
//printf( "fread: i = %d", i );
if (fread(&prod[i], sizeof(struct prod_rec), 1, *ptr_rdfile[i]) != 1)
{
printf( "error writing sturct: Errno = %d, %s.\n", errno, strerror(errno) );
}
}
}
Running with the following printf (and various iterations of) in main just before call to parse_file,
printf( "parse_files: ptr_rdfile = %p\n *ptr_rdfile = %p\n ptr_rdfile[0] = %p\n ptr_rdfile[1] = %p\n (void*)&ptr_rdfile[0] = %p\n (void*)&ptr_rdfile[1] = %p\n *ptr_rdfile[0] = %p\n *ptr_rdfile[1] = %p\n, **ptr_rdfile = %p\n **ptr_rdfile[1] = %p\n", ptr_rdfile, *ptr_rdfile, ptr_rdfile[0], ptr_rdfile[1], (void*)&ptr_rdfile[0], (void*)&ptr_rdfile[1], *ptr_rdfile[0], *ptr_rdfile[1], **ptr_rdfile, **ptr_rdfile );
shows shows the following:
ptr_rdfile = 0x804c008
*ptr_rdfile = 0x804c018
ptr_rdfile[0] = 0x804c018
ptr_rdfile[1] = 0x804c180
(void*)&ptr_rdfile[0] = 0x804c008
(void*)&ptr_rdfile[1] = 0x804c00c
Stepping into parse_files from main, with gdb, ptr_rdfile has the following:
(gdb) print ptr_rdfile[1]
$1 = (FILE **) 0xb7e52e55
(gdb) print *ptr_rdfile
$2 = (FILE **) 0x804c008
(gdb) print **ptr_rdfile
$3 = (FILE *) 0x804c018
(gdb) print ***ptr_rdfile
$4 = {_flags = -72539000, ...
print *ptr_rdfile[1]
$11 = (FILE *) 0x5b18c483
Looking beyond my thrashing around above, I think it appears the ptr_rdfile[0] came in ok, but not ptr_rdfile[1].
I also tried the following format for ptr_rdfile:
//function declare:
int parse_files(FILE ***ptr_rdfile, int argc, char *argv[]);
function call:
if( parse_files(&ptr_rdfile, argc, argv) !=0 )
Above caused same error.
Before I moved the above code into parse_files, I had that code in main, and it worked correctly with the same declare of ptr_rdfile, and the following call to fread:
if (fread(&prod[i], sizeof(struct prod_rec), 1, ptr_rdfile[i]) != 1)
Moving to a separate function, based on discussions I researched on this site re. passing arrays of pointers to functions, I came away with the above attempts, but I'm apparently missing something here...
Any debug suggestions appreciated.
Thank you.
UPDATE:
I had tried something like #user3629249 suggested, which had resulted in the following compile warning:
$ gcc -g -Wall -Wextra -o parsebin.out open_files.c parse_files.c parsebin.c
parsebin.c: In function ‘main’:
parsebin.c:41:3: warning: passing argument 1 of ‘parse_files’ from incompatible pointer type [enabled by default]
parsebin.c:17:7: note: expected ‘struct FILE **’ but argument is of type ‘struct FILE ***’
I just tried again with the following code (func declare, func call, and function code):
In main:
//func declare:
int parse_files(FILE **ptr_myfile, int argc, char *argv[]);
//func call:
if( parse_files(ptr_myfile, argc, argv) !=0 )
In parse_files:
int parse_files(FILE **ptr_myfile, int argc, char *argv[])
{
...
if (fread(&prod[i], sizeof(struct prod_rec), 1, ptr_myfile[i]) != 1)
Well, dang, I must have messed up something in that earlier attempt cuz the above seems to work ok. Whew, thank you user3629249 and everyone else for the kind help and guidance. With the help, I think I understand the pointer scheme here. Thank you again.

Resources