]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Propagate memory allocation failure to out_of_memory_NORETURN
authorMark Wielaard <mark@klomp.org>
Sun, 22 Jan 2023 22:18:18 +0000 (23:18 +0100)
committerMark Wielaard <mark@klomp.org>
Thu, 30 Mar 2023 23:31:25 +0000 (01:31 +0200)
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).

NEWS
coregrind/m_aspacemgr/aspacemgr-linux.c
coregrind/m_mallocfree.c
coregrind/m_transtab.c
helgrind/libhb_core.c
include/pub_tool_aspacemgr.h
include/pub_tool_mallocfree.h
memcheck/mc_main.c

diff --git a/NEWS b/NEWS
index 990043fe63a82235767832ae3ba15eed7b16c992..4fd2baf04c8909ef45f20d82551570c0474d1da4 100644 (file)
--- 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.
index 00a42ffe6ebaf808fb8f7c8a7a701f5c9ba41581..ae38d8bd05e0f380c9605d86a63444ea6383a5af 100644 (file)
@@ -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
index a51c9aa730d5af6a4f53f95d0ae4ab7321a943fd..b58d471b67a41f238119dea69779ec989f561d1b 100644 (file)
@@ -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);
index 384461289d07c62b243f4168a275e54e124f18b4..102108a357d36381e25ae280d5919769d69f1b0a 100644 (file)
@@ -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);
index 7c0ea84503ab726ac44871a8f9622837788f539b..f660a34ea0f58ac11503e34341566e9b607514ea 100644 (file)
@@ -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);
index 4466345490974c9f57ae0bf132eeb6a1891fd3b0..163c385d14e120df7aab8c7694712b941087a1bf 100644 (file)
@@ -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. */
index 8532bba8703d26048657caa24b3a8a7822aa0236..ef7096edeedffcfded82e628517d0e02ebd5c3d8 100644 (file)
@@ -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.
index 3619dd1f92026cc26c6a8e1132fec69f42a6cbe5..946813be79c1db98b26a194a54500da518eb0ef6 100644 (file)
@@ -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++) {