From: Philippe Waroquiers Date: Wed, 26 Sep 2018 16:04:43 +0000 (+0200) Subject: Fix 398028 Assertion `cfsi_fits` failing in simple C program X-Git-Tag: VALGRIND_3_14_0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9dd4af5c78c2b8094fcb5015b0992c6cb54980c8;p=thirdparty%2Fvalgrind.git Fix 398028 Assertion `cfsi_fits` failing in simple C program At least with libopenblas, we can have several rx mappings with some holes between mappings. Change the invariant (2) checking so that such holes are ok, as long as no cfsi refers to such an hole. --- diff --git a/NEWS b/NEWS index ad188da19b..384cc9d357 100644 --- a/NEWS +++ b/NEWS @@ -167,6 +167,7 @@ where XXXXXX is the bug number as listed below. 397089 amd64: Incorrect decoding of three-register vmovss/vmovsd opcode 11h 397354 utimensat should ignore timespec tv_sec if tv_nsec is UTIME_NOW/OMIT 397424 glibc 2.27 and gdb_server tests +398028 Assertion `cfsi_fits` failing in simple C program 398066 s390x: cgijl dep1, 0 reports false unitialised values warning n-i-bz Fix missing workq_ops operations (macOS) diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index 0fc54bf1dd..1aa43146fe 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -660,6 +660,8 @@ static void check_CFSI_related_invariants ( const DebugInfo* di ) DebugInfo* di2 = NULL; Bool has_nonempty_rx = False; Word i, j; + const Bool debug = VG_(debugLog_getLevel)() >= 3; + vg_assert(di); /* This fn isn't called until after debuginfo for this object has been successfully read. And that shouldn't happen until we have @@ -676,7 +678,7 @@ static void check_CFSI_related_invariants ( const DebugInfo* di ) if (map->size == 0) continue; has_nonempty_rx = True; - + /* normal case: r-x section is nonempty */ /* invariant (0) */ vg_assert(map->size > 0); @@ -689,8 +691,9 @@ static void check_CFSI_related_invariants ( const DebugInfo* di ) const DebugInfoMapping* map2 = VG_(indexXA)(di2->fsm.maps, j); if (!map2->rx || map2->size == 0) continue; - vg_assert(!ranges_overlap(map->avma, map->size, - map2->avma, map2->size)); + vg_assert2(!ranges_overlap(map->avma, map->size, + map2->avma, map2->size), + "DiCfsi invariant (1) verification failed"); } } di2 = NULL; @@ -723,17 +726,44 @@ static void check_CFSI_related_invariants ( const DebugInfo* di ) if (map->size > 0) VG_(bindRangeMap)(rm, map->avma, map->avma + map->size - 1, 0); } - /* If the map isn't now empty, it means the cfsi range isn't covered - entirely by the rx mappings. */ - Bool cfsi_fits = VG_(sizeRangeMap)(rm) == 1; - if (cfsi_fits) { - // Sanity-check the range-map operation + /* Typically, the range map contains one single range with value 0, + meaning that the cfsi range is entirely covered by the rx mappings. + However, in some cases, there are holes in the rx mappings + (see BZ #398028). + In such a case, check that no cfsi refers to these holes. */ + Bool cfsi_fits = VG_(sizeRangeMap)(rm) >= 1; + // Check the ranges in the map. + for (Word ix = 0; ix < VG_(sizeRangeMap)(rm); ix++) { UWord key_min = 0x55, key_max = 0x56, val = 0x57; - /* We can look up any address at all since we expect only one range */ - VG_(lookupRangeMap)(&key_min, &key_max, &val, rm, 0x1234); - vg_assert(key_min == (UWord)0); - vg_assert(key_max == ~(UWord)0); - vg_assert(val == 0); + VG_(indexRangeMap)(&key_min, &key_max, &val, rm, ix); + if (debug) + VG_(dmsg)("cfsi range rx-mappings coverage check: %s %#lx-%#lx\n", + val == 1 ? "Uncovered" : "Covered", + key_min, key_max); + { + // Sanity-check the range-map operation + UWord check_key_min = 0x55, check_key_max = 0x56, check_val = 0x57; + VG_(lookupRangeMap)(&check_key_min, &check_key_max, &check_val, rm, + key_min + (key_max - key_min) / 2); + if (ix == 0) + vg_assert(key_min == (UWord)0); + if (ix == VG_(sizeRangeMap)(rm) - 1) + vg_assert(key_max == ~(UWord)0); + vg_assert(key_min == check_key_min); + vg_assert(key_max == check_key_max); + vg_assert(val == 0 || val == 1); + vg_assert(val == check_val); + } + if (val == 1) { + /* This is a part of cfsi_minavma .. cfsi_maxavma not covered. + Check no cfsi overlaps with this range. */ + for (i = 0; i < di->cfsi_used; i++) { + DiCfSI* cfsi = &di->cfsi_rd[i]; + vg_assert2(cfsi->base > key_max + || cfsi->base + cfsi->len - 1 < key_min, + "DiCfsi invariant (2) verification failed"); + } + } } vg_assert(cfsi_fits); diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h index 713acbea87..98e715658f 100644 --- a/coregrind/m_debuginfo/priv_storage.h +++ b/coregrind/m_debuginfo/priv_storage.h @@ -670,9 +670,12 @@ struct _DebugInfo { (0) size of at least one rx mapping > 0 (1) no two non-archived DebugInfos with some rx mapping of size > 0 have overlapping rx mappings - (2) [cfsi_minavma,cfsi_maxavma] does not extend beyond - [avma,+size) of one rx mapping; that is, the former - is a subrange or equal to the latter. + (2) Each address in [cfsi_minavma,cfsi_maxavma] is in an rx mapping + or else no cfsi can cover this address. + The typical case is a single rx mapping covering the full range. + In some cases, the union of several rx mappings covers the range, + with possibly some holes between the rx mappings, and no cfsi fall + within such an hole. (3) all DiCfSI in the cfsi array all have ranges that fall within [avma,+size) of that rx mapping. (4) all DiCfSI in the cfsi array are non-overlapping