Newbie: bug in argument casting to digit

J

Jobs'R'Us

Hello,

I have a bug in a simple validation for an argument that must be an
int from 1 to 99.

If in the command prompt I enter the following, the program behaves
perfectly:
programname filename.txt doghouse 5

If in the command prompt I enter the following, the program still
behaves perfectly, it explains that the digit ("5all") is incorrect:
programname filename.txt doghouse 5all

The bug is, if I enter the following, the program incorrectly accepts
"5a" and interprets it exactly like like "5":
programname filename.txt doghouse 5a

Someone kindly point out what I'm doing wrong?

Also, I would like to know why gcc gives me a warning about the line
with atoi() being used implicitely?

The code:

// too much in a hurry to remove the ones that do not apply to this
code snippet:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

//arguments expected: <a file name> <a string> <a small int>
int main(int argc, char *argv[])
{

FILE *file;
char searchedword[50];
int searcheddigit;

if(argc != 4)
{
printf("Sorry, wrong number of parameters...\n\n");
printf("Usage: blah blah blah\n\n");
return 1;
}
else if(strlen(argv[2]) > 50)
{
printf("Sorry, the searched word is too long...\n\n");
printf("Usage: blah blah blah\n\n");
return 2;
}
else if(strlen(argv[3]) > 2)
{
printf("Sorry, the number is wrong, must be a digit from 1 to
99...\n\n");
printf("Usage: blah blah blah\n\n");
return 3;
}
else
{
file = fopen(argv[1], "r");

if(file == NULL)
{
printf("Sorry, can't open the indicated file.\n\n");
printf("Usage: blah blah blah\n\n");
return 4;
}
else
{
strcpy(searchedword,argv[2]);
searcheddigit = atoi(argv[3]);

if((searcheddigit < 1) || (searcheddigit > 99))
{

printf("Sorry, the number of words to the left and to the right,
needs to be a positive digit between 1 and 99...\n\n");
printf("Usage: blah blah blah\n\n");
return 5;
}
/* Program continues... */

Thank you for the help and please keep your explanations geared for a
seven year old!
Kirst
 
J

Jens.Toerring

Jobs'R'Us said:
I have a bug in a simple validation for an argument that must be an
int from 1 to 99.
If in the command prompt I enter the following, the program behaves
perfectly:
programname filename.txt doghouse 5
If in the command prompt I enter the following, the program still
behaves perfectly, it explains that the digit ("5all") is incorrect:
programname filename.txt doghouse 5all
The bug is, if I enter the following, the program incorrectly accepts
"5a" and interprets it exactly like like "5":
programname filename.txt doghouse 5a

Because you only check that the input string isn't more than 2 chars
long but don't test if the char(s) is/are digit(s). Use either the
isdigit() function on all the chars of the string or strtol() and
test if the second argument after the call points to a '\0' char -
otherwise there were non-digits in the input string.
Also, I would like to know why gcc gives me a warning about the line
with atoi() being used implicitely?

No idea, atoi() is declared in <stdlib.h> which you already include.

Regards, Jens
 
C

CBFalconer

Jobs'R'Us said:
.... snip ...

If in the command prompt I enter the following, the program still
behaves perfectly, it explains that the digit ("5all") is
incorrect: programname filename.txt doghouse 5all

The bug is, if I enter the following, the program incorrectly
accepts "5a" and interprets it exactly like like "5":
programname filename.txt doghouse 5a

.... snip ...

*** following edited to remain within 65 char margine ***
else if(strlen(argv[3]) > 2)
{
printf("Sorry, the number is wrong, "
"must be a digit from 1 to 99...\n\n");
printf("Usage: blah blah blah\n\n");
return 3;
}
else

What are you testing? Just that the string length is in the range
0 to 2. As you have found out, this does not guarantee the
conditions you want.

Look into the strto* functions, which return error conditions, and
allow you to check what terminated the numerical field. Once you
have extracted a value, you can check that the string terminator
was a '\0', and thus that there was no extra cruft on the supplied
value, and that the value itself is in some range.
 
A

Al Bowers

Jobs'R'Us said:
Hello,

I have a bug in a simple validation for an argument that must be an
int from 1 to 99.

If in the command prompt I enter the following, the program behaves
perfectly:
programname filename.txt doghouse 5

If in the command prompt I enter the following, the program still
behaves perfectly, it explains that the digit ("5all") is incorrect:
programname filename.txt doghouse 5all

The bug is, if I enter the following, the program incorrectly accepts
"5a" and interprets it exactly like like "5":
programname filename.txt doghouse 5a

Someone kindly point out what I'm doing wrong?
else if(strlen(argv[3]) > 2)
You are only checking the length of the string. You also
need to test to make sure the characters of the string are
digits.
Try:
else if(strlen(argv[3]) > 2 || !isdigit((unsigned char)argv[3][0] ||
!isdigit((unsigned char)argv[3][1])
{
printf("Sorry, the number is wrong, must be a digit from 1 to
99...\n\n");
printf("Usage: blah blah blah\n\n");
return 3;
}
/* Program continues... */

You also have the option of using of of the strto* functions
provided by the Standard. With this program, you
might use function strtoul to validate that the string is valid.
Example of using strtoul is function ValidUINT defined below.

#include <stdlib.h>
#include <limits.h>
#include <errno.h>


int ValidUINT(const char *src, unsigned *result)
{
char *s;
unsigned long tmp;

errno = 0;
tmp = strtoul(src,&s,10);
if(s == src || errno == ERANGE || *s != '\0' ||
tmp > UINT_MAX) return 0;
if(result) *result = tmp;
return 1;
}

You can use this function as follows;

change seracheddigit to
unsigned searcheddigit;

else if(!ValidUINT(argv[3],&searchddigit) || searcheddigit > 99)
/* Not valid or greater than 99 */
else /* Use searcheddigit. It is in range */
 
B

Barry Schwarz

Hello,

I have a bug in a simple validation for an argument that must be an
int from 1 to 99.

If in the command prompt I enter the following, the program behaves
perfectly:
programname filename.txt doghouse 5

If in the command prompt I enter the following, the program still
behaves perfectly, it explains that the digit ("5all") is incorrect:
programname filename.txt doghouse 5all

The bug is, if I enter the following, the program incorrectly accepts
"5a" and interprets it exactly like like "5":
programname filename.txt doghouse 5a

Someone kindly point out what I'm doing wrong?

Also, I would like to know why gcc gives me a warning about the line
with atoi() being used implicitely?

The code:

// too much in a hurry to remove the ones that do not apply to this
code snippet:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

//arguments expected: <a file name> <a string> <a small int>
int main(int argc, char *argv[])
{

FILE *file;
char searchedword[50];
int searcheddigit;

if(argc != 4)
{
printf("Sorry, wrong number of parameters...\n\n");
printf("Usage: blah blah blah\n\n");
return 1;
}
else if(strlen(argv[2]) > 50)

If strlen returns 50, you accept the data.
{
printf("Sorry, the searched word is too long...\n\n");
printf("Usage: blah blah blah\n\n");
return 2;
}
else if(strlen(argv[3]) > 2)
{
printf("Sorry, the number is wrong, must be a digit from 1 to
99...\n\n");
printf("Usage: blah blah blah\n\n");
return 3;
}
else
{
file = fopen(argv[1], "r");

if(file == NULL)
{
printf("Sorry, can't open the indicated file.\n\n");
printf("Usage: blah blah blah\n\n");
return 4;
}
else
{
strcpy(searchedword,argv[2]);

Then you copy the 51 chars (50 that strlen reported + the '\0') to
searchedword which has room for only 50. Undefined behavior.
searcheddigit = atoi(argv[3]);

if((searcheddigit < 1) || (searcheddigit > 99))
{

printf("Sorry, the number of words to the left and to the right,
needs to be a positive digit between 1 and 99...\n\n");
printf("Usage: blah blah blah\n\n");
return 5;
}
/* Program continues... */

Thank you for the help and please keep your explanations geared for a
seven year old!
Kirst



<<Remove the del for email>>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top