Avoid buffer underflow and overflow - c

My buffer size is 50 but I want to load my buffer only with 12 length characters
and again I have to load my buffer with different Character length but i am not able
to load buffer again, it is showing previous data with some garbage values.I tried to
remove garbage values by using hard coded value and again I reinitialized buffer to zero value but still I am getting same problem.
This code is for receiving data in C
{
if(PortRecvs(0,buff,sizeof(buff),1000)<0)
{
clrscr();
printf("Receive Fail..");
DelayMs(1000);
}
clrscr();
printf("Receive Buff:\n%s",buff);
DelayMs(1000);
if(PortRecvs(0,buff,12,1000)<0)
{
clrscr();
printf("Receive Fail..");
DelayMs(1000);
}
clrscr();
printf("Receive Buff:\n%s",buff);
DelayMs(1000);
}

There are too many clrscr() calls there for good debugging. The DelayMs() calls would drive me bonkers too (though some would deem driving me bonkers an unnecessary exercise).
It's a plausible inference that your PortRecvs() function returns the number of bytes read; you do not, however, ensure that printf() only prints the number of bytes that were read. It is likely that your code should look more like:
{
int nbytes;
if ((nbytes = PortRecvs(0, buff, sizeof(buff), 1000)) < 0)
{
printf("Receive Fail.\n");
DelayMs(1000);
}
else
printf("Receive Buff: [[%.*s]]\n", nbytes, buff); // Do not print if receive failed
DelayMs(1000);
if ((nbytes = PortRecvs(0, buff, 12, 1000)) < 0)
{
printf("Receive Fail.\n");
DelayMs(1000);
}
else
printf("Receive Buff: [[%.*s]]\n", nbytes, buff);
DelayMs(1000);
}
Note that this code does not print the buffer if the receive fails. It ensures that each message ends with a newline. It surrounds the data with markers [[ and ]] (choose your own if you don't like those — I often use << and >> instead) so that you can see more easily trailing blanks or embedded newlines. And, most importantly, it uses the %.*s conversion specification to print just the number of bytes that were received from PortRecvs().
Note that functions like PortRecvs() typically work with binary data and do not add a null terminator to the value received. The onus is on you to ensure that you handle data without null termination correctly.

Related

Incorrect fprintf results

In the code below, I am trying to read from a socket and store the results in a file.
What actually happens, is that my client sends a GET request to my server for a file.html. My server finds the file and writes the contents of it to the socket. Lastly my client reads the content from thread_fd and recreates the file.
For some reason the recreated file has less content than the original. I have located the problem to be some lines in the end, that are missing. When I use printf("%s", buffer) inside the while loop everything seems fine in STDOUT but my fprintf misses somewhat 3.000 bytes for a file of 81.000 bytes size.
#define MAXSIZE 1000
int bytes_read, thread_fd;
char buffer[MAXSIZE];
FILE* new_file;
memset(buffer, 0, MAXSIZE);
if((new_file = fopen(path, "wb+")) == NULL)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
fprintf(new_file, "%s", buffer);
if(bytes_read < MAXSIZE)
break;
memset(buffer, 0, MAXSIZE);
}
You read binary data from the socket that may or may not contain a \0 byte. When you then fprintf that data the fprintf will stop at the first \0 it encounters. In your case that is 3000 bytes short of the full file. If your file contains no \0 byte the fprintf will simply continue printing the ram contents until it segfaults.
Use write() to write the data back to the file and check for errors. Don't forget to close() the file and check that for errors too.
Your code should/could look like:
int readfile(int thread_fd, char *path)
{
unsigned int bytes_read;
char buffer[MAXSIZE];
int new_file;
if ((new_file = open(path, _O_CREAT|_O_BINARY,_S_IWRITE)) == -1) return -1;
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
if (write(new_file, buffer, bytes_read)!= bytes_read) {
close(new_file);
return -2;
}
}
close(new_file);
return 0;
}
There are a few issues with your code that can cause this.
The most likely cause is this :
if(bytes_read < MAXSIZE)
break;
This ends the loop when read returns less than the requested amount of bytes. This is however perfectly normal behavior, and can happen eg. when not enough bytes are available at the time of the read call (it's reading from a network socket after all). Just let the loop continue as long as read returns a value > 0 (assuming the socket is a blocking socket - if not, you'll also have to check for EAGAIN and EWOULDBLOCK).
Additionally, if the file you're receiving contains binary data, then it's not a good idea to use fprintf with "%s" to write to the target file. This will stop writing as soon as it finds a '\0' byte (which is not uncommon in binary data). Use fwrite instead.
Even if you're receiving text (suggested by the html file extension), it's still not a good idea to use fprintf with "%s", since the received data won't be '\0' terminated.
This worked!
ps: I don't know if I should be doing this, since I am new here, but really there is no reason for negativity. Any question is a good question. Just answer it if you know it. Do not judge it.
#define MAXSIZE 1000
int bytes_read, thread_fd, new_file;
char buffer[MAXSIZE];
memset(buffer, 0, MAXSIZE);
if((new_file = open(path, O_RDONLY | O_WRONLY | O_CREAT)) < 0)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
write(new_file, buffer, bytes_read);
close(new_file);

Program terminating without printing

Why does my while loop not print the print statements I want before terminating? None of my print statements print in the terminal when my program exits. I can't see any other places where the loop might exit.
while (1) {
int num_read;
// add the fd value into the fd_set value
FD_SET(sock_fd, &read_fds);
FD_SET(STDIN_FILENO, &read_fds);
// choose which fds to watch
select(sock_fd + 1, &read_fds, '\0', '\0', '\0');
if (FD_ISSET(STDIN_FILENO, &read_fds)) { //check whether the fd value is in the fd_set
num_read = read(STDIN_FILENO, buf, BUF_SIZE);
if (num_read == 0) {
printf("Print statement before terminating");
break;
}
buf[num_read] = '\0'; // Just because I'm paranoid
int num_written = write(sock_fd, buf, num_read);
if (num_written != num_read) {
perror("client: write");
printf("Print statement before terminating");
close(sock_fd);
printf("Print statement before terminating");
exit(1);
}
}
if (FD_ISSET(sock_fd, &read_fds)) { //the socket with the server
num_read = read(sock_fd, buf, BUF_SIZE);
buf[num_read] = '\0';
printf("%s", buf);
}
}
printf("Print statement before terminating");
close(sock_fd);
printf("Print statement before terminating");
return 0;
}
Printf() is a library function which uses library buffer. By default library uses lined buffer mechanism to print data on terminal. To make printf() to print messages immediately use "\n" in each string passed to printf().
When process terminates buffer is flushed that is why you got your prints.
Please read this.
https://stackoverflow.com/a/36573578/5694959
You can use what Monc suggested. i.e. adding '\n' in end of your statement. Alternatively you can use fflush(stdout). which also clears printf buffer and prints on stdout.
Monc and Devidas have provided clues for possible explanations, but unless you are programming to an ancient system, exit() should flush the pending output in stdout and any other streams.
A more likely explanation is you execute your program in an environment where stdout is not tied to the terminal or whatever serves to display output on your system. Some Windows based IDEs and some online systems have inadequate output handling and make it difficult to debug such problems.
Posting a complete program is necessary to let readers investigate if the problem has its source elsewhere in your program.

Using fgets() to read from different pipes, reading same message from both (should be different)

Im using fgets to read from 2 different pipes which have been sent 2 different messages thus should be returning 2 different messages. I have 2 pipes for each and closed the unneeded child end, all my fprintfs are flushed yet theyre both returning the same message then it just hangs. I have no idea why. Debugging didnt help me though i could have missed something.
int reader(FILE *output, int **pipes, char *getMessage) {
if(output == NULL) {
fprintf(stderr, "Player quit\n");
}
fgets(getMessage, sizeof(getMessage), output);
printf("mes %s\n", getMessage);
return 0;
}
Is my reader method (I am using the same buffer for both but i was using memset to try to clear it each time:
printf("test%c\n", roundDeck[deckPos]);
fprintf(input[pickturn], "yourturn %c\n", roundDeck[deckPos]);
fprintf(stdout, "yourturn %c\n", roundDeck[deckPos]);
fflush(input[pickturn]);
allHeldCards[pickturn][1] = roundDeck[deckPos];
roundDeck[deckPos] = '-';
//fclose(inPut);
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
printf("pt %d\n", pickturn);
reader(output[pickturn], pipes, getMessage);
if(msgProcess(pickturn, allIds, allFlags, allHeldCards,
getMessage, pipes, roundDeck,
deckPos, numPlayers, input) == 1) {
roundDeck[deckPos] = '-';
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
}
memset(getMessage, 0, 50);
the inputs were changing where they needed to do on the outside so maybe Im using memset incorrectly?
There is a problem here:
fgets(getMessage, sizeof(getMessage), output);
Since getMessage has type char *, then sizeof(getMessage) is sizeof(char *) which is likely to be 4 or 8. You read that many bytes from the "output" into getMessage.
Instead, you need to specify how many bytes to read. Even if you replace sizeof(getMessage) with your buffer size, that means it will block until all that number of bytes have been read, or the input is closed. Either your message protocol has to contain the length it expects to read, or you have to define your function to read until the input is closed or a certain delimiter occurs.
Then you have to make sure that the data you read contains a null-terminated string before you try and print it with %s or any other function that expects a string.
Not clear why your inputs are called output and your outputs are called input either.
It's hard to debug further without seeing more of a complete program than just these snippets

Getting characters past a certain point in a file in C

I want to take all characters past location 900 from a file called WWW, and put all of these in an array:
//Keep track of all characters past position 900 in WWW.
int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
printf("%d \n", Seek900InWWW);
if(Seek900InWWW < 0)
printf("Error seeking to position 900 in WWW.txt");
char EverythingPast900[appropriatesize];
int NextRead;
char NextChar[1];
int i = 0;
while((NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
EverythingPast900[i] = NextChar[0];
printf("%c \n", NextChar[0]);
i++;
}
I try to create a char array of length 1, since the read system call requires a pointer, I cannot use a regular char. The above code does not work. In fact, it does not print any characters to the terminal as expected by the loop. I think my logic is correct, but perhaps a misunderstanding of whats going on behind the scenes is what is making this hard for me. Or maybe i missed something simple (hope not).
If you already know how many bytes to read (e.g. in appropriatesize) then just read in that many bytes at once, rather than reading in bytes one at a time.
char everythingPast900[appropriatesize];
ssize_t bytesRead = read(WWW, everythingPast900, sizeof everythingPast900);
if (bytesRead > 0 && bytesRead != appropriatesize)
{
// only everythingPast900[0] to everythingPast900[bytesRead - 1] is valid
}
I made a test version of your code and added bits you left out. Why did you leave them out?
I also made a file named www.txt that has a hundred lines of "This is a test line." in it.
And I found a potential problem, depending on how big your appropriatesize value is and how big the file is. If you write past the end of EverythingPast900 it is possible for you to kill your program and crash it before you ever produce any output to display. That might happen on Windows where stdout may not be line buffered depending on which libraries you used.
See the MSDN setvbuf page, in particular "For some systems, this provides line buffering. However, for Win32, the behavior is the same as _IOFBF - Full Buffering."
This seems to work:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int WWW = open("www.txt", O_RDONLY);
if(WWW < 0)
printf("Error opening www.txt\n");
//Keep track of all characters past position 900 in WWW.
int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
printf("%d \n", Seek900InWWW);
if(Seek900InWWW < 0)
printf("Error seeking to position 900 in WWW.txt");
int appropriatesize = 1000;
char EverythingPast900[appropriatesize];
int NextRead;
char NextChar[1];
int i = 0;
while(i < appropriatesize && (NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
EverythingPast900[i] = NextChar[0];
printf("%c \n", NextChar[0]);
i++;
}
return 0;
}
As stated in another answer, read more than one byte. The theory behind "buffers" is to reduce the amount of read/write operations due to how slow disk I/O (or network I/O) is compared to memory speed and CPU speed. Look at it as if it is code and consider which is faster: adding 1 to the file size N times and writing N bytes individually, or adding N to the file size once and writing N bytes at once?
Another thing worth mentioning is the fact that read may read fewer than the number of bytes you requested, even if there is more to read. The answer written by #dreamlax illustrates this fact. If you want, you can use a loop to read as many bytes as possible, filling the buffer. Note that I used a function, but you can do the same thing in your main code:
#include <sys/types.h>
/* Read from a file descriptor, filling the buffer with the requested
* number of bytes. If the end-of-file is encountered, the number of
* bytes returned may be less than the requested number of bytes.
* On error, -1 is returned. See read(2) or read(3) for possible
* values of errno.
* Otherwise, the number of bytes read is returned.
*/
ssize_t
read_fill (int fd, char *readbuf, ssize_t nrequested)
{
ssize_t nread, nsum = 0;
while (nrequested > 0
&& (nread = read (fd, readbuf, nrequested)) > 0)
{
nsum += nread;
nrequested -= nread;
readbuf += nread;
}
return nsum;
}
Note that the buffer is not null-terminated as not all data is necessarily text. You can pass buffer_size - 1 as the requested number of bytes and use the return value to add a null terminator where necessary. This is useful primarily when interacting with functions that will expect a null-terminated string:
char readbuf[4096];
ssize_t n;
int fd;
fd = open ("WWW", O_RDONLY);
if (fd == -1)
{
perror ("unable to open WWW");
exit (1);
}
n = lseek (fd, 900, SEEK_SET);
if (n == -1)
{
fprintf (stderr,
"warning: seek operation failed: %s\n"
" reading 900 bytes instead\n",
strerror (errno));
n = read_fill (fd, readbuf, 900);
if (n < 900)
{
fprintf (stderr, "error: fewer than 900 bytes in file\n");
close (fd);
exit (1);
}
}
/* Read a file, printing its contents to the screen.
*
* Caveat:
* Not safe for UTF-8 or other variable-width/multibyte
* encodings since required bytes may get cut off.
*/
while ((n = read_fill (fd, readbuf, (ssize_t) sizeof readbuf - 1)) > 0)
{
readbuf[n] = 0;
printf ("Read\n****\n%s\n****\n", readbuf);
}
if (n == -1)
{
close (fd);
perror ("error reading from WWW");
exit (1);
}
close (fd);
I could also have avoided the null termination operation and filled all 4096 bytes of the buffer, electing to use the precision part of the format specifiers of printf in this case, changing the format specification from %s to %.4096s. However, this may not be feasible with unusually large buffers (perhaps allocated by malloc to avoid stack overflow) because the buffer size may not be representable with the int type.
Also, you can use a regular char just fine:
char c;
nread = read (fd, &c, 1);
Apparently you didn't know that the unary & operator gets the address of whatever variable is its operand, creating a value of type pointer-to-{typeof var}? Either way, it takes up the same amount of memory, but reading 1 byte at a time is something that normally isn't done as I've explained.
Mixing declarations and code is a no no. Also, no, that is not a valid declaration. C should complain about it along the lines of it being variably defined.
What you want is dynamically allocating the memory for your char buffer[]. You'll have to use pointers.
http://www.ontko.com/pub/rayo/cs35/pointers.html
Then read this one.
http://www.cprogramming.com/tutorial/c/lesson6.html
Then research a function called memcpy().
Enjoy.
Read through that guide, then you should be able to solve your problem in an entirely different way.
Psuedo code.
declare a buffer of char(pointer related)
allocate memory for said buffer(dynamic memory related)
Find location of where you want to start at
point to it(pointer related)
Figure out how much you want to store(technically a part of allocating memory^^^)
Use memcpy() to store what you want in the buffer

c recv() read until newline occurs

I'm working on writing a IRC bot in C, and have ran into a snag.
In my main function, I create my socket and connect, all that happy stuff. Then I have a (almost) infinite loop to read what's being sent back from the server. I then pass what's read off to a helper function, processLine(char *line) - the problem is, that the following code reads until my buffer is full - I want it to only read text until a newline (\n) or carriage return (\r) occurs (thus ending that line)
while (buffer[0] && buffer[1]) {
for (i=0;i<BUFSIZE;i++) buffer[i]='\0';
if (recv(sock, buffer, BUFSIZE, 0) == SOCKET_ERROR)
processError();
processLine(buffer);
}
What ends up happening is that many lines get jammed all together, and I can't process the lines properly when that happens.
If you're not familiar with IRC protocols, a brief summary would be that when a message is sent, it often looks like this: :YourNickName!YourIdent#YourHostName PRIVMSG #someChannel :The rest on from here is the message sent...
and a login notice, for instance, is something like this: :the.hostname.of.the.server ### bla some text bla with ### being a code(?) used for processing - i.e. 372 is an indicator that the following text is part of the Message Of The Day.
When it's all jammed together, I can't read what number is for what line because I can't find where a line begins or ends!
I'd appreciate help with this very much!
P.S.: This is being compiled/ran on linux, but I eventually want to port it to windows, so I am making as much of it as I can multi-platform.
P.S.S.: Here's my processLine() code:
void processLine(const char *line) {
char *buffer, *words[MAX_WORDS], *aPtr;
char response[100];
int count = 0, i;
buffer = strdup(line);
printf("BLA %s", line);
while((aPtr = strsep(&buffer, " ")) && count < MAX_WORDS)
words[count++] = aPtr;
printf("DEBUG %s\n", words[1]);
if (strcmp(words[0], "PING") == 0) {
strcpy(response, "PONG ");
strcat(response, words[1]);
sendLine(NULL, response); /* This is a custom function, basically it's a send ALL function */
} else if (strcmp(words[1], "376") == 0) { /* We got logged in, send login responses (i.e. channel joins) */
sendLine(NULL, "JOIN #cbot");
}
}
The usual way to deal with this is to recv into a persistent buffer in your application, then pull a single line out and process it. Later you can process the remaining lines in the buffer before calling recv again. Keep in mind that the last line in the buffer may only be partially received; you have to deal with this case by re-entering recv to finish the line.
Here's an example (totally untested! also looks for a \n, not \r\n):
#define BUFFER_SIZE 1024
char inbuf[BUFFER_SIZE];
size_t inbuf_used = 0;
/* Final \n is replaced with \0 before calling process_line */
void process_line(char *lineptr);
void input_pump(int fd) {
size_t inbuf_remain = sizeof(inbuf) - inbuf_used;
if (inbuf_remain == 0) {
fprintf(stderr, "Line exceeded buffer length!\n");
abort();
}
ssize_t rv = recv(fd, (void*)&inbuf[inbuf_used], inbuf_remain, MSG_DONTWAIT);
if (rv == 0) {
fprintf(stderr, "Connection closed.\n");
abort();
}
if (rv < 0 && errno == EAGAIN) {
/* no data for now, call back when the socket is readable */
return;
}
if (rv < 0) {
perror("Connection error");
abort();
}
inbuf_used += rv;
/* Scan for newlines in the line buffer; we're careful here to deal with embedded \0s
* an evil server may send, as well as only processing lines that are complete.
*/
char *line_start = inbuf;
char *line_end;
while ( (line_end = (char*)memchr((void*)line_start, '\n', inbuf_used - (line_start - inbuf))))
{
*line_end = 0;
process_line(line_start);
line_start = line_end + 1;
}
/* Shift buffer down so the unprocessed data is at the start */
inbuf_used -= (line_start - inbuf);
memmove(innbuf, line_start, inbuf_used);
}
TCP doesn't offer any sequencing of that sort. As #bdonlan already said you should implement something like:
Continuously recv from the socket into a buffer
On each recv, check if the bytes received contain an \n
If an \n use everything up to that point from the buffer (and clear it)
I don't have a good feeling about this (I read somewhere that you shouldn't mix low-level I/O with stdio I/O) but you might be able to use fdopen.
All you would need to do is
use fdopen(3) to associate your socket with a FILE *
use setvbuf to tell stdio that you want it line-buffered (_IOLBF) as opposed to the default block-buffered.
At this point you should have effectively moved the work from your hands to stdio. Then you could go on using fgets and the like on the FILE *.

Resources