Provide the user with a hint of what caused an out of memory error.
And explain that some memory policies, like selinux deny_execmem
might cause Permission denied errors.
Add an err argument to out_of_memory_NORETURN. And change
am_shadow_alloc to return a SysRes (all three callers were already
checking for errors and calling out_of_memory_NORETURN).
462830 WARNING: unhandled amd64-freebsd syscall: 474
463027 broken check for MPX instruction support in assembler
464476 Firefox fails to start under Valgrind
+464680 Show issues caused by memory policies like selinux deny_execmem
464859 Build failures with GCC-13 (drd tsan_unittest)
464969 D language demangling
465435 m_libcfile.c:66 (vgPlain_safe_fd): Assertion 'newfd >= VG_(fd_hard_limit)' failed.
/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
-void* VG_(am_shadow_alloc)(SizeT size)
+SysRes VG_(am_shadow_alloc)(SizeT size)
{
- SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
- return sr_isError(sres) ? NULL : (void*)(Addr)sr_Res(sres);
+ return VG_(am_mmap_anon_float_valgrind)( size );
}
/* Map a file at an unconstrained address for V, and update the
#include "pub_core_mallocfree.h"
#include "pub_core_options.h"
#include "pub_core_threadstate.h" // For VG_INVALID_THREADID
+#include "pub_core_syscall.h" // For VG_(strerror)
#include "pub_core_gdbserver.h"
#include "pub_core_transtab.h"
#include "pub_core_tooliface.h"
/*------------------------------------------------------------*/
__attribute__((noreturn))
-void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB )
+void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB, UWord err )
{
static Int outputTrial = 0;
// We try once to output the full memory state followed by the below message.
ULong tot_alloc = VG_(am_get_anonsize_total)();
const HChar* s1 =
"\n"
- " Valgrind's memory management: out of memory:\n"
+ " Valgrind's memory management: out of memory: %s\n"
" %s's request for %llu bytes failed.\n"
" %'13llu bytes have already been mmap-ed ANONYMOUS.\n"
" Valgrind cannot continue. Sorry.\n\n"
" output of 'ulimit -a'. Is there a limit on the size of\n"
" virtual memory or address space?\n"
" - You have run out of swap space.\n"
+ " - You have some policy enabled that denies memory to be\n"
+ " executable (for example selinux deny_execmem) that causes\n"
+ " mmap to fail with Permission denied.\n"
" - Valgrind has a bug. If you think this is the case or you are\n"
" not sure, please let us know and we'll try to fix it.\n"
" Please note that programs can take substantially more memory than\n"
INNER_REQUEST(VALGRIND_MONITOR_COMMAND("v.info memory aspacemgr"));
}
outputTrial++;
- VG_(message)(Vg_UserMsg, s1, who, (ULong)szB, tot_alloc);
+ VG_(message)(Vg_UserMsg, s1,
+ ((err == 0 || err == VKI_ENOMEM)
+ ? "" : VG_(strerror) (err)),
+ who, (ULong)szB, tot_alloc);
} else {
- VG_(debugLog)(0,"mallocfree", s1, who, (ULong)szB, tot_alloc);
+ VG_(debugLog)(0,"mallocfree", s1,
+ ((err == 0 || err == VKI_ENOMEM)
+ ? "" : VG_(strerror) (err)),
+ who, (ULong)szB, tot_alloc);
}
VG_(exit)(1);
// non-client allocation -- abort if it fails
sres = VG_(am_mmap_anon_float_valgrind)( cszB );
if (sr_isError(sres)) {
- VG_(out_of_memory_NORETURN)("newSuperblock", cszB);
+ VG_(out_of_memory_NORETURN)("newSuperblock", cszB, sr_Err(sres));
/* NOTREACHED */
sb = NULL; /* keep gcc happy */
} else {
a->sblocks_size * 2);
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("arena_init", sizeof(Superblock *) *
- a->sblocks_size * 2);
+ a->sblocks_size * 2,
+ sr_Err(sres));
/* NOTREACHED */
}
array = (Superblock**)(Addr)sr_Res(sres);
sres = VG_(am_mmap_anon_float_valgrind)( 8 * tc_sector_szQ );
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("initialiseSector(TC)",
- 8 * tc_sector_szQ );
+ 8 * tc_sector_szQ, sr_Err(sres) );
/*NOTREACHED*/
}
sec->tc = (ULong*)(Addr)sr_Res(sres);
( N_TTES_PER_SECTOR * sizeof(TTEntryC) );
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("initialiseSector(TTC)",
- N_TTES_PER_SECTOR * sizeof(TTEntryC) );
+ N_TTES_PER_SECTOR * sizeof(TTEntryC),
+ sr_Err(sres));
/*NOTREACHED*/
}
sec->ttC = (TTEntryC*)(Addr)sr_Res(sres);
( N_TTES_PER_SECTOR * sizeof(TTEntryH) );
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("initialiseSector(TTH)",
- N_TTES_PER_SECTOR * sizeof(TTEntryH) );
+ N_TTES_PER_SECTOR * sizeof(TTEntryH),
+ sr_Err(sres));
/*NOTREACHED*/
}
sec->ttH = (TTEntryH*)(Addr)sr_Res(sres);
( N_HTTES_PER_SECTOR * sizeof(TTEno) );
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("initialiseSector(HTT)",
- N_HTTES_PER_SECTOR * sizeof(TTEno) );
+ N_HTTES_PER_SECTOR * sizeof(TTEno),
+ sr_Err(sres));
/*NOTREACHED*/
}
sec->htt = (TTEno*)(Addr)sr_Res(sres);
( N_UNREDIR_TT * UNREDIR_SZB );
if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)("init_unredir_tt_tc",
- N_UNREDIR_TT * UNREDIR_SZB);
+ N_UNREDIR_TT * UNREDIR_SZB, sr_Err(sres));
/*NOTREACHED*/
}
unredir_tc = (ULong *)(Addr)sr_Res(sres);
if (0)
VG_(printf)("XXXXX bigchunk: abandoning %d bytes\n",
(Int)(shmem__bigchunk_end1 - shmem__bigchunk_next));
- shmem__bigchunk_next = VG_(am_shadow_alloc)( sHMEM__BIGCHUNK_SIZE );
- if (shmem__bigchunk_next == NULL)
+ SysRes sres = VG_(am_shadow_alloc)( sHMEM__BIGCHUNK_SIZE );
+ if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)(
- "helgrind:shmem__bigchunk_alloc", sHMEM__BIGCHUNK_SIZE );
+ "helgrind:shmem__bigchunk_alloc", sHMEM__BIGCHUNK_SIZE,
+ sr_Err(sres));
+ }
+ shmem__bigchunk_next = (void*)(Addr)sr_Res(sres);;
shmem__bigchunk_end1 = shmem__bigchunk_next + sHMEM__BIGCHUNK_SIZE;
}
tl_assert(shmem__bigchunk_next);
UInt prot );
/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
-extern void* VG_(am_shadow_alloc)(SizeT size);
+extern SysRes VG_(am_shadow_alloc)(SizeT size);
/* Unmap the given address range and update the segment array
accordingly. This fails if the range isn't valid for valgrind. */
// TODO: move somewhere else
// Call here to bomb the system when out of memory (mmap anon fails)
+// Provide the VKI errno if possible (normally the result of sr_Err),
+// may be zero if unknown.
__attribute__((noreturn))
-extern void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB );
+extern void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB,
+ UWord err );
// VG_(perm_malloc) is for allocating small blocks which are
// never released. The overhead for such blocks is minimal.
|| dist_sm == &sm_distinguished[1]
|| dist_sm == &sm_distinguished[2]);
- new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
- if (new_sm == NULL)
+ SysRes sres = VG_(am_shadow_alloc)(sizeof(SecMap));
+ if (sr_isError(sres))
VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap",
- sizeof(SecMap) );
+ sizeof(SecMap), sr_Err(sres) );
+ new_sm = (void *)(Addr)sr_Res(sres);
VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
update_SM_counts(dist_sm, new_sm);
return new_sm;
UWord line, set;
tl_assert(MC_(clo_mc_level) >= 3);
tl_assert(ocacheL1 == NULL);
- ocacheL1 = VG_(am_shadow_alloc)(sizeof(OCache));
- if (ocacheL1 == NULL) {
+ SysRes sres = VG_(am_shadow_alloc)(sizeof(OCache));
+ if (sr_isError(sres)) {
VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1",
- sizeof(OCache) );
+ sizeof(OCache), sr_Err(sres) );
}
+ ocacheL1 = (void *)(Addr)sr_Res(sres);
tl_assert(ocacheL1 != NULL);
for (set = 0; set < OC_N_SETS; set++) {
for (line = 0; line < OC_LINES_PER_SET; line++) {