reading from non-blocking named pipe gives EFAULT (14) in Ubuntu - c

The code below returns EFAULT (errno == 14). I would appreciate help figuring out why.
I've also tried to implement the code using select() but still got the same error code.
I've got very similar code running on Python with no issues.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int read_fail1(int fd)
{
int n;
char buf[500];
for (;;)
{
buf[strlen(buf)-1] = 0;
n = read(fd, buf, strlen(buf)-1);
if (n == -1)
{
if (errno == EFAULT)
{
fprintf(stderr, "EFAULT");
return 42;
}
}
else if (n > 0)
{
fprintf(stderr, "%s", buf);
}
}
}
int main(int argc, const char *argv[])
{
const char *myfifo = "pipeMUD";
mkfifo(myfifo, 0666);
int fd = open(myfifo, O_RDWR | O_NONBLOCK);
if (fd <= 0)
return 42;
read_fail1(fd);
return 0;
}
POST ANSWER EDIT:
As mentioned in the post linked below, if an invalid address is passed to the kernel, it throws the EFAULT. I guess that on Linux, based on the above code, passing a 0 length count parameter to read() will also cause EFAULT to be retured.
unix socket error 14: EFAULT (bad address)

This line:
buf[strlen(buf)-1] = 0;
buf if a local variable, and thus is not initialized in C.
strlen looks for '\0' (null character) value, and thus will give unpredictable result on uninitialized array.
But, as long as you declare buf statically as you do, you can use sizeof instead.
Though it would be a better practice to use a macro instead:
#define READ_BUFFER_SIZE 500
char buf[READ_BUFFER_SIZE];
n = read(fd, buf, READ_BUFFER_SIZE - 1);

Related

Why am I getting free(): invalid pointer?

I am currently reading Linux System Programming by Robert Love and am stuck on the read() example that takes care of all five error cases. I am getting an free(): invalid pointer error. I am assuming that it has something to do with advancing the buffer in case the read is not finished.
It works if I store the offset and return the pointer to its original position. This is not mentioned in the book. Is there a better approach?
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int main()
{
int fd;
if( (fd = open("someFile.txt", O_CREAT | O_WRONLY | O_TRUNC, 0664)) < 0)
perror("open for write");
char * text = "This is an example text";
write(fd, text, strlen(text));
close(fd);
if( (fd = open("someFile.txt", O_RDONLY)) < 0)
perror("open");
char *buf;
if( (buf = (char *) calloc(50, sizeof(char))) == NULL )
perror("calloc");
int len = 50;
ssize_t ret;
/* If I store the offset in a variable it works */
off_t offset = 0;
while (len != 0 && (ret = read (fd, buf, len)) != 0) {
if (ret == -1) {
if (errno == EINTR)
continue;
perror ("read");
break;
}
len -= ret;
buf += ret;
offset += ret; // Offset stored here
}
if( close(fd) == -1 )
perror("close");
buf -= offset; // Here I return the pointer to its original position
free(buf);
return 0;
}
There are multiple bugs in this code.
First, perror is not being used correctly, as it only prints an error -- there should also be code here to abort on errors, so subsequent code doesn't try to use results from operations that failed.
Secondly, only the result from calloc can be given to free. The result is saved in buf, but then later code changes the value of buf and tries to free the changed value. Storing the changes in offset should fix this, but this is an error prone solution at best. If you have multiple code paths that modify buf, you have to make sure every one of those also modify offset in the same way.
A better approach would be to not modify buf, and instead use a second pointer variable in the read that is initialized to the value of buf and then gets modified after each read.
As pointed out, the number given to calloc is different than the number len is initialized to. This is a perfect example of misuse of a magic number. Both the 20 and 50 should be replaced with the same symbol (variable or constant or #define) so that you don't get a buffer overrun error.

Using of a system call in c

I would like to create a program name patch witch recives a FILENAME and a string.In the file there is the string 'allis'.I need to replace each time the string 'allis' appears in the text with the string I recieved as an input.
I need to use only system call and not the standat libary.
This is an example code on how the code should look like(this just example of the structure it is not the mission, the code writes "allis" word instead of "hello world"):
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc , char* argv[], char* envp[])
{
char buf[6];
int fd = open(argv[1],O_WRONLY,0777);
if (fd == -1)
exit(1);
write(fd,"hello world!\n",13);
close(fd);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
exit(1);
read(fd,buf,5);
buf[5]='\0';
close(fd);
fd = open(argv[1],O_WRONLY,0777);
if (fd == -1)
exit(1);
write(fd,"allis",5);
close(fd);
return 0;
}
I need to use the system call lseek but I dont know how I should use it because I dont know where in the text 'allis' is located and what happens if the string i get as an input is bigger than 'allis' I need to move all the text to the right or something because I will override other text.
EDIT:
I wrote a code which check char by char (instead of allis its shira and it replace it with sergay)It actually worked. and than I tried to change the code to work with argv[1] and argv[2] as needed and it didnt work I revert back to the code that originally worked for me and its just doesnt work now!! The problem is that the buf doesnt take 5 character (only 1)
and believe me or not it worked before.
The code :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define SYS_WRITE 1
#define STDOUT 1
extern int system_call();
int main(int argc , char* argv[], char* envp[])
{
char buf[5];
int index1=0,index2=0;//the index of the file
int fd1;
int fd = open("file.txt", O_RDONLY);
if (fd == -1)
return 1;
fd1 = open("copytext.txt",O_WRONLY,0777);
if (fd1 == -1)
return 1;
int i =0;
while (fd!=-1){//while there is still info to read
printf("enter the %d loop\n",i);
i++;
if(read(fd,buf,5) == 0 ) break;//read 5 chars from the file //buf[5]='\0';//!! not sure about this
printf("the buffer is: %s\n",buf);
if ((buf[0]=='s') && (buf[1]=='h') && (buf[2]=='i') && (buf[3]=='r') && (buf[4]=='a'))// if (strcmp(buf,"shira")==0)//if we found shira
{
write(fd1,"sergay",6);//replace shira
index2 = index2 + 6;
if(lseek(fd1,index2,SEEK_SET) < 0) break;
index1 = index1 + 5;//size of shira
if(lseek(fd,index1,SEEK_SET) < 0) break;
}
else {//we did not find shira;
write(fd1,buf,1);//write only one
index2++;
if(lseek(fd1,index2,SEEK_SET) < 0) break;
index1++;
if(lseek(fd,index1,SEEK_SET) < 0) break;
}
}
printf("get out of the loop\n");
char buffer[index2];
fd1 = open("copytext.txt", O_RDONLY);
if (fd1 == -1)
return 1;
if(lseek(fd1,0,SEEK_SET) < 0) return 1;
if(read(fd1,buffer,index2) == 0 ) return 1;
fd = open("file.txt",O_WRONLY,0777);
if (fd == -1)
return 1;
if(lseek(fd,0,SEEK_SET) < 0) return 1;
write(fd,buffer,index2);
close(fd);
close(fd1);
return 0;
}

How to clean a buffer filled using read() and continue reading at the same buffer?

I have a project for the university where I have to implement an Iterative server.
The server uses a protocol given by the professor and in a few words the client has to send a message in a specific form and my server has to make some parsing in order to save some data in a global struct.
I use the function read() in order to receive the message and store it in a char array with fixed size. My problem is that the message some times might be bigger than the size of the buffer I use to store it. NOTE: I am not able to send the size of the message first in order to bypass this problem.
I would like to know if there is a way to make this happen.
Bellow is some of the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "keyvalue.h"
#include <errno.h>
int main ( int argc, char *argv[])
{
char keyvaluebuffer[4096];
int num;
//socket()
//bind()
//listen()
while(1)
{
//accept()
while((num = read(acceptfd, keyvaluebuffer, 4096) ) > 0 )
{
//At this point I use the keyvaluebuffer to parse it and store the data.
}//while (read > 0) end
if (num < 0){close(accept);}
close(accept);
}//while(1) end
close(socket);
}//main end
If the message is larger than the buffer size, then you will at least need to store the part of the message that has been retrieved before reading more of the message. One option would be to dynamically allocate a message buffer. After reading part of the message into the static buffer it is copied into the dynamic message buffer. If the dynamic message buffer has been filled, it is reallocated.
In the example code below, buffer[] is an array that holds BUF_SIZE chars. msg is a pointer to dynamically allocated memory, and initially points to BUF_SIZE bytes. msgbuff_sz keeps track of the size of the dynamic message allocation, while msg_sz keeps track of the actual message size. After each call to read(), the contents of buffer[] are copied to the appropriate location in msg, and msg_sz is updated. If the message size is the same as the message buffer size, the message buffer msg is reallocated. This continues until the end-of-file condition is reached (or until read() returns an error value).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 4096
int main(void)
{
int fd = open("message.txt", O_RDONLY);
if (fd < 0) {
perror("Unable to open file");
exit(EXIT_FAILURE);
}
char buffer[BUF_SIZE];
char *msg = malloc(BUF_SIZE);
size_t msgbuff_sz = BUF_SIZE;
size_t msg_sz = 0;
if (msg == NULL) {
perror("Buffer allocation error");
exit(EXIT_FAILURE);
}
ssize_t ret_val;
while ((ret_val = read(fd, buffer, sizeof buffer)) > 0) {
memcpy(msg + msg_sz, buffer, ret_val);
msg_sz += ret_val;
if (msg_sz == msgbuff_sz) {
msgbuff_sz += BUF_SIZE;
char *tmp = realloc(msg, msgbuff_sz);
if (tmp == NULL) {
perror("Buffer reallocation error");
exit(EXIT_FAILURE);
}
msg = tmp;
}
}
if (ret_val < 0) {
perror("Unable to read file");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < msg_sz; i++) {
putchar(msg[i]);
}
putchar('\n');
free(msg);
return 0;
}

How to properly error trap read in c to get byte number from a file descriptor

I am currently writing a small dummy program to try and get the hang of properly using the read in c. I made a small function called readdata to read from the file descriptor and store in a buffer then return the number of bytes read. My problem is I am trying to correctly error handle and trap things so that there is no buffer overflow but I keep doing something from.
Here is the tester:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 10
int readdata(int fd, char *buf, int bsize);
int main(void) {
char buf[BUFSIZE];
int returnval;
int length;
returnval = readdata(STDIN_FILENO, buf, BUFSIZE);
printf("%s",buf);
length = strlen(buf);
fprintf(stderr,"The return value is %d\n", returnval);
fprintf(stderr,"The string is %s\n",buf);
fprintf(stderr,"The length of the string is %d\n",length);
return 0;
}
Here is the small function:
#include <stdio.h>
#include <stdlib.h>
int readdata(int fd, char *buf, int bufsize){
int n = 0;
if(fd < 0){
return 1;
}
while((n=read(fd,buf,(bufsize-1)))>0){
if(n == -1) {
perror( "Read failed" );
return 1;
}
else{
buf[bufsize] = 0;
return n;
}
}
}
If I run
cc -o test test.c readdata.c
And then put
echo "Hello" | ./test
It works fine. But if I pass the bufsize limit like this:
echo "1234567891" | ./getdatatest
It gives me this weird output where it says "the string is 123456789[some weird symbol]" . So I am not sure where to handle this error or why it is still incorrectly putting in the buffer when reading.
You do know that read() can return less characters than you requested? Also, buf[bufsize] is just past the end of buf. Your readdata function should also return something like -1 on error instead of 1 so you can distinguish the condition “one byte read” from “IO error.”
Consider something like this:
for (;;) {
n = read(fd, buf, (bufsize - 1));
if(n == -1) {
perror( "Read failed" );
return -1;
} else {
buf[n] = 0;
return n;
}
}

C read file and print buffer

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.

Resources