I made the following code and i want to know if this is the best method of string input in C from security and bug free point of view.
#include <stdio.h>
#include <string.h>
#define MSG_LEN 25
int main(){
char msg[MSG_LEN];
int i;
while(1) {
putchar(':');
fgets(msg, MSG_LEN, stdin);
for(i = 0; i < strlen(msg); i++){
putchar(msg[i]);}
if (strlen(msg) == MSG_LEN - 1) putchar('\n');
while (strlen(msg) == MSG_LEN - 1) fgets(msg, MSG_LEN, stdin);
}
return 0;
}
Finally i found the solution for my question after bumping my head against the wall for some time. Anyone got any improvement for this code? I give most of credit to Simon Goater.
The main issues with user input in c are avoiding buffer overflows, which your code does, and draining/truncating the input that is longer than the given buffer allows. If you don't drain the remaining data, it can be read in again without blocking on the next fgets and give undesirable results. I've modified your code to loop so that the draining feature can be shown.
#include <stdio.h>
#include <string.h>
#define MSG_LEN 25
int main(){
char msg[MSG_LEN];
while(1) {
puts(":");
fgets(msg, MSG_LEN, stdin);
printf("%s", msg);
if (strlen(msg) == MSG_LEN - 1) printf("\n");
while (strlen(msg) == MSG_LEN - 1) fgets(msg, MSG_LEN, stdin);
}
return 0;
}
Related
I am working on a project including server-client communication.
Our code doesn't work all the time, sometimes it works perfectly. But sometimes we either get a timeout or our buffer doesn't work properly. Thats why we want to implement malloc(). Do you think this could help?
our code before malloc():
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define BUFFERSIZE 1024
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char buffer[BUFFERSIZE];
void resetBuffer(char *buffer) {
memset((buffer), '\0', strlen(buffer));
}
void receiveAnswer(int sock) {
resetBuffer(buffer);
size_t length;
bool x = true;
while (x) {
recv(sock, buffer, sizeof(buffer), 0);
length = strlen(buffer);
if (buffer[length-1] == '\n') {
x = false;
}
}
if (buffer[0] == '-') {
printf("Error: %s", buffer);
} else {
printf("%s\n ", buffer);
}
}
void sendResponse(int sock, char *message) {
resetBuffer(buffer);
strcpy(buffer, message);
bool x = true;
size_t length;
while(x) {
send(sock, buffer, strlen(buffer), 0);
length = strlen(buffer);
if (buffer[length - 1] == '\n') {
x = false;
}
}
printf("Client: %s\n", buffer);
}
int performConnection(int sock, char *gameID) {
receiveAnswer(sock);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, VERSION);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, gameID);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, "PLAYER \n");
sleep(1);
receiveAnswer(sock);
resetBuffer(buffer);
return 0;
}
Our code with malloc() doesn't work at all anymore:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define BUFFERSIZE 1024
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char *buffer;
void resetBuffer(char *buffer) {
memset((buffer), '\0', strlen(buffer));
}
void receiveAnswer(int sock) {
resetBuffer(buffer);
size_t length;
bool x = true;
while (x) {
recv(sock, buffer, sizeof(buffer), 0);
length = strlen(buffer);
if (buffer[length-1] == '\n') {
x = false;
}
}
if (buffer[0] == '-') {
printf("Error: %s", buffer);
} else {
printf("%s\n ", buffer);
}
}
void sendResponse(int sock, char *message) {
resetBuffer(buffer);
strcpy(buffer, message);
bool x = true;
size_t length;
while (x) {
send(sock, buffer, strlen(buffer), 0);
length = strlen(buffer);
if (buffer[length - 1] == '\n') {
x = false;
}
}
printf("Client: %s\n", buffer);
}
int performConnection(int sock, char *gameID) {
buffer = (char *)malloc(sizeof(char) * BUFFERSIZE);
receiveAnswer(sock);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, VERSION);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, gameID);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, "PLAYER \n");
sleep(1);
receiveAnswer(sock);
resetBuffer(buffer);
free(buffer);
return 0;
}
Any help is appreciated!
Best Enno
resetBuffer(buffer); fails as it attempts strlen(buffer) on uninitialized data. This invokes undefined behavior (UB) as strlen() expects a pointer to a string.
Instead:
// resetBuffer(buffer);
memset(buffer, 0, sizeof(char)* BUFFERSIZE);
// or simply
memset(buffer, 0, BUFFERSIZE);
this
void resetBuffer(char* buffer){
memset((buffer), '\0', strlen(buffer));
}
is undefined behavior. It depends of the previous contents of buffer (strlen looks for 0 terminator)
you need to pass in a length (not got from strlen)
Why are you bothering with the function reset_buffer() at all?
Each invocation appears immediately ahead of, for instance, strcpy(). The latter doesn't care if the buffer has be "reset". (Hopefully the buffer is large enough to hold what is being put into it.)
The last invocation appears immediately ahead of free(). Again, the content of the buffer is irrelevant.
More of a worry is that buffer[] has become *buffer... The sizeof(buffer) in the receive function is now telling recv there are 8 bytes available (the size of a pointer on your machine) to be filled, not the 1024 bytes of the "pre-malloc" version.
Change:
void receiveAnswer (int sock){
// ...
recv(sock, buffer, sizeof(buffer), 0);
to
recv(sock, buffer, BUFFERSIZE, 0);
This is not a MRE, so this "fix", while correct, may not be the entire solution.
buffer does not necessarily contain a proper C string, hence using strlen to compute the number of bytes received is incorrect: use the return value of recv instead. Similarly, the buffer clearing function should either get the length as an argument or use BUFFER_SIZE.
Whether buffer is defined as a global array of bytes or allocated from the heap before use does not matter, and your code has nothing to do with implementing the malloc function.
Im using fgets but also alarm so I have a way to execute code whilst my user is still entering input. What I want to do is get a count of the current number of characters the use has input since the last time they pressed enter.
this is my current code. Basically I want to be able to move the cursor back to the start position + current number of characters typed so it doesnt overwrite.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
int time_left = 25;
void moveTo(int row, int col)
{
printf("\x1b[%d;%df", row, col);
}
void move_cursor_to_input_pos()
{
moveTo(2, 15);
fflush(stdout);
}
void update_timer(int signum)
{
// check how many bytes are currently in the input buffer
int bytes_waiting;
int res = ioctl(1, FIONREAD, &bytes_waiting);
if (res == -1)
{
perror("ioctl");
exit(1);
}
if (time_left >= 0)
{
moveTo(0, 15);
fflush(stdout);
time_left -= 1;
if (time_left < 10)
printf("%d ", time_left + 1);
else
printf("%d", time_left + 1);
moveTo(3, 15);
fflush(stdout);
printf("res: %d, bytes: %d", res, bytes_waiting);
move_cursor_to_input_pos();
alarm(1);
}
}
int main()
{
moveTo(0, 7);
printf("Time: ");
moveTo(2, 7);
printf("Input: ");
moveTo(3, 7);
printf("Chars: ");
signal(SIGALRM, update_timer);
alarm(1);
while (time_left > 0)
{
while (1)
{
char input[100];
if (fgets(input, 100, stdin))
{
moveTo(10, 10);
printf("You entered: %s", input);
}
}
}
return 0;
};
Here you can see the timer is non blocking, however it always resets cursor back to the start of the line.
https://imgur.com/a/EBEroU7
if I had already typed 1234 then it updates the timer I want to put the cursor after the 4 not back one the 1. ioctl but I cant get it to do anything
Ive tried to use
Ok so this ended up solving my problem even if it isnt the exact way I thought I would need to solve it.
this escape code printf("\x1b[s"); saves the current cursor position
this escape code printf("\x1b[u"); restores the saved cursor position
So I can just do the save before I move to the timer location and restore after. Works perfectly
https://imgur.com/a/1FO4HNn
I have to create a program that asks from standard input a string and write in standard error the string previously written.
This is my program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
char *buffer = malloc(sizeof(char)*20);
int len = 0;
do {
len = read(STDIN_FILENO, buffer, 20);
if(len == -1)
write(STDERR_FILENO, "Error read\n", 10);
else
write(STDERR_FILENO, buffer, len);
} while(strncmp(buffer,"fine\n", 5));
free(buffer);
return 0;
}
The code works but I'm not satisfied..there is one problem:
The buffer is a 20char but I can insert more than 20 char...why? How I can limit the buffer to only 20 char?
The code works but I'm not satisfied..there is one problem: The buffer is a 20char but I can insert more than 20 char...why?
Because your program can't stop someone inputting more than 20 chars; all it can do is limit that it doesn't overflow the buffer which it already does - read() doesn't read more than the requested bytes. It only appears as if a read() call is reading more than size (20) but acutally read() reads only (upto) 20 chars and the rest is read in the next iteration.
No matter what method you use to read input and/or increase buffer size, this problem of "extra input" is always going to be there.
What you can do instead is check if if len is 20 and buffer[19] is not \n:
else {
write(STDERR_FILENO, buffer, len);
/* Read out the left over chars. */
if (len == 20 && buffer[19] != '\n') {
char c;
do {
read(STDIN_FILENO, &c, 1); /* left out the error checking */
} while (c != '\n');
}
Or increase the buffer size, say, to 512 bytes and then only look at the first 20 bytes that you're interested in.
Note: Add error checking for all read() and write() calls.
You're not allocating enough memory for your buffer. You always need 1 more to store the NUL terminating character. And you also need to remember to add that NUL character to the end of the string read in by read as it won't do it for you.
When you get an error, you should exit the loop.
#define BUF_SIZE (20)
int main() {
char *buffer = malloc(sizeof(char)*(BUF_SIZE+1));
int len = 0;
do {
len = read(STDIN_FILENO, buffer, BUF_SIZE);
if(len == -1) {
write(STDERR_FILENO, "Error read\n", 10);
break;
} else {
buffer[len]='\0';
write(STDERR_FILENO, buffer, len);
}
} while(strncmp(buffer,"fine\n", 5));
free(buffer);
return 0;
}
You'll probably also find that the strncmp(buffer,"fine\n", 5) isn't going to work as you'd need to process the read in string to handle lines of input as read will happily read in multiple lines at a time (assuming they all fit in the buffer size).
I am learning C and I have been trying to read a file and print what I just read. I open the file and need to call another function to read and return the sentence that was just read.
My function will return 1 if everything went fine or 0 otherwise.
I have been trying to make it work for a while but I really dont get why I cant manage to give line its value. In the main, it always prints (null).
The structure of the project has to stay the same, and I absolutely have to use open and read. Not fopen, or anything else...
If someone can explain it to me that would be awesome.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define BUFF_SIZE 50
int read_buff_size(int const fd, char **line)
{
char buf[BUFF_SIZE];
int a;
a = read(fd, buf, BUFF_SIZE);
buf[a] = '\0';
*line = strdup(buf);
return (1);
}
int main(int ac, char **av)
{
char *line;
int fd;
if (ac != 2)
{
printf("error");
return (0);
}
else
{
if((fd = open(av[1], O_RDONLY)) == -1)
{
printf("error");
return (0);
}
else
{
if (read_buff_size(fd, &line))
printf("%s\n", line);
}
close(fd);
}
}
Here:
char buf[BUFF_SIZE];
int a;
a = read(fd, buf, BUFF_SIZE);
buf[a] = '\0';
if there are more characters than BUFF_SIZE available to be read, then you will fill your array entirely, and buf[a] will be past the end of your array. You should either increase the size of buf by one character:
char buf[BUFF_SIZE + 1];
or, more logically given your macro name, read one fewer characters:
a = read(fd, buf, BUFF_SIZE - 1);
You should also check the returns from strdup() and read() for errors, as they can both fail.
read(fd, buf, BUFF_SIZE); //UB if string is same or longer as BUFF_SIZE
u need +1 byte to store 0, so use BUFF_SIZE - 1 on reading or +1 on array allocation...also you should check all returned values and if something failed - return 0
Keep it simple and take a look at:
https://github.com/mantovani/apue/blob/c47b4b1539d098c153edde8ff6400b8272acb709/mycat/mycat.c
(Archive form straight from the source: http://www.kohala.com/start/apue.tar.Z)
#define BUFFSIZE 8192
int main(void){
int n;
char buf[BUFFSIZE];
while ( (n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
exit(0);
}
No need to use the heap (strdup). Just write your buffer to STDOUT_FILENO (=1) for as long as read returns a value that's greater than 0. If you end with read returning 0, the whole file has been read.
I'm currently doing my assignment and it's compulsory to use C-Free 5.0. Just need your help to solve this piece of puzzle. I want to implement a time limit for the user to input an answer before it expires. I've tried this code but it got block at scanf() function. Is there any other method like an unblocking input or something. I've tried to implement '#include <sys/select.h>' but this program doesn't have that library.
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
int main()
{
char st[10];
printf ("Please enter a line of text : ");
time_t end = time(0) + 5; //5 seconds time limit.
while(time(0) < end)
{
scanf("%s", &st);
if(st != NULL)
{
printf ("Thank you, you entered >%s<\n", st);
exit(0);
}
}
main();
}
Here is an example program that shows how you can use O_NONBLOCK flag on a stdin file descriptor.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define INPUT_LEN 10
int main()
{
printf ("Please enter a line of text : ");
fflush(stdout);
time_t end = time(0) + 5; //5 seconds time limit.
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
char answer[INPUT_LEN];
int pos = 0;
while(time(0) < end)
{
int c = getchar();
/* 10 is new line */
if (c != EOF && c != 10 && pos < INPUT_LEN - 1)
answer[pos++] = c;
/* if new line entered we are ready */
if (c == 10)
break;
}
answer[pos] = '\0';
if(pos > 0)
printf("%s\n", answer);
else
puts("\nSorry, I got tired waiting for your input. Good bye!");
}
Since you have fcntl.h try setting stdin to non-blocking. It's not pretty (active waiting), but if you do not have select then this is the easyest way to go:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
// get stdin flags
int flags = fcntl(0, F_GETFL, 0);
if (flags == -1) {
// fcntl unsupported
perror("fcntl");
return -1;
}
// set stdin to non-blocking
flags |= O_NONBLOCK;
if(fcntl(0, F_SETFL, flags) == -1) {
// fcntl unsupported
perror("fcntl");
return -1;
}
char st[1024] = {0}; // initialize the first character in the buffer, this is generally good practice
printf ("Please enter a line of text : ");
time_t end = time(0) + 5; //5 seconds time limit.
// while
while(time(0) < end // not timed out
&& scanf("%s", st) < 1 // not read a word
&& errno == EAGAIN); // no error, but would block
if (st[0]) // if the buffer contains something
printf ("Thank you, you entered >%s<\n", st);
return 0;
}
A remark to your code: if (st != NULL) will always be satisfied since st is a stack pointer.