Valid read from mmap-ed memory produces SIGBUS under load. Why?
With your current program, it can happen that thread 0 creates /tmp/buf_0
, writes to it and closes it. Then thread 1 removes and creates /tmp/buf_0
, but before thread 1 writes to it, thread 0 opens, maps, and reads from /tmp/buf_0
- and thus tries to access a file does not yet contain 64 kiB data. You get a SIGBUS
.
To avoid that issue, just make unique files / and bufs
for each thread, by using omp_get_thread_num()
instead of bufIdx
.
Bus Error when writing to mmaped data
A documented cause for SIGBUS with mmap is
Attempted access to a portion of the buffer that does not correspond to the file (for example, beyond the end of the file, including the case where another process has truncated the file).
My guess is that the accounts
file didn't exist, so open
with O_CREAT
created it. But it has zero size, so any attempt to read or write through the mapping will fault. You need to fill the file with enough zeroes (or something else) to cover the mapping, for example using ftruncate
.
rrdtool gives bus error when an attempt is made to create an rrd database
This problem may be related to some mmap bug of your old Centos distribution.
If upgrading to a newer version is not an option, you could try to compile your rrdtool
with the following option:
./configure --disable-mmap
By doing so, the faulty memcpy
at line 716 in the rrd_write()
function (shown below) should not be executed:
/* Write count bytes from buffer buf to the current position
* rrd_file->pos of rrd_simple_file->fd.
* Returns the number of bytes written or <0 on error. */
ssize_t rrd_write(
rrd_file_t *rrd_file,
const void *buf,
size_t count)
{
rrd_simple_file_t *rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt;
#ifdef HAVE_MMAP
size_t old_size = rrd_file->file_len;
if (count == 0)
return 0;
if (buf == NULL)
return -1; /* EINVAL */
if((rrd_file->pos + count) > old_size)
{
rrd_set_error("attempting to write beyond end of file");
return -1;
}
memcpy(rrd_simple_file->file_start + rrd_file->pos, buf, count);
rrd_file->pos += count;
return count; /* mimmic write() semantics */
#else
ssize_t _sz = write(rrd_simple_file->fd, buf, count);
if (_sz > 0)
rrd_file->pos += _sz;
return _sz;
#endif
}
How to work around lack of NUL terminator in strings returned from mmap()?
I would suggest undergoing a paradigm shift here.
You're looking at the entire universe consisting of '\0'-delimited strings that define your text. Instead of looking at the world this way, why don't you try looking at the world where text is defined as a sequence defined by a beginning and an ending iterator.
You mmap
your file, then initially set the beginning iterator, call it beg_iter
to the start of the mmap-ed segment, and the ending iterator, call it end_iter
, to the first byte following the last byte in the mmap-ed segment, or beg_iter+number_of_pages*pagesize
, then until either
A) end_iter
equals beg_iter
, or
B) beg_iter[-1]
is not a null character, then
C) decrement end_iter
, and go back to step A.
When you're done, you have a pair of iterators, the beginning iterator value, and the ending iterator value that define your text string.
Of course, in this case, your iterators are plain char *
, but that's really not very important. What is important is that now you find yourself with a rich set of algorithms and templates from the C++ standard library at your disposal, that let you implement many complicated operations, both mutable (like std::transform
), and non-mutable, (like std::find
).
Null-terminated strings are really a holdover from the days of plain C. With C++, null-terminated strings are somewhat archaic, and mundane. Modern C++ code should use std::string
objects, and sequences defined by beginning and ending iterators.
One small footnote: instead of figuring out how much NULL
padding you ended up mmap-ing(), you might find it easier to fstat() the file, and get the file's exact length, in bytes, before mmap-ing it. Then you'll now exactly know much got mmaped, and you don't have to reverse-engineer it, by looking at the padding.
What is a bus error? Is it different from a segmentation fault?
Bus errors are rare nowadays on x86 and occur when your processor cannot even attempt the memory access requested, typically:
- using a processor instruction with an address that does not satisfy its alignment requirements.
Segmentation faults occur when accessing memory which does not belong to your process. They are very common and are typically the result of:
- using a pointer to something that was deallocated.
- using an uninitialized hence bogus pointer.
- using a null pointer.
- overflowing a buffer.
PS: To be more precise, it is not manipulating the pointer itself that will cause issues. It's accessing the memory it points to (dereferencing).
using mmap to copy a file
Mapping two files to the same memory region is problematic. What should the contents of this memory be, data from the first file or the second, or a mix? This won't work.
What you can do is map two files and memcpy
from one mapped region to the other. Note, however, that it is a good idea to create the file first and set its length, otherwise mmap
may return SIGBUS
(see docs).
SIGBUS Attempted access to a portion of the buffer that does not
correspond to the file (for example, beyond the end of the file,
including the case where another process has truncated the file).
C Bus Error with mmap, what is the problem
You can't write to a non-existent portion of a file via mmap()
.
This truncates the file:
int dfd = open(comms->destination, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
This mmap()
's the truncated file:
void* destination = mmap(NULL, fileSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, dfd, 0);
This tries to copy to a non-existent part of the file:
memcpy(destination, content, fileSize);
Per the Linux mmap()
man page ERRORS:
ERRORS
...
Use of a mapped region can result in these signals:
...
SIGBUS
Attempted access to a portion of the buffer that does not
correspond to the file (for example, beyond the end of the
file, including the case where another process has truncated
the file).
Per the POSIX mmap()
specification:
... References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a
SIGBUS
signal.An implementation may generate
SIGBUS
signals when a reference would cause an error in the mapped object, such as out-of-space condition.
The fix is to call ftruncate()
to set the file length on the output file:
ftruncate( dfd, fileSize );
void* destination = mmap(NULL, fileSize, PROT_READ | PROT_WRITE, MAP_SHARED, dfd, 0);
Note that you also have to replace the MAP_PRIVATE
flag with MAP_SHARED
. Per POSIX again (bolding mine):
MAP_SHARED
andMAP_PRIVATE
describe the disposition of write references to the memory object. IfMAP_SHARED
is specified, write references shall change the underlying object.If MAP_PRIVATE
is specified, modifications to the mapped data by the calling process shall be visible only to the calling process and shall not change the underlying object. It is unspecified whether modifications to the underlying object done after theMAP_PRIVATE
mapping is established are visible through theMAP_PRIVATE
mapping. EitherMAP_SHARED
orMAP_PRIVATE
can be specified, but not both. The mapping type is retained acrossfork()
.
Related Topics
Can Not Add New User in Docker Container with Mounted /Etc/Passwd and /Etc/Shadow
Communication Between Linked Docker Containers
How to Determine The Ip of The Computer That Connects to Me
Why Is Capeff All Zeros in /Proc/$Pid/Status
How to Get Complete Stack Dump from Profiler in Every Sample for Use in Flame Graph
How to Automatically Start an Application That Needs X in Linux
Using Source to Include Part of a File in a Bash Script
Notify Gpio Interrupt to User Space from a Kernel Module
Downloading a Tarball from Github Without Curl
Trying to Install Docker Gpg Key Recieving Error: Curl: Option '-' Is Unknown
How to Configure Multiple Ssh Access to an Ec2 Instance
Is There Any Reference Implementation of Linux File System Filter Driver
How to Disable Floating Point Unit (Fpu)