|
From: Marcin S. <mar...@in...> - 2015-09-14 12:43:39
|
From: Marcin Ślusarz <mar...@in...>
They can be used to validate application assumptions about addressability
and definedness for long pieces of memory without using ADDRESSABLE/DEFINED
variants for each byte in a region.
For libpmemobj, we want to validate whether whole memory pool immediately
after create and load is in only two states: defined or unaddressable.
Pools can be huge and in the beginning they are mostly empty, so to
validate free chunks without CHECK_MEM_IS_UNADDRESSABLE we have to call
CHECK_MEM_IS_ADDRESSABLE for *each* free byte, which is *very* slow.
CHECK_MEM_IS_UNDEFINED is not as important for performance, but
I implemented it for completeness.
---
memcheck/docs/mc-manual.xml | 10 ++++++++++
memcheck/mc_include.h | 2 ++
memcheck/mc_main.c | 31 +++++++++++++++++++++++++++++++
memcheck/memcheck.h | 18 ++++++++++++++++++
memcheck/tests/addressable.c | 33 +++++++++++++++++++++++++++++++++
memcheck/tests/addressable.stderr.exp | 30 ++++++++++++++++++++++++------
memcheck/tests/addressable.stdout.exp | 2 ++
7 files changed, 120 insertions(+), 6 deletions(-)
diff --git memcheck/docs/mc-manual.xml memcheck/docs/mc-manual.xml
index b54b721..6a21ea6 100644
--- memcheck/docs/mc-manual.xml
+++ memcheck/docs/mc-manual.xml
@@ -2118,6 +2118,16 @@ arguments.</para>
</listitem>
<listitem>
+ <para><varname>VALGRIND_CHECK_MEM_IS_UNADDRESSABLE</varname> and
+ <varname>VALGRIND_CHECK_MEM_IS_UNDEFINED</varname>: check immediately
+ whether or not the given address range has the relevant property.
+ Returns zero if the relevant property holds; otherwise,
+ the returned value is the address of the first byte for which the
+ property is not true. Always returns 0 when not run on
+ Valgrind.</para>
+ </listitem>
+
+ <listitem>
<para><varname>VALGRIND_CHECK_VALUE_IS_DEFINED</varname>: a quick and easy
way to find out whether Valgrind thinks a particular value
(lvalue, to be precise) is addressable and defined. Prints an error
diff --git memcheck/mc_include.h memcheck/mc_include.h
index 663cdca..1f4ebcd 100644
--- memcheck/mc_include.h
+++ memcheck/mc_include.h
@@ -277,6 +277,8 @@ enum {
MCPE_IS_MEM_DEFINED_LOOP,
MCPE_IS_MEM_DEFINED_COMPREHENSIVE,
MCPE_IS_MEM_DEFINED_COMPREHENSIVE_LOOP,
+ MCPE_IS_MEM_UNDEFINED,
+ MCPE_IS_MEM_UNDEFINED_LOOP,
MCPE_IS_DEFINED_ASCIIZ,
MCPE_IS_DEFINED_ASCIIZ_LOOP,
MCPE_FIND_CHUNK_FOR_OLD,
diff --git memcheck/mc_main.c memcheck/mc_main.c
index 65fdfcb..4f21472 100644
--- memcheck/mc_main.c
+++ memcheck/mc_main.c
@@ -3792,6 +3792,25 @@ static Bool is_mem_addressable ( Addr a, SizeT len,
return True;
}
+static Bool is_mem_undefined ( Addr a, SizeT len,
+ /*OUT*/Addr* bad_addr )
+{
+ SizeT i;
+ UWord vabits2;
+
+ PROF_EVENT(MCPE_IS_MEM_UNDEFINED);
+ for (i = 0; i < len; i++) {
+ PROF_EVENT(MCPE_IS_MEM_UNDEFINED_LOOP);
+ vabits2 = get_vabits2(a);
+ if (VA_BITS2_UNDEFINED != vabits2) {
+ if (bad_addr != NULL) *bad_addr = a;
+ return False;
+ }
+ a++;
+ }
+ return True;
+}
+
static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
/*OUT*/Addr* bad_addr,
/*OUT*/UInt* otag )
@@ -6561,6 +6580,18 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
break;
}
+ case VG_USERREQ__CHECK_MEM_IS_UNADDRESSABLE: {
+ Bool ok = MC_(check_mem_is_noaccess) ( arg[1], arg[2], &bad_addr );
+ *ret = ok ? (UWord)NULL : bad_addr;
+ break;
+ }
+
+ case VG_USERREQ__CHECK_MEM_IS_UNDEFINED: {
+ Bool ok = is_mem_undefined( arg[1], arg[2], &bad_addr );
+ *ret = ok ? (UWord)NULL : bad_addr;
+ break;
+ }
+
case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
Bool errorV = False;
Addr bad_addrV = 0;
diff --git memcheck/memcheck.h memcheck/memcheck.h
index 811930e..7514071 100644
--- memcheck/memcheck.h
+++ memcheck/memcheck.h
@@ -99,6 +99,9 @@ typedef
VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE,
VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE,
+ VG_USERREQ__CHECK_MEM_IS_UNADDRESSABLE,
+ VG_USERREQ__CHECK_MEM_IS_UNDEFINED,
+
/* This is just for memcheck's internal use - don't use it */
_VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR
= VG_USERREQ_TOOL_BASE('M','C') + 256
@@ -184,6 +187,21 @@ typedef
(volatile unsigned char *)&(__lvalue), \
(unsigned long)(sizeof (__lvalue)))
+/* Check that memory at _qzz_addr is unaddressable for _qzz_len bytes.
+ If any byte in this range is addressable, Valgrind returns the
+ address of the first offending byte. Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_UNADDRESSABLE(_qzz_addr,_qzz_len) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ VG_USERREQ__CHECK_MEM_IS_UNADDRESSABLE,\
+ (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Check that memory at _qzz_addr is undefined for _qzz_len bytes. If any
+ byte in this range is defined or unaddressable, Valgrind returns the
+ address of the first offending byte. Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_UNDEFINED(_qzz_addr,_qzz_len) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ VG_USERREQ__CHECK_MEM_IS_UNDEFINED, \
+ (_qzz_addr), (_qzz_len), 0, 0, 0)
/* Do a full memory leak check (like --leak-check=full) mid-execution. */
#define VALGRIND_DO_LEAK_CHECK \
diff --git memcheck/tests/addressable.c memcheck/tests/addressable.c
index 5f3c2e1..e3240f5 100644
--- memcheck/tests/addressable.c
+++ memcheck/tests/addressable.c
@@ -91,6 +91,37 @@ static void test5()
(void) VALGRIND_CHECK_MEM_IS_DEFINED(m+20, 10); /* BAD */
}
+/* Case 6 - test CHECK_MEM_IS_UNDEFINED */
+static void test6()
+{
+ char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
+
+ (void) VALGRIND_MAKE_MEM_UNDEFINED(m, pgsz*5);
+ if (VALGRIND_CHECK_MEM_IS_UNDEFINED(m, pgsz*5) != NULL)
+ exit(61);
+
+ memset(m, 'x', 10);
+ if (VALGRIND_CHECK_MEM_IS_UNDEFINED(m, 10) != m)
+ exit(62);
+ if (VALGRIND_CHECK_MEM_IS_UNDEFINED(m+10, 10) != NULL)
+ exit(63);
+}
+
+/* Case 7 - test CHECK_MEM_IS_UNADDRESSABLE */
+static void test7()
+{
+ char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
+
+ VALGRIND_CHECK_MEM_IS_ADDRESSABLE(m, pgsz * 5);
+ if (VALGRIND_CHECK_MEM_IS_UNADDRESSABLE(m, pgsz * 5) != m)
+ exit(71);
+
+ munmap(m, pgsz * 5);
+
+ if (VALGRIND_CHECK_MEM_IS_UNADDRESSABLE(m, pgsz * 5) != NULL)
+ exit(72);
+}
+
static struct test {
void (*test)(void);
int faults;
@@ -100,6 +131,8 @@ static struct test {
{ test3, 0 },
{ test4, 1 },
{ test5, 0 },
+ { test6, 0 },
+ { test7, 0 },
};
static const int n_tests = sizeof(tests)/sizeof(*tests);
diff --git memcheck/tests/addressable.stderr.exp memcheck/tests/addressable.stderr.exp
index 8fbd952..107b644 100644
--- memcheck/tests/addressable.stderr.exp
+++ memcheck/tests/addressable.stderr.exp
@@ -10,19 +10,19 @@ For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Unaddressable byte(s) found during client check request
at 0x........: test2 (addressable.c:48)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
Address 0x........ is not stack'd, malloc'd or (recently) free'd
Invalid write of size 1
at 0x........: test2 (addressable.c:51)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
Address 0x........ is not stack'd, malloc'd or (recently) free'd
Process terminating with default action of signal N (SIGSEGV or SIGBUS)
Bad memory (SIGSEGV or SIGBUS) at address 0x........
at 0x........: test2 (addressable.c:51)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
If you believe this happened as a result of a stack
overflow in your program's main thread (unlikely but
possible), you can try to increase the size of the
@@ -50,7 +50,7 @@ ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Process terminating with default action of signal N (SIGSEGV or SIGBUS)
Bad memory (SIGSEGV or SIGBUS) at address 0x........
at 0x........: test4 (addressable.c:74)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
HEAP SUMMARY:
in use at exit: ... bytes in ... blocks
@@ -62,12 +62,12 @@ For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Uninitialised byte(s) found during client check request
at 0x........: test5 (addressable.c:85)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
Address 0x........ is in a rw- anonymous segment
Uninitialised byte(s) found during client check request
at 0x........: test5 (addressable.c:91)
- by 0x........: main (addressable.c:125)
+ by 0x........: main (addressable.c:158)
Address 0x........ is in a r-- anonymous segment
@@ -89,3 +89,21 @@ For a detailed leak analysis, rerun with: --leak-check=full
For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+
+HEAP SUMMARY:
+ in use at exit: ... bytes in ... blocks
+ total heap usage: ... allocs, ... frees, ... bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+
+HEAP SUMMARY:
+ in use at exit: ... bytes in ... blocks
+ total heap usage: ... allocs, ... frees, ... bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git memcheck/tests/addressable.stdout.exp memcheck/tests/addressable.stdout.exp
index f72368e..b47a782 100644
--- memcheck/tests/addressable.stdout.exp
+++ memcheck/tests/addressable.stdout.exp
@@ -3,3 +3,5 @@ Test 2: PASS
Test 3: PASS
Test 4: PASS
Test 5: PASS
+Test 6: PASS
+Test 7: PASS
--
2.5.0
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
|