C pthreads error - c

Programming Language C
below is the code that uses multiple threads to print out a file. There are no errors, however the code doesn't work correctly. However, when compiled it shows this warning 5 times:
'cast from pointer to integer of different size'
I've tried everything I can think of to resolve this issue, but haven't been success and now are just shooting in the dark. Does anyone see where my mistake is? Any help is greatly appreciated and will gladly provide any other information upon request.
Thanks.
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define NUM_THREAD 4
struct fileParams {
int fd;
int size;
};
void *printFile(void *stuff)
{
struct fileParams *params = stuff;
int addr;
addr=(unsigned char *)mmap(NULL, (int) &params->size, PROT_READ,
MAP_PRIVATE,(int) &params->fd,0);
write(STDOUT_FILENO, addr, (int)&params->size);
}
int main (int argc, char * argv[])
{
pthread_t threads[NUM_THREAD];
unsigned char *addr;
int fd,rc;
struct stat sb;
int numCPU=sysconf(_SC_NPROCESSORS_ONLN);
struct fileParams params;
printf("Number of aviable cores: %d\n",numCPU);
printf("Using 4 processors\n");
if (argc != 2 || strcmp(argv[1], "—help") == 0)
printf("Usage: %s file\n", argv[0]);
fd=open(argv[1],O_RDONLY);
if (fd == -1)
{
printf("File open fdailed.\n");
exit(EXIT_FAILURE);
}
if (fstat(fd, &sb) == -1)
{
printf ("fstat error\n");
exit(EXIT_FAILURE);
}
params.fd=fd;
params.size=sb.st_size/4;
for (int n = 0; n<4; n++)
rc=pthread_create(&threads[n],NULL,printFile,&params);
exit(EXIT_SUCCESS);
}

You need provide inputs to functions that match the function - passing pointers where integers are wanted (or the other way around) will generate warnings or errors depending on compile options.
mmap takes an size_t as the 2nd parameter, but you are giving it a cast int to a pointer (&params->size), the same with mmaps 5th parameter.
Get rid of the '&' so it is just a int.
mmap also returns a void *, which you are then assigning to addr (an int).
Change int to a void * pointer type which should also fix the 5th warning.

Related

read fails with EFAULT

I am running the following C code, where trying to read in buffer which
is allocated on caller's stack, but fails with errno 14 (Bad Address).
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
void wrapper(int fd, char **buf)
{
int res = read(fd, *buf, 10);
printf("res: %d, errno: %d\n", res, errno);
printf("Buf: %s\n", *buf);
}
int main()
{
char buffer[10];
memset(buffer, 0, 10);
int fd = open("main.c", O_RDONLY);
wrapper(fd, (char **)&buffer);
return 0;
}
The output is
res: -1, errno: 14
Buf: (null)
I have been searching for explanation why it fails, whereas changing it to
void wrapper(int fd, char *buf)
...
wrapper(fd, (char *)buffer);
works, but without result so far.
why it fails
Arrays are not pointers. buffer is not a char*. Consequently, &buffer is not a char**, is not compatible with char**, and should not be cast to char**. If it is cast to char** and then dereferenced, the behaviour is undefined.
After analyzed your intention, of course it is possible to create something like a "wrapper" containing read string by read(2) syscall and use that buffer away from wrapper() function. You wanted to pass amount of characters which would be read from file being in a table of files whom index of the table (file descriptor) was return by open(2) syscall. But as n.m. said, arrays are not pointers and your solution cannot work properly.
Let me explain my simple fix to your code:
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define AMOUNT 20
#define assert_msg(x) for ( ; !(x) ; assert(x) )
void
wrapper(int fd, char **buf, size_t size)
{
ssize_t res;
char *out;
out = calloc(size + 1, sizeof(char));
assert(out != NULL);
res = read(fd, out, size);
assert_msg(res != -1) {
fprintf(stderr, "Error ocurred: %s\n", strerror(errno));
}
out[size] = '\0';
fprintf(stdout, "Inside function: %s\n", out);
fprintf(stdout, "res: %d, size: %d, errno: (%d: %s)\n", res, size,
errno, strerror(errno));
*buf = out;
}
int
main(int argc, char **argv)
{
int fd;
char *buf;
buf = NULL;
assert(argc == 2);
errno = 0;
fd = open(argv[1], O_RDONLY);
assert_msg(fd != -1) {
fprintf(stderr, "Error ocurred: %s\n", strerror(errno));
}
wrapper(fd, &buf, AMOUNT);
fprintf(stdout, "Outside function: %s\n", buf);
free(buf);
return (EXIT_SUCCESS);
}
I pass a filename as an input argument. It was a bit easier for me instead of hardcoding the name.
As you can see, inside my wrapper() implementation I allocate memory for an out buffer which size I am passing by a value of size variable. I know that the same value as AMOUNT value defined as macro but it would be easy to change in any other solution.
Then, I read given amount of characters using read(2) syscall, from a file descriptor returned by open(2) syscall in main() function which I pass to wrapper().
At the end of that function I tell that I would like to save an address to the beginning of allocated out buffer and I would like that *buf indicates on that address. It is a buffer of size + 1 char elements, allocated on heap, not on a local stack. Therefore program cannot "reuse" that addresses during his execution. Every address for variables declared like int a;, struct type name; or char tab[10]; are "freed" automatically after the end of function and you do not have an access to it. To be clear, you may have an access (e.g. print data from address saved to indicator) but you cannot be sure that you would not lose the data being saved there. Space allocated manually still exist on a heap until calling free(3) function.
So if we would do something like:
void
wrapper(int fd, char **buf, const size_t size)
{
ssize_t res;
char out[size];
(...)
*buf = out;
}
you may lost your data being saved on a local stack during continuing program execution.
Additionally, in my solution I also defined my own macro assert_msg(x) which is able to run assert(3) function and shows a text message with error. But it is only a feature but thanks to that we are able to see string corresponding to an errno number.
Of course, my program need better handling errors but it had to present the idea only.
Furthermore, you should also specify file permissions during using open(2) syscall as a third argument. It looks similar to the second argument because it is a bitwise 'or' separated list of values. Example flags: S_IRUSR, S_IRGRP, S_IWOTH etc.
In that argument, you can also just write proper value describing permissions, for example 0755.

write() warning message in compilation

I have a piece of code to create function to print a message from input parameter.
I've been compiling the code with c9.io and works pretty well without warnings but when i do it locally it shows a warning like this:
child2bok: c39:11: warning: Ignoring return value of 'write', declares with attribute warn_unused_result [-Wunused -result]
And this is the code.Sure it is a problem with write() definition but i'm so novice with unix programming and no idea to solve it. It executes well but i'd like to remove the warning before i deliver to the teacher.
Here you are the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include "rutines.h"
void children();
void show_help();
int main(int argc, char *argv[])
{
int ord;
if (argc > 1)
ord = atoi(argv[1]);
if (argc == 1)
{
show_help("Error");
exit(1);
}
children(ord);
}
void children(int ord)
{
char msg[10];
srand(getpid());
sleep(rand() % 5);
sprintf(msg, " %d", ord);
while (strlen(msg) > 0)
{
int written= write(1, msg, strlen(msg));
if (written < 0)
break;
exit(0);
}
void show_help(char *err_message)
{
write_string(err_message,"");
write_string("Usage: child2aok \n","");
}
You should check and handle the value returned by the write() command. From the write documentation:
write [...] may return less than count even under valid conditions.
Why don't you simply use printf(" %d", ord); instead of sprintf(msg, " %d", ord); write(1, msg, strlen(msg))?
write does not guarantee to write all the data; it may write as little as one byte (or block, or return an error, ...). So you have to use it in a loop:
bool write_all(int fd, void * buf, size_t len)
{
size_t remaining = len;
for (size_t n; (n = write(fd, buf, remaining)) > 0; remaining -= n)
{ }
return remaining == 0;
}
This function returns true if all bytes were written, and false on error.

Is there a way to mmap a stdin?

I have a following problem:
My job is to write a program that takes unsigned integer numbers that are passed to it through stdin and print out only the numbers that have more than 2 bits set to one. How should I do it efficiently? I did a version of a program where I read the numbers from a file using mmap, and it's quite quick. I read it like a very big *char buffer and using strtol I 'scrub' out each number and do my check and whatnot.
Is there a way to operate on a string passed through stdin the same way? I though about buffering using fread, but there is a problem, where the buffer cuts off the number (meaning if i pass "1024 35" and I have a 6 byte buffer I will get "1024 3"), and I shudder to think how to get around that.
Source:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h> /* mmap() is defined in this header */
#include <fcntl.h>
#include<string.h>
#include"apue.h"
int main (int argc, char *argv[])
{
int fdin, fdout;
char *src, *dst;
struct stat statbuf;
/* open the input file */
if ((fdin = open (argv[1], O_RDONLY)) < 0)
{printf("can't open %s for reading", argv[1]);return 1;}
/* find size of input file */
if (fstat (fdin,&statbuf) < 0)
{printf("fstat error");return 1;}
/* mmap the input file */
if ((src = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
== (caddr_t) -1)
{printf("mmap error for input");return 1;}
char* beg=src;
long x;
char* end=&src[statbuf.st_size-1];
while(src<end)
{
beg=src;
x = strtol (src,&src,10);
if(!((x != 0) && ((x & (~x + 1)) == x)))
fwrite(beg, 1, (int)(src-beg), stdout);
}
return 0;
}
http://pastebin.com/EVhG3x79
I think the expected solution is how to count the ones and not how to read from stdin.
int count_ones(int n);
means the question is how to implement the count_ones efficiently.
and your main just should look like this:
int main()
{
int x;
cin>>x;
if( count_ones(x)>2){
cout<<x<<endl;
}
return 0;
}
I think the expected answer is:
use array size 256
for each byte(=unsigned char) put in the array in its place the count of ones (can be: from 0 to 8)
split each number to its bytes and sum the ones on each of the bytes.
return the result

MAC address from interface on OS X (C)

This might be a stupid question and I apologize if it's already been addressed here, but I've searched quite a bit without much luck. I'm trying to get my interface's hardware address in C and I'm using OS X (x86-64). I know how to get it with ifconfig, but I want my program to get it automatically for any computer, well, at least OS X computers. I found another thread that posted this link which pretty much does what I want (with some modifications), but I can't make the iokit functions link in ld (my compiler is gcc). I tried adding the flags -lIOKit and -framework IOKit to the gcc command line, but I still get the same link errors. Here's a link to my code: header and source.
This little program will work without changes on OSX.
Code : (credits to Alecs King from freebsd list)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int mib[6], len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
if (argc != 2) {
fprintf(stderr, "Usage: getmac <interface>\n");
return 1;
}
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex(argv[1])) == 0) {
perror("if_nametoindex error");
exit(2);
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
perror("sysctl 1 error");
exit(3);
}
if ((buf = malloc(len)) == NULL) {
perror("malloc error");
exit(4);
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
perror("sysctl 2 error");
exit(5);
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *ptr, *(ptr+1), *(ptr+2),
*(ptr+3), *(ptr+4), *(ptr+5));
return 0;
}
You should, however, change int len; to size_t len;

C printf compiler warning

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int fd, offset;
char *data;
struct stat sbuf;
int counter;
if (argc != 2) {
fprintf(stderr, "usage: mmapdemo offset\n");
exit(1);
}
if ((fd = open("mmapdemo.c", O_RDONLY)) == -1) {
perror("open");
exit(1);
}
if (stat("mmapdemo.c", &sbuf) == -1) {
perror("stat");
exit(1);
}
offset = atoi(argv[1]);
if (offset < 0 || offset > sbuf.st_size-1) {
fprintf(stderr, "mmapdemo: offset must be in the range 0-%ld\n",sbuf.st_size-1);
exit(1);
}
data = mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (data == (caddr_t)(-1)) {
perror("mmap");
exit(1);
}
// print the while file byte by byte
while(counter<=sbuf.st_size)
printf("%c", data++);
return 0;
}
This gives me error as follows:
gcc mmapdemo.c -o mmapdemo
mmapdemo.c: In function 'main':
mmapdemo.c:48: warning: format '%c' expects type 'int', but argument 2 has type 'char *'
Please help me to solve the problem.
printf("%c", *data++);
data is a char *. The %c format specifier tells printf to expect a char. To get a char from a char *, you need to dereference the pointer using the * operator.
That said, your program still won't work properly because you're not incrementing counter in your print loop, nor have you initialized it. I would go with:
for (size_t i = 0; i < sbuf.st_size; ++i) {
printf("%c", data[i]);
}
instead. I haven't inspected the rest of your program, but given that there were three serious errors in three lines that I looked at, I doubt that the rest is bug-free.
to print it out byte by byte, need to use
printf("%c ", *data++)
or to print out the hex values:
printf("%02X", *data++);

Resources