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.
Related
I'm trying to mmap a page-size-rounded file to an area larger than the file size and ftruncate it when one of the traling pages causes a SIGBUS so that the SIGBUS no longer happens.
This works great on Linux and MacOS, but on Cygwin I keep getting a SIGBUS even after a successful growing ftruncate.
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void perrorAndExit(char const *Ctx){ perror(Ctx); _exit(1); }
int main(){
long pgsz = sysconf(_SC_PAGESIZE);
int fd = open("TMPFILE", O_RDWR|O_CREAT,0640);
if(0>fd) perrorAndExit("open");
if(ftruncate(fd,pgsz*1)) perrorAndExit("truncate 1 pgsz");
char *m;
if(MAP_FAILED==(m = mmap(0,pgsz*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))) perrorAndExit("mmap");
memset(m,'=',pgsz);
strcpy(m,"hello, world\n");
if(ftruncate(fd,pgsz*2)) perrorAndExit("truncate 2 pgsz");
strcpy(m+pgsz,"what is up?\n"); //still SIGBUSes on Cygwin
}
Are there any workarounds for this other than starting with a larger file or creating a new mapping after the second truncate?
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?
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.
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.
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.