#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int* ptr = (int *) mmap(0x4096, sizeof(int)*1024, 1100, MAP_PRIVATE, 0, 0);
fprintf(stdout, "%p\n", ptr);
if (ptr == MAP_FAILED)
{
fprintf(stderr, "Could not mmap\n");
return 1;
}
return 0;
}
My code is printing could not mmap, I cannot figure out what am I doing wrong. My memory page's size is 4096 bytes so my address input is page size aligned too. What I want to do is allocate a memory space for 1024 integers using mmap on my specified address.
As pointed by several people in the comments, I should be using MAP_ANONYMOUS, and haven't specified the memory location correctly. Using the following parameters worked,
mmap((void*) 0x0804a000, sizeof(int)*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
Related
The following code will generate errno 12 cannot allocate memory
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <memory.h>
#include <errno.h>
int main()
{
char* p;
for (size_t i = 0; i < 0x10000; i++)
{
char* addr = (char*)0xAAA00000000uL - i * 0x2000;
p = mmap(addr, 0x1000,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p != addr) {
printf("%lu %d\n", i, errno);
getchar();
return 1;
}
memset(p, 'A' + (i % 26), 0x1000);
}
return 0;
}
The output is 65510 12 on my machine.
However, if we change size of each page from 0x1000 to 0x2000, the allocation will be successful, even if it is using more memory.
The only difference I think is the number of continuous pages, is there a limitation on this? If so, how to set it to unlimited?
It seems that setting /proc/sys/vm/max_map_count to a larger number solves the problem.
Reference: How much memory could vm use
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.
Trying to use mmap to write to a file. Unfortunately the first write in the loop map[i] = i; will cause a bus error. Not sure why.
The PC runs Ubuntu 14.04 and the file /tmp/mmapped.bin has 12 bytes and the program is invoked with ./a.out 3.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILEPATH "/tmp/mmapped.bin"
//#define NUMINTS (1000)
#define FILESIZE 0x400000000
int main(int argc, char *argv[])
{
int i;
int fd;
int *map; /* mmapped array of int's */
int size = atoi(argv[1]);
fd = open(FILEPATH, O_RDWR| O_CREAT | O_TRUNC);
if (fd == -1) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
map = mmap(0, 4 * size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
for (i = 1; i <= size; ++i) {
map[i] = i;
}
if (munmap(map, FILESIZE) == -1) {
perror("Error un-mmapping the file");
}
close(fd);
return 0;
}
In c you need to start at index 0. Because it will simply increment the pointer by the amount i and then dereference it. Your code dereferences the pointer beyond the allowed bound.
It should be,
for (i = 0; i < size; ++i) {
map[i] = i;
}
because it's equivalent to
for (i = 0; i < size; ++i) {
*(map + i) = i;
}
Also, use
map = mmap(0, size * sizeof *map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
to ensure that enough space is allocated and that *(map + i) will be inside bounds. Don't use magic numbers.
According to the mmap man page a bus error (SIGBUS) happens when you read/write outside the bounds of the file.
The length of the mapping is separate from the length of the file. If your file is newly created its size will be 0, even if you specify a length with mmap. Resize the file with ftruncate after opening it.
I got a question about shared memory and segmentation fault.
I thought that it would be fine to use huge size of memory.
When I checked Shmmax, i found the huge memory can be allocated.
under data is the result of $ipcs -lm
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#define ARRAY_SIZE 40000000
int main(int argc, char *argv[]){
int shmid;
void *shared_memory = (void *)0;
shmid = shmget((key_t)1234, sizeof(float), IPC_CREAT|0666);
if (shmid == -1)
{
perror("shmget failed : ");
exit(0);
}
shared_memory = (float *)shmat(shmid, NULL, 0);
if (shared_memory == (void *)-1)
{
perror("shmat failed : ");
exit(0);
}
static float *testx;
testx = (float *)shared_memory;
int k = 0;
for(k;k<400;k++){
testx[k] = 1.12;
}
for(k;k<40000000;k++){
testx[k] = 1.12;
}
}
the program can run the first for loop which has small amount of size
the problem, however, is the second loop with 40,000,000 size
any suggestion what should i edit to run this code?
The reason for your SEGFAULT is that you haven't created enough size segment with shmget.
The argument you passed to shmget as size is sizeof(float) which is just enough to store 1 float.
What you need to do is call shmget like this -
shmget((key_t)1234, sizeof(float)*40000000, IPC_CREAT|0666);
Then you can use all the memory correctly.
The reason that the smaller loop of 400 worked is because shmget creates segments that are multiple of PAGE_SIZE.
So even when you passed sizeof(float), it allocated atleast 1 page which was enough to hold 400 floats but not 40000000.
I hope that clears the confusion.
Context:
Taking advantage of my holidays to fiddle with some pointers :)
The code below is an intellectual challenge to myself more than anything else. it helps me working on pointers and so on.
And I fail.
I didn't enforce the coherence with error management, I confess.
Debian64.
The problem :
I make my way with mmap and I litteraly plundge with a double pointer assignation. here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
static int mmap_create(const char ** restrict map, const char * restrict path, const unsigned int * restrict size)
{
int fd;
int result;
fd = open(path, O_RDWR | O_CREAT,(mode_t)0777);
if (fd == -1)
{
printf("fail3\n");
close(fd);
return -1;
}
result = lseek(fd, *size-1, SEEK_SET);
if (result == -1)
{
printf("fail4\n");
close(fd);
return -1;
}
result = write(fd, "", 1);
if (result != 1)
{
printf("fail0\n");
close(fd);
return -1;
}
/* Here is my problem since map is a pointer to pointer */
map = mmap(0, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
printf("fail\n");
close(fd);
return -1;
}
printf("pointing to %p\n",map);
return 0;
}
static void second_function(const char * restrict path, const char ** restrict handle)
{
printf("pointing to %p\n",handle);
/* CREATE MMAP */
unsigned int value = 100;
mmap_create(handle,path,&value);
}
static void write_to(char ** map)
{
printf("pointing to %p\n",map);
}
int main(int argc, char * argv[])
{
const char path[] = "/my/path/";
char ** handle_a;
printf("pointing to %p\n",handle_a);
second_function(path,handle_a);
printf("pointing to %p\n",handle_a);
write_to(handle_a);
/*munmap*/
return 0;
}
Question:
How could I do to be able to retrieve the right address of the mapped file up to the write_to function ?
The first two are nil (normal) the third is assigned but the last two ones are nil. Not good.
I think it all goes wrong in the mmap call since it gives a pointer but I have a pointer to pointer.
Thereafter, the addresses are not the same anymore.
And then, I am lost..
Any "pointer" please?
Thanks
handle_a has no memory allocated to store the pointer
change
char ** handle_a;
to
char * handle_a;
and then use as
second_function(path,&handle_a);
and assign it like;
*map = mmap(0, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);