Shared Memory programming errors(O_RDRW, PROT_WRITE,MAP_SHARED) - c

I am trying to run program for shared memory objects. My code as below:
#include <stdio.h> /*adding standard input output library*/
#include <stdlib.h> /*standard library for four variable types, several macros, and various functions for performing general functions*/
#include <string.h> /*adding string library*/
#include <sys/fcntl.h> /* library for file control options */
#include <sys/shm.h> /*library for shared memory facility*/
#include <sys/stat.h> /*data returned by the stat() function*/
int main()
{
/* the size (in bytes) of shared memory object */
const int SIZE=4096;
/* name of the shared memory object */
const char *name = "OS";
/* strings written to shared memory */
const char *message_0 = "Hello";
const char *message_1 = "World!";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory obect */
void *ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDRW, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
/* write to the shared memory object */
sprintf(ptr,"%s",message_0);
ptr += strlen(message_0);
sprintf(ptr,"%s",message_1);
ptr += strlen(message_1);
return 0;
}
But I am getting following errors
1.error:
‘O_RDRW’ undeclared (first use in this function)
shm_fd = shm_open(name, O_CREAT | O_RDRW, 0666);
2.error:
‘PROT_WRITE’ undeclared (first use in this function)
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
3.error:
‘MAP_SHARED’ undeclared (first use in this function)
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
And warnings like this
note: each undeclared identifier is reported only once for each
function it appears in
I tried to locate fctnl.h, sham.h, stat.h and found many files but i tried including this files
#include "/usr/include/x86_64-linux-gnu/sys/fcntl.h" /*chose one file out of several options available*/
include "/usr/include/x86_64-linux-gnu/sys/shm.h" /*chose one file out of several options available*/
#include "/usr/include/x86_64-linux-gnu/sys/stat.h" /*chose one file out of several options available*/
But still error remains the same.I am using Ubuntu 16.04 LTS.Thanks in advance.

#include <sys/mman.h> to solve PROT_WRITE;
O_RDRW should be O_RDWR - "open for read and WRite";
#include <sys/mman.h> to fix MAP_SHARED error;

#include <sys/mman.h>
Please include in order to solve the PROT_WRITE

Related

Can I map a structure into a shared memory file?

I am trying to open a shared memory segment in my main process. My terminology may be incorrect in the question but this is what I am trying to achieve:
I collect information from 7 sensors and from that I evaluate the state. I made a structure senStruct. I want to share the 7 sensor and state information to other processes with use of shared memory. In code I am opening the senfile, mapping the senStruct into it. Now I simply want to store something into state and it gives me an error.
Here is the code:
#include <fcntl.h> /* Defines O_* constants */
#include <sys/stat.h> /* Defines mode constants */
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct senStruct {
int sensor[7];
int state;
}senStruct;
int main()
{
int fd;
size_t size = sizeof(senStruct);
senStruct *p;
fd = shm_open( "senfile" , O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR );
ftruncate (fd, size);
printf("Before mapping...p points to %p\n",p);
p =(senStruct *) mmap (NULL , size, PROT_READ | PROT_WRITE,MAP_SHARED , fd, 0);
printf("After mapping...p points to %p\n",p);
p->state=1;
return 0;
}
Output is:
Before mapping...p points to (nil)
After mapping...p points to 0xffffffffffffffff
Segmentation fault (core dumped)
Address of p after p seems doubtful to me. Looking into gdb indicates segmentation fault at p->state = 1. Is my procedure incorrect or did I miss anything?

How do I directly access reserved memory with a kernel module?

I'm trying to limit the OS (Ubuntu Server 15.04) to a certain memory usage and reserve the rest but write a kernel module to read/write to the reserved memory. I figured out how to limit the usage/reserve memory using the kernel parameters "mem=4G memmap=4G#0 memmap=4G$4G" (4GB for OS and 4GB reserved, split at 4GB point) but I don't know how DMA to reserved memory works with kernel modules. I was thinking just create a proc file but I'm not sure if you can create one outside of the OS's allocated memory.
Any suggestions? Thanks!
Edit: This is for research so it doesn't need to be "nice"
Update:
Maybe I don't need to write a kernel module. I just found this and I'm going to give it a shot:
http://elinux.org/Memory_Management#Reserving_.28and_accessing.29_the_top_of_memory_on_startup
Update:
I tried the link above but I segfault whenever I try to write. Here's my code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mann.h>
#define RESERVED_MEMORY_SIZE 0x100000000
int main() {
int fd;
char *reserved_memory;
fd = open("/dev/mem", O_RDWR | O_SYNC);
reserved_memory = (char *) mmap(0, RESERVED_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
reserved_memory[0] = 'a';
return 0;
}
dmesg shows:
a.out[1167]: segfault at ffffffffffffffff ip 00000000004005d7 sp 00007ffeffccbd80 error 7 in a.out[400000+1000]
For kicks I tried reserved_memory[1]:
a.out[1180]: segfault at 0 ip 00000000004005db sp 00007ffc388d77b0 error 6 in a.out[400000+1000]
I'll look into the format of those messages so I can figure out what it's telling me.
Update:
I found this question by somebody with the same issue as me however the only solution appears to be a kernel rebuild. I'm going to try to avoid this so maybe my best option is a custom kernel module again.
accessing mmaped /dev/mem?
Ok, so I think I solved it. Turns out I just didn't understand how mmap works and I guess the kernel has no restriction on writing/reading /dev/mem if it's in reserved memory. Below are two programs that will write to my reserved spot in memory and read from it.
Write "Hello World!":
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define RESERVED_MEMORY_OFFSET 0x100000000 /* Offset is 4GB */
int main() {
int fd;
char *reserved_memory;
char *buffer = "Hello World!";
fd = open("/dev/mem", O_RDWR | O_SYNC):
/* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
if (reserved_memory == MAP_FAILED) {
printf("Failed to creating mapping.\n");
printf("ERRNO: %s\n", strerror(errno));
return -1;
}
sprintf(reserved_memory, "%s", buffer);
return 0;
}
Read from beginning of reserved memory:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define RESERVED_MEMORY_OFFSET 0x100000000 /* Offset is 4GB */
int main() {
int fd;
char *reserved_memory;
char buffer[13];
fd = open("/dev/mem", O_RDWR | O_SYNC):
/* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
if (reserved_memory == MAP_FAILED) {
printf("Failed to creating mapping.\n");
printf("ERRNO: %s\n", strerror(errno));
return -1;
}
snprintf(buffer, 13, "%s", reserved_memory);
printf("%s\n", buffer);
return 0;
}
Special thanks to #knm241!

mmap file returns a pointer to an inaccessible place in memory

I have this program that is supposed to mmap a file in read-write mode and be able to edit its contents. Also the file this is written for is about 40-50 GB, so I need mmap64. The problem is, while mmap64 does not return an error, the address it returns is not accessible.
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <unistd.h>
typedef unsigned long long u64;
void access_test(u64 p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = *(char*)(p+i);
}
}
int main(int argc, char *argv[])
{
int fd;
long long int sz, p;
struct stat buf;
fd = open(argv[1], O_RDWR, 0x0666);
if (fd == -1) {
perror("open");
return 1;
}
fstat64(fd, &buf);
sz = buf.st_size;
printf("File size: 0x%016llx\n", sz);
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
if (p == -1) {
perror ("mmap");
return 1;
}
access_test(p,sz);
if (close (fd) == -1) {
perror ("close");
return 1;
}
if (munmap ((void*)p, buf.st_size) == -1) {
perror ("munmap");
return 1;
}
return 0;
}
The result of this is on a small file:
$ ./testmmap minicom.log
File size: 0x0000000000000023
[1] 8282 segmentation fault (core dumped) ./testmmap minicom.log
The same goes for the big one.
Always enable warnings when you compile
Here is the result with warnings enabled:
$ gcc mmp.c -Wall -g
mmp.c: In function ‘access_test’:
mmp.c:18:10: warning: variable ‘tmp’ set but not used [-Wunused-but-set-variable]
char tmp;
^
mmp.c: In function ‘main’:
mmp.c:36:5: warning: implicit declaration of function ‘fstat64’ [-Wimplicit-function-declaration]
fstat64(fd, &buf);
^
mmp.c:40:5: warning: implicit declaration of function ‘mmap64’ [-Wimplicit-function-declaration]
p = mmap64 (0, buf.st_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
The last two warnings here are extremely important. They say there is no prototype for mmap64. C therefore gives you a default prototype, and it is wrong, at least for the mmap64() call (since the prototype will return an int, which cannot represent a pointer on a 64-bit Linux host)
The argument to fstat64() is a struct stat64 too BTW, which is another issue.
Make the specific 64-bit functions available
If you want to make the fstat64()/mmap64() function available, you need to compile the code with the _LARGEFILE and LARGEFILE64_SOURCE #define, see information here, so you should compile this as e.g:
gcc -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE mmp.c -Wall -g
Or use #define _FILE_OFFSET_BITS=64
There is however no need to do this. Just call the normal fstat() and mmap() and #define _FILE_OFFSET_BITS=64 when compiling. e.g.:
gcc -D_FILE_OFFSET_BITS=64 mmp.c -Wall -g
This will enable support for large files, and e.g. translate the mmap() call to mmap64() if it is needed (e.g. if you're on a 32-bit host).
If you are trying to mmap() an 50 GB file, you anyway need to be on a 64-bit host, and on a 64-bit Linux host there's no need for any of this - mmap() and fstat() handles large files without any need to do anything.
Use pointers
The next issue is you're assigning the return value of mmap() to an integer. This might happen to work, but the code does look odd because of it. If you want to treat the thing as a char *, assign it to a char *. Don't play tricks with casting pointers around to a 64-bit integer type.
E.g. your access function should be:
void access_test(char *p, u64 sz)
{
u64 i;
char tmp;
for (i=0; i<sz; i++) {
tmp = p[i];
}
}
And p should be declared as char *p; in main(), or use uint8_t *p; if you intend to treat the data as binary data.

Unix/C: put a file into shared memory

Have a problem.
I have a file which contents look like number:error_description.
Now i need to put this file to shared memory (POSIX). If any contents are modified it should be saved to the base-file.
There is a need to search in the content in the shared memory (results will be sent to a client over a message queue).
How do I implement all this? First I thought I have to open (fopen("my_file", "r")) and then I have to create shared memory and mmap the file.
Can someone help me?
edit:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
/*
* \ /tmp/errors -> Error File
*/
#define MSGQ_HANDLER "/error_handler"
#define PATH_TO_FILE "/tmp/errors"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd = open(PATH_TO_FILE, O_RDWR);
struct stat file_stat;
fstat(fd, &file_stat);
printf("File size: %zd\n", file_stat.st_size);
char *byte_ptr = mmap(NULL, file_stat.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if(byte_ptr == MAP_FAILED){
perror("error:");
}
while(1){
printf("%s\n", byte_ptr);
if(byte_ptr)
exit(1);
}
return EXIT_SUCCESS;
}
So far it is what I have now.
Read a line works.
How do I change the content?
Don't use fopen and forget about shared memory (the sh* API I mean). mmap is all that's needed.
Open your file with open and the right options (read/write). Then use mmap with the option MAP_SHARED. All changes in the file will be reflected directly and visible to all processes that map the same file. On Linux and Solaris (on other systems I don't know, but it is not guaranteed by POSIX or any standard) you can even access the file concurrently with read/write. It is a bad idea though.
Concurrent memory accesses from different processes will, of course, need synchronisation (mutex, semaphores etc.).

C - why I cannot mmap a small (256UL or smaller) size of memory?

Please tell me, why my simple application cannot mmap a small size of memory?
And, why such a specific boundary - 257UL?
// #define MAP_SIZE 256UL or below - fail
// #define MAP_SIZE 257UL - ok
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
int main(int argc, char **argv) {
int fd;
void *map_base, *virt_addr;
unsigned long read_result, writeval;
off_t target = strtoul("0x00002000", 0, 0);
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
printf("/dev/mem opened.\n");
fflush(stdout);
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
...
}
mmap works in multiples of the page size on your system. If you're doing this on i386/amd64 or actually most modern CPUs, this will be 4096.
In the man page of mmap on my system it says: "offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).". On some systems for historical reasons the length argument may be not a multiple of page size, but mmap will round up to a full page in that case anyway.
Probably you just don't have the rights to write to /dev/mem. This is probably not what you want, mapping all the low end physical memory into your address space.
Have a look into shm_open to open memory segments or MAP_ANONYMOUS to map anonymously.
Edit:
Do a man mem to know what the /dev/mem device node is about:
Byte addresses in mem are interpreted as physical memory
addresses.
References to nonexistent locations cause errors to be returned.
If you want to map to a device node to have a memory segment you should use /dev/zero, but nowadays the tools I describe above should be sufficient.
Then don't, really don't, run such a code with root privileges unless you really know what you are doing. Writing into the physical memory and thus overwriting kernel and userspace data and programs can only lead to catastrophes.

Resources