C shared memory - c

I am trying to implement shared memory on embedded device with uClinux.
My C source
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <errno.h>
//using namespace std;
int main() {
int segment_id;
segment_id = shmget(04, getpagesize(), IPC_CREAT | 0666);
printf("Page size - %d\n",getpagesize());
printf("Error in socket - %d\n",errno);
}
I get an error
Page size - 4096
Error in socket - 38
Can anyone help me?
Thanks.

You need to test segment_id value, and use errno only if segment_id == -1.

Your key 04 looks completely bogus. You should obtain a key_t with ftok, I guess.
Also, if you have the choice, it might be better to choose the shm_open / mmap facilities for such a task.
And since I am at it, use perror to print errors, and also please remove C++ from your question title, has nothing to do with C++.

The errno 38 corresponds to ENOSYS which means function not implemented.
I missed a kernel config. I have to enable CONFIG_SYSVIPC.

Related

allocation error when trying to do shmat

when trying to do shmat i get allocation error, telling me i cannot accsess the memory, it did not happen to me before and i really dont know what to do.
this is the error :
0xffffffffffffffff error: Cannot access memory at address 0xffffffffffffffff
and the wiered thing is that vecBoard is allocated in the process mapped area and only get crazy when shmat is triggered. thank you all!
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHM_SIZE 4096
#define FLAGS IPC_CREAT
#define COLUMNS 8
#define ROWS 8
key_t key;
int main()
{
char* vecBoard;
// Creating shared memory :
if ((key = ftok("ex31.c",'k')) == -1)
{
perror("ftok");
exit(1);
}
int shm_id;
shm_id=shmget(key,SHM_SIZE,FLAGS);
if(shm_id==-1)
{
printf("error creating shared memory\n");
exit(0);
}
printf("the shared memory segment ID is: %d\n",shm_id);
vecBoard = (char *)shmat(shm_id,0,0);
if((vecBoard = (char *)shmat(shm_id,0,0)) == (char*)-1)
{
printf("error in attaching to the shared memory\n");
exit(0);
}
}
The shown code calls shmat() twice, for the same memory segment.
That's obviously wrong.
Looking at errno would help diagnose the problem (i.e. call perror on failure instead of just printf). The OS gives you information when a system call fails; don't ignore it!
If you carefully read the man page for shmget, the third argument (flags) is supposed to contain, in its low 9 bits, the permissions desired for the shared memory segment. If you just pass IPC_CREAT here, those bits are cleared to 0, so you create a segment for which nobody has either read or write permissions. Thus shmat fails (with EACCES because you are (implicitly) asking to both read and write that segment, and you don't have permission to do either.
You probably want to change it to something like IPC_CREAT | 0600, if you want the current user to be able to access the segment.
Note that before testing this again, you'll probably have to remove the existing shared memory segment with the erroneous permissions. Use the ipcs and ipcrm tools for this.

SIGSEGV, after mmapping area

I am trying to revive process from core dump after SIGQUIT.
I really want that piece of virtual memory, yet I get SIGSEGV when I try to map it.
EDIT: This area isn't free: 0xf75d2000 - 0xf7774000, but still i want to have it.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ucontext.h>
#include <elf.h>
#include <sys/procfs.h>
#include <sys/user.h>
#include <linux/unistd.h>
#include <linux/unistd.h>
#include <asm/ldt.h>
#include <signal.h>
bool flag = false;
int argc2;
char ** argv2;
int main2(){
FILE * file = fopen("/proc/self/maps", "r");
if (file) {
char c;
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
fflush(stdout);
void* res = mmap((void*)(0xf75d2000), 0x001a5000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
return 0;
}
int main(int argc, char ** argv){
argc2 = argc;
argv2 = argv;
ucontext_t cont;
getcontext (&cont);
if(!flag){
void* a = mmap((void*)0x34B000, 81920, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if(a == MAP_FAILED){
printf("mmapfail");
return 1;
}
cont.uc_mcontext.gregs[REG_ESP] = 0x355000;
flag = true;
setcontext(&cont);
} else{
exit(main2());
}
}
I'm compiling it with:
gcc -static -Wl,-Ttext=0x4A9480,--build-idone,-Tdata=0x639480,--section-start=.plt=0x3B9480,--section-start=.rel.plt=0x3AF480,--section-start=.note.ABI-tag=0x39B480 main.c -o main -m32
The address you are trying to map (0xf75d2000) is above the userspace/kernel split in virtual memory. If your kernel is configured with CONFIG_VMSPLIT_3G, you can't map arbitrary addresses above 0xc0000000.
The existing mappings were setup in kernel to expose the vDSO space (to assist with system calls).
Of course you get a SEGV. You map things with MAP_FIXED into some address that doesn't belong to you, then you pull the stack from under your feet. You cannot do this.
The address space is not yours to mess around in. MAP_FIXED is only safe for overwriting earlier mappings. You can possibly play around in it in a single experiment where you'll throw away the program afterwards, but any other use is just not going to work.
Right now your call to setcontext will crash because it doesn't know where to return. Do you even know how function calls and the stack interact? Your call to setcontext saves the return address on the stack, then setcontext changes the stack pointer then it tries to return and dies because it reads 0 as the return address (or setcontext maybe saves the old stack pointer in some other register and will restore it from that register before it returns and what crashes is your other mmap that overwrites the real stack). Please don't do this. Your only chance to reliably change stacks without being the operating system is to set up a signal handler with sigaltstack, catch that signal and never return from the signal handler.
But since you're mapping the memory for your new stack with MAP_FIXED into some random address you'll probably overwrite some other important data structure and it still won't work.
The address space needs to be claimed before other areas are claimed, therefore it needs to be claimed in the executable's metadata.
Create an section in assembly language, then specify it's address in a command line argument to the linker.
For example:
#include <stdio.h>
extern char mem[];
asm (R"(
.section fixed, "aw", #nobits
.global mem
mem:
.zero 0x20000000
)");
int main() {
printf("mem = %p\n", mem);
}
Compile and link with:
gcc -O2 -Wl,--section-start=fixed=0x40000000 -fno-pie -no-pie test.c
Unfortunately using GCC's __attribute__((Section("fixed"))) on a variable definition GCC results in a executable bloated with zeros.

OSX and shared memory needing sudo

I recently found out after updating the OSX software on our server that I am unable to run one of my programs without getting Segmentation Fault 11. It is a simple program which tries to allocate shared memory and then free it. It works fine when i compile and run my file using sudo. Any help would be much appreciated!
Source Code:
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <stddef.h>
#include <sys/un.h>
#include <unistd.h>
int main(){
double *shared;
int arrsize, shmid;
arrsize = 10;
shmid = shmget(IPC_PRIVATE, arrsize * sizeof(double), IPC_CREAT | 666);
shared = (double*) shmat(shmid, NULL, 0);
shared[2] = 3.0; //source of Segmentation Fault
shmdt( (void*) shared );
shmctl(shmid, IPC_RMID, NULL);
printf("Success!");
return 0;
}
System:
ProductName: Mac OS X
ProductVersion: 10.9.1
BuildVersion: 13B42
You are not setting your permissions correctly for the shared memory. You have to use the macros in sys/stat.h to pass the right permissions. Consult man 2 chmod:
shmid = shmget(IPC_PRIVATE, arrsize * sizeof(double), S_IRUSR | S_IWUSR );
Will do the trick.
Your shmget call may be failing when running as a normal user because your literal value 666 is being parsed as a decimal literal. You need a leading 0 for it to be recognized as octal as intended.

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.).

Unable to create Shared Memory C [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
The following code always returns -1 for creating shared memory. I don't know the reason for it. As far as I know my code is correct. Perror returns not such file or directory. I don't know what it is pointing to, but this file and the header are in the same directory. Here is the code:
#include "MyShared.h"
int main()
{
struct MyShared *obj;
int shmid,i,childpid;
shmid=shmget(MySharedKey,sizeof(struct MyShared),PERM);
if(shmid==-1)
printf("Failed to create shared mem\n");
obj=(struct MyShared*)shmat(shmid,NULL,0);
obj->ReadFromBuf=0;
....
}
Here is the header file. My Shared.h
#ifndef MYSHARED_H_INCLUDED
#define MYSHARED_H_INCLUDED
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PERM (S_IRWXU | S_IRGRP)
#define MySharedKey 564732
#define SIZE 512 // 512 bytes
struct MyShared
{
char buf[SIZE];
int ReadFromBuf,WriteToBuf,readbytes;
};
#endif
Why can't this code create a shared memory?
I am using ubuntu 10.04.
I am following Unix System programming by Stevens and it doesn't say anything or creation permissions for a shared memory.
Regards
Instead of
printf("Failed to create shared mem\n");
better use
perror("Failed to create shared mem");
This evaluates the errno variable and prints a more useful error message, in your case something like
Failed to create shared mem: No such file or directory
The reason is that you try to attach to a non-existing memory segment.
In order to create a shared memory segment, you need to pass the IPC_CREAT flag to shmget():
shmid=shmget(MySharedKey,sizeof(struct MyShared),PERM | IPC_CREAT);
See also http://www.kernel.org/doc/man-pages/online/pages/man2/shmget.2.html
If you are not passing this flag, it is assumed that the shared memory segment already exists and that your process wants to attach to it. This is what needs to be done by your slave processes which want to access the shared memory segment, once it has been created by some master process.
first, you lose some head file.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
second, the first argument of shmget() function is a key_t type.So you must use fotk() function to generator key.
Example:
Myshared.h
#ifndef _MYSHARED_H
#define _MYSHARED_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define FLAG (IPC_CREATE | IPC_EXCL)
#define SIZE 512
typedef struct {
char buf[SIZE];
int read_from_buffer, write_to_buffer, read_bytes;
} Shared;
#endif
Myshared.c
#include "Myshared.h"
#include <stdio.h>
int main(int argc, char **argv)
{
key_t key;
int shmid;
key = ftok("/dev/null", 0); # /dev/null just a example
shmid = shmget(key, sizeof(struct Shared), FLAG);
if (shmid == -1) {
perror("Create Shared Memory Error:");
}
......
}
the end, you can type man ftok and man shmget to help yourself.

Resources