From: Mark Wielaard Date: Sun, 22 Jan 2023 22:18:18 +0000 (+0100) Subject: Propagate memory allocation failure to out_of_memory_NORETURN X-Git-Tag: VALGRIND_3_21_0~88 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f32cc294e363f9ea953b22cddcb290954725d83b;p=thirdparty%2Fvalgrind.git Propagate memory allocation failure to out_of_memory_NORETURN 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). --- diff --git a/NEWS b/NEWS index 990043fe63..4fd2baf04c 100644 --- a/NEWS +++ b/NEWS @@ -128,6 +128,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 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. diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c index 00a42ffe6e..ae38d8bd05 100644 --- a/coregrind/m_aspacemgr/aspacemgr-linux.c +++ b/coregrind/m_aspacemgr/aspacemgr-linux.c @@ -2744,10 +2744,9 @@ SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length ) /* 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 diff --git a/coregrind/m_mallocfree.c b/coregrind/m_mallocfree.c index a51c9aa730..b58d471b67 100644 --- a/coregrind/m_mallocfree.c +++ b/coregrind/m_mallocfree.c @@ -37,6 +37,7 @@ #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" @@ -749,7 +750,7 @@ void ensure_mm_init ( ArenaId aid ) /*------------------------------------------------------------*/ __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. @@ -760,7 +761,7 @@ void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB ) 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" @@ -769,6 +770,9 @@ void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB ) " 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" @@ -801,9 +805,15 @@ void VG_(out_of_memory_NORETURN) ( const HChar* who, SizeT szB ) 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); @@ -865,7 +875,7 @@ Superblock* newSuperblock ( Arena* a, SizeT cszB ) // 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 { @@ -1830,7 +1840,8 @@ void* VG_(arena_malloc) ( ArenaId aid, const HChar* cc, SizeT req_pszB ) 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); diff --git a/coregrind/m_transtab.c b/coregrind/m_transtab.c index 384461289d..102108a357 100644 --- a/coregrind/m_transtab.c +++ b/coregrind/m_transtab.c @@ -1574,7 +1574,7 @@ static void initialiseSector ( SECno sno ) 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); @@ -1583,7 +1583,8 @@ static void initialiseSector ( SECno sno ) ( 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); @@ -1592,7 +1593,8 @@ static void initialiseSector ( SECno sno ) ( 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); @@ -1608,7 +1610,8 @@ static void initialiseSector ( SECno sno ) ( 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); @@ -2371,7 +2374,7 @@ static void init_unredir_tt_tc ( void ) ( 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); diff --git a/helgrind/libhb_core.c b/helgrind/libhb_core.c index 7c0ea84503..f660a34ea0 100644 --- a/helgrind/libhb_core.c +++ b/helgrind/libhb_core.c @@ -716,10 +716,13 @@ static void* shmem__bigchunk_alloc ( SizeT n ) 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); diff --git a/include/pub_tool_aspacemgr.h b/include/pub_tool_aspacemgr.h index 4466345490..163c385d14 100644 --- a/include/pub_tool_aspacemgr.h +++ b/include/pub_tool_aspacemgr.h @@ -153,7 +153,7 @@ extern Bool VG_(am_is_valid_for_client) ( Addr start, SizeT len, 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. */ diff --git a/include/pub_tool_mallocfree.h b/include/pub_tool_mallocfree.h index 8532bba870..ef7096edee 100644 --- a/include/pub_tool_mallocfree.h +++ b/include/pub_tool_mallocfree.h @@ -46,8 +46,11 @@ extern HChar* VG_(strdup) ( const HChar* cc, const HChar* s ); // 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. diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index 3619dd1f92..946813be79 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -309,10 +309,11 @@ static SecMap* copy_for_writing ( SecMap* dist_sm ) || 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; @@ -2543,11 +2544,12 @@ static void init_OCache ( void ) 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++) {