I can't understand what's happening with buf1 and pass in main(). I understand that after buffer overflow in gets(buf1):
Firstly (by input more then 15 characters), we are actually
changing calling frame for calling function main()
Secondly (if keep input more then 19 characters), then we will start change return address of calling function main().
But why after 16 character in gets (buf1) (123456789012345**6**) we get pass equal 54 (which is ASCII code for 6). We do not overflow pass variable so why we get this pass = 54?
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
int CommandInjection(char *varCommand)
{
char cat[] = "cat ";
char *command;
size_t commandLength;
commandLength = strlen(cat) + strlen(varCommand) + 1;
command = (char *) malloc(commandLength);
strncpy(command, cat, commandLength);
strncat(command, varCommand, (commandLength - strlen(cat)) );
system(command); //The function system is executed with the input entered by the user. The input can be dangerous.
return (0);
}
int main(void)
{
char buf1[15];
char varCommand[30];
bool pass = 0;
printf("\nEnter the password: \n(If you enter more than 15 characters you can break the security)\n");
gets(buf1); //Function that does not make bound checking
if(strcmp(buf1, "thepassword"))
{
printf ("\nWrong Password\n PASS=%d", pass);
if(pass==true)
printf ("\nHowever, there was memory corruption and you can enter to other part of the program\n pass=%d", pass);
}
else
{
printf ("\nCorrect Password\n");
pass = true;
}
if(pass == true)
{
// Don't must enter here if the password is wrong
printf ("\nEnter the file name (for example: text.txt; ls -l)\n");
gets(varCommand); //There is no input validation
CommandInjection(varCommand);
}
return 0;
}
Related
I am a C beginner trying to understand some nuances of scanf. This seems really trivial but I am struggling with reading inputs from stdin in "the correct way".
When terminal input is like string1 string3 string3 and I hit return, It works correctly and gives 3 in the result.
But when I give input like string1 and I hit return, I want the program to return 1 in the result variable and break the loop. Which doesn't happen. The program just expects me to enter more input into the terminal.
#include <stdio.h>
#define nameBufferLen 20
int main () {
int result;
char name[nameBufferLen];
char opens[nameBufferLen];
char closes[nameBufferLen];
while(1) {
result = fscanf(stdin,"%s %s %[^\n]s", name, opens, closes);
printf("%s|%s|%s| AND Result len is : %d\n", name, opens, closes, result);
if (result!=3) {
break;
}
}
return 0;
}
I am curious to know what could be the approach and regex that enables me to do this with scanf.
Here is the implementation that #Barmar mentioned:
#include <stdio.h>
#define nameBufferLen 19
#define str(s) str2(s)
#define str2(s) #s
int main (void) {
for(;;) {
char s[3 * (nameBufferLen + 1)];
if(!fgets(s, sizeof(s), stdin)) {
printf("err\n");
return 1;
}
char name[nameBufferLen+1] = { 0 };
char opens[nameBufferLen+1] = { 0 };
char closes[nameBufferLen+1] = { 0 };
int result = sscanf(s,
"%" str(nameBufferLen) "s"
"%" str(nameBufferLen) "s"
"%" str(nameBufferLen) "s",
name, opens, closes
);
if(result == 1)
break;
}
}
and example run:
a b c
a b
a
If you enter strings longer than 19 the excess will spill into the next variable. You can detect that with strlen() of each of the variables. Alternatively you can parse the string s with, for example, strpbrk().
hey guys i have looked around for a solution and tried everything i can think of im new to pointers and dynamic strings and i could really do with some help with problem. im currently learning c and i need to get the user to input a dynamic size for the string length . i need to make it so the users input can not be bigger then 100 . here's where i am at currently . i have the code booting but if i try set the size to let's say 5 i can still input way more chars into the string. cheers really appreciate any help .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
int maxSize = 100;
char *name = (char*) malloc (maxSize * sizeof (char));
int n;
char text1[]= ("input string size\n");
printf ("your string lenght is %d\n", strlen(name));
//getting size
n=intPrintScanner(text1);
printf ("your size is %d\n",n);
name = realloc (name, sizeof (char) * n);
//printing results
printf ("your string lenght is %d\n",strlen (name));
scanf("%s", name);
printf("your string is %s",name);
free(name);
fflush(stdin);
printf("press any key to close");
getchar();
return (0);
}
Bugs:
You never assign any data to name so it just contains garbage. You can't use strlen on it before you have stored valid data there either. You can store a string inside name by for example using strcpy.
When using realloc, there's no guarantee that the old pointer is the same as the returned pointer. Also, you need error handling. Implement it like this instead:
char* tmp = realloc (name, n);
if(tmp == NULL)
{
/* actual error handling here in case realloc fails */ }
}
name = tmp; // assign pointer to the new area only if allocation succeeded
fflush(stdin); is not well-defined, never use fflush on input streams. Instead you should discard unwanted line feed characters from stdin - which could be as trivial as an extra getchar() call just after reading something. Check out How to read / parse input in C? The FAQ for lots of general good advise regarding how to take input from stdin.
Cosmetic/style:
No need for parenthesis here: char text1[]= ("input string size\n");. All it achieves it to make the code look strange.
The correct form of main is int main (void). The int main() is obsolete style.
There is no need to wrap the expression passed to return in a parenthesis.
There is never a need to multiply something with sizeof (char), since sizeof (char) is by definition always 1 no matter system.
There is no need to cast the result of malloc.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
char* read_until(int fd, char end) {
int i = 0, size;
char c = '\0';
char* string = (char*)malloc(sizeof(char));
while (1) {
size = read(fd, &c, sizeof(char));
if (c != end && size > 0) {
string = (char*)realloc(string, sizeof(char) * (i + 2));
string[i++] = c;
} else {
break;
}
}
string[i] = '\0';
return string;
}
int main()
{
char *name;
int correct=0;
do{
write(1,"Put a name: ",strlen("Put a name: "));
name = read_until(STDIN_FILENO,'\n');
if(strlen(name) > 99){
write(1,"Error\n",strlen("Error\n"));
}else{
correct=1;
}
}while(correct != 1);
write(1,name,strlen(name));
free(name);
}
Try using write and read instead of printf and scanf, it is better for allocating dynamic memory, read and try to understand the read_until function, there are better ways to do main.
I am a beginner coder and writing a code that
asks for the user's name
check if the length is >15, if it is, it will ask the user to input a shorter name when they restart the program
if the length is valid, upper case the first letter of the entered name
display something like "Hi name"
However, The program keeps exiting no matter what I enter. Here is what I did :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
int main(void)
{
char str_name[15];
printf("Please enter your first name to begin: ");
scanf_s("%14s", str_name, _countof(str_name));
getchar();
if (strlen(str_name) > 15)
{
printf("The entered name is too long, please restart the program and try again.");
getchar();
exit(0);
}
else
{
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
getchar();
}
return 0;
}
You can simply use fgets() to read an input buffer.
char *fgets(char *str, int n, FILE *stream) reads a line from the specified stream and stores it in a buffer pointed to by str. It stops when either n-1 characters are read, the newline character is read, or the EOF is reached.
Some things to note about fgets():
Returns NULL on error.
Appends \n character at the end of buffer. Can replaced with \0 instead.
Buffer must be pointer to an array of characters. Either allocated on the stack or the heap.
Reads from stdin or FILE objects.
Here is some example code which shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NAMESTRLEN 16
int main(void) {
char str_name[NAMESTRLEN] = {'\0'};
size_t slen;
printf("Please enter your first name to begin: ");
if (fgets(str_name, NAMESTRLEN, stdin) == NULL) {
fprintf( stderr, "Error from fgets()\n");
return 1;
}
slen = strlen(str_name);
if (slen > 0 && str_name[slen-1] == '\n') {
str_name[slen-1] = '\0';
} else {
fprintf( stderr, "Too many characters\n");
return 1;
}
if (str_name[0] == '\0') {
fprintf( stderr, "No name entered\n");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
return 0;
}
There are several issues in your code:
The buffer size is too short: scanf() will not read more than 14 bytes into str_name, so it is not possible to test if the user entered a name longer than 15 characters.
toupper() should not be given a char argument because it is only defined for values of type unsigned char and the special value EOF. Cast the char as unsigned char.
your attempt at pausing before the terminal window closes fails on windows for long names because the extra characters entered by the user are still pending after the scanf_s(). getchar() reads one and returns immediately, and the program exits and the terminal window closes. Open the terminal window and run the program manually so it does not close automatically. With this approach, you can remove the getchar() and make the program more portable.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char str_name[17];
printf("Please enter your first name to begin: ");
if (scanf_s("%16s", str_name, sizeof(str_name))) {
printf("Premature end of file.\n");
return 1;
}
if (strlen(str_name) > 15) {
printf("The entered name is too long, please restart the program and try again.");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s\n", str_name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char str_name[16] = {0};
size_t len = 0;
int ch;
printf("Please enter your first name to begin: ");
while ((EOF != (ch = fgetc(stdin))) && (ch != '\n') && (len<sizeof(str_name)))
{
if (isalpha(ch))
{
str_name[len++] = ch;
}
}
if (len==sizeof(str_name))
{
fprintf(stderr, "Name too long\n");
}
else
{
str_name[len] = '\0';
printf ("Hi %c%s.\n", toupper(str_name[0]), &str_name[1]);
}
return 0;
}
As you can see I changed the input grabbing function. To check the input str len you should read byte per byte, not a whole string: fgetc do it. Using scanf with a format specifier like %14s it will return you always a trimmed string and you are not able to warn user about a too long Name.
Another point is to check that inserted chars are letters and not other kind of chars: isalpha do the job.
Moreover a c-string is composed by chars plus a null terminator ('\0', 0x00 ), so: a 15 chars string wants a 16 bytes array.
Lastly the code you wrote to mahe the first letter uppercase is completely wrong: you are passing to print a 1 char array and not a c string. My solution is one of many.
The problem is:
char Name[1]; // Declare a single element array.
Name[0] = toupper(str_name[0]); // Set it to the upper-case first letter.
// Try and print the nul-terminated string in Name - but there is no
// trailing zero (and the rest of the name is missing).
printf("Hi %s.\n", Name);
What you need is:
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
There is another problem that str_name[0] is a char value, and char may be signed. If you are using Windows-1252 for example, then Ä is 196, or as a signed char, -60. toupper takes an int, which must be positive¹. When -60 as a signed char is converted to int, you will get -60, and an out of range error. You need to write this as:
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
(Sorry.)
¹ Chrqlie points out the requirement is actually that the argument must be one of the values of unsigned char (which are - by definition - non-negative) or EOF (which is negative)"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void displayString (const char *sPtr);
void getString (char *[]);
int determinIfConvert (char);
int main ()
{
char originalString[11] = { 0 };
char convertedString[11];
getString (originalString);
displayString (originalString);
// this loop runs through the "originalString" to check for the char: 'a'
for (int i = 0; i < 11; i++) {
determinIfConvert (originalString[i]);
}
system ("pause");
}
void getString (char *a[]) // this function gets a string
{
printf ("enter 11 char string: \n");
scanf ("%s", a);
}
// this program displays the inputstring
void displayString (const char *sPtr)
{
for (; (*sPtr != '\0'); ++sPtr) {
printf ("%c", *sPtr);
}
}
int determinIfConvert (char *a)
{
if (a == 97) // this is a test condition. The goal is to
// check for all lowercase, but now i'm
// only entering "aaaaa"
{
printf ("Works"); // if it prints multiple"works"
// then i can continue my program
// but it only prints ONE "works" and freezes.
}
}
At the moment I have a problem with my For Loop in main() not finishing. The goal is to enter a string of characters, and then check for lowercase ones. This will be done with the function DeterminIfConvert(char). However, when I run through the loop element by element, it freezes after the second element. My test data is "aaaa" and it prints the "aaaa," so I know that my first two functions work just fine. I get to the loop, it goes through the first element, prints "works" and then freezes. :/
Multiple mistakes
void getString(char *a[])
should be
void getString(char a[])
Since you're sending the base address of an array of char, not an array of pointer to char
char *a[]; // array of pointer to char
char a[]; // array of char
int determinIfConvert(char *a)
should be
int determinIfConvert(char a)
Since you're sending a char, not a pointer to char
char * a; // pointer to char
char a; // char
NOTE:
Use the standard definition of main()
int main(void) //if no command line arguments.
If you are inputting an 11-char string, then you should be doing:
char originalString[12] = { 0 };
This is because you need 1 more character to store the null character '\0'.
That is probably why in your function getString(...), the pointer exceeds the array bounds and might invoke undefined behavior.
Finally, your function prototype for getString(...) should be
void getString(char a[]); //without the *
In addition to the other answers, you have several other areas where you can improve your code.
Avoid using magic numbers in your code (e.g. 11). Instead define a constant for the maximum characters in your string #define MAXC 11 or you can use an enum instead enum { MAXC = 11 };
As it currently sits, you do not protect against overflowing your 11 character array (which means your user can enter no more than 10 characters plus room for the nul-terminating character). To protect against the user entering something more than 10, you should use a field-width specifier with scanf:
scanf ("%10s", a);
That doesn't solve your problems with scanf. You must check the return every time to insure the expected number of conversions takes place, e.g.:
if (scanf ("%10s", a) != 1) {
fprintf (stderr, " -> error: invalid input.\n");
exit (EXIT_FAILURE);
}
That's better, but using %s, you cannot read a string containing whitespace, and you are still leaving a trailing '\n' in the input buffer. If the users enters "my dog", you store "my" only. To fix part of the problem you can use a format specifier of "%10[^\n]%*c". However, you must protect against an endless-loop if the user presses [Enter] without other input. To resolve all issues, and prevent leaving the trailing newline in the input buffer, you can use something like:
int getString (char *a) // this function gets a string
{
int c, rtn = 0;
printf ("enter string (10 char or less): ");
while ((rtn = scanf ("%10[^\n]%*c", a)) != 1) {
if (rtn == EOF)
break;
fprintf (stderr, " -> error: invalid input, try again..\n");
printf ("enter string (10 char or less): ");
/* flush input buffer - to avoid endless loop */
while ((c = getchar()) != '\n' && c != EOF) {}
}
return rtn;
}
All of which expose the difficulties using scanf for user input. A better approach may be to use fgets (or getline) to read the complete line of input.
Regardless whether you use scanf or fgets, etc.. you must take a bit of time and care in writing your input handlers to insure you try and cover all ways a user could muck up input. Below fgets is used just to present an alternative. You should also choose a return type that allows you to tell whether you have successfully received input or not. It might as well be a useful return such as the length of the input taken, etc..
The remainder of your level of pointer indirection issues have been addressed by other answers. Putting it all together, you could do something like:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 11
void displayString (const char *sPtr);
int getString (char *);
int determinIfConvert (char);
int main (void)
{
char originalString [MAXC] = "";
// char convertedString[MAXC] = ""; /* currently unused */
if (!getString (originalString)) {
fprintf (stderr, "error: getString failed.\n");
return 1;
}
displayString (originalString);
// this loop runs through the "originalString" to check for the char: 'a'
for (int i = 0; i < 11; i++) {
determinIfConvert (originalString[i]);
}
system ("pause");
return 0; /* main() is type 'int' and returns a value */
}
int getString (char *a) // this function gets a string
{
char *p = a;
int c;
size_t len = 0;
printf ("enter string (10 char or less): ");
for (;;) {
p = fgets (a, MAXC, stdin);
if (!p) break; /* handle [CTRL+D] */
if (*p == '\n') { /* handle empty str */
fprintf (stderr, " -> error: invalid input, try again..\n");
printf ("enter string (10 char or less): ");
continue;
}
/* trim newline/flush input buffer */
len = strlen (p);
if (len && a[len - 1] == '\n')
a[--len] = 0;
else /* user entered more than 10 chars */
while ((c = getchar()) != '\n' && c != EOF) {}
break;
}
return (int) len;
}
// this program displays the inputstring
void displayString (const char *sPtr)
{
for (; *sPtr; sPtr++) {
printf ("%c", *sPtr);
}
putchar ('\n');
}
int determinIfConvert (char a)
{
if (a == 97)
printf ("Works\n");
return 0;
}
Example Use/Output
$ ./bin/getdispstr
enter string (10 char or less): my dog has fleas
my dog has
Works
$ ./bin/getdispstr
enter string (10 char or less):
-> error: invalid input, try again..
enter string (10 char or less): my dog has fleas, my cat has none.
my dog has
Works
With CTRL+D (EOF)
$ ./bin/getdispstr
enter string (10 char or less): error: getString failed.
There are many ways to do this, this is just an example. Look over all the answers and let me know if you have questions.
This
char originalString[11] = { 0 };
followed by this
for (int i = 0; i < 11; i++)
{
determinIfConvert(originalString[i]);
}
is causing the problem. You see the array of char does not have elements post index 0. And yeah I believe what you are trying to attempt with
getString(originalString); seems like you want to get originalString from user input which is not correctly executed in your case.
You pass object of type char to a function accepting char*
char originalString[11] = { 0 };
determinIfConvert(originalString[i]);
int determinIfConvert(char *a)
A string is nothing but a null terminated set of characters, so if you wish to have 11 characters in you string, you should be allocating 12 bytes to your
array, ie you may change :
char originalString[11] = { 0 };
to
char originalString[12] = "";
/* Here is the string is empty but because you use double quotes
* compiler understands that you are initializing a string, so '\0' is auto
* appended to the end of it by the compiler to mark the end of the string.
*/
So is the case with convertedString[11] change it to
char convertedString[12] = "";
Change
void getString(char *a[]);
to
void getString(char a[]); //char *a is also fine
Change
int determinIfConvert(char *a)
to
int determinIfConvert(char a) // You wish to check a character
You may wish to replace
scanf("%s", a);
with
fgets(a,12,stdin);
because scanf can't check for overflows but fgets can. Here you can have up to 11 characters in the string. If an overflow occurs, the rest of the input is trimmed and '\0' is assigned to the 12th byte.
You may wish to use the islower function to check is a character is lowercase. So you may change
if (a == 97)
to
if (islower(a)) // check if a character is lowercase.
Remember you may need to include the string.h header to use islower()
so this is a code that reads 3 strings (orig // test1 // orig_copy) from 2 different files (firstline // secondline)**and calls divide_string to use strtok and take tokens and store them in **(token_orig // token_test // token_orig_copy),
--> this is the problem :
- when i put the three lines in main it does compile and take token from all 3 strings and "Done ." in the end.
-but when i try the next three lines (notice how i changed "HAHAHAH" to "HAHAHAHA", that little changing changes everything and make the program stops at printf("for the string number two :"); .
i hope i cleared the problem
PS : you can past copy the program so you can compile yourself easily
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char s[4] = " ,.";
int divide_string(char* thestring,char** destination)
{
int i=0;
char* token=strtok(thestring,s);
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
i++;
printf("the word %d is 'tokened' \n",i);
while(token!=NULL)
{
token =strtok(NULL,s);
if (token != NULL)
{
destination[i]=malloc(sizeof(token)+1);
strcpy(destination[i],token);
printf("the word %d is 'tokened' \n",i);
++i;
}
}
return i;
}
void main ()
{ //TRY THESE THREE LINES THAT WORKS<-----------------------------
char orig[]= "does work HAHAHAH";
char orig_copy[] = "does work HAHAHAH";
char test1[]="does work HAHAHAH";
// char orig[]= "doesnt work HAHAHAHA";
// char orig_copy[] = "doesnt work HAHAHAHA";
// char test1[]="doesnt work HAHAHAHA";
char *token_orig[81];
char *token_test[81];
char *token_orig_copy[81];
strcpy(orig_copy,orig);
printf("for string number one : \n");
int max_orig = divide_string(orig,token_orig);
printf("for string number two : \n");
int a = divide_string(orig_copy,token_orig_copy);
printf("for string number three : \n");
int max_test = divide_string(test1,token_test);
printf("%s-",token_orig[0]);
printf("%s-",token_orig[1]);
printf("%s-\n",token_orig[2]);
printf("%s-",token_orig_copy[0]);
printf("%s-",token_orig_copy[1]);
printf("%s-\n",token_orig_copy[2]);
printf("%s-",token_test[0]);
printf("%s-",token_test[1]);
printf("%s-\n",token_test[2]);
printf("done .");
return 0;
}
Since token is a pointer, sizeof(token) gives you the size of the pointer variable (4 or 8 bytes probably), NOT the number of chars in the string it points to! You want:
strlen(token) + 1
instead (+1 for the \0).
About the only time sizeof is useful for character strings is literals like:
sizeof("Hello World")