From 88b7345e1037e770a7d2cd0516f00da84c5c27d4e6ec7949d323649d4a0e584b Mon Sep 17 00:00:00 2001 From: Tom de Vries Date: Wed, 27 Nov 2019 18:54:59 +0000 Subject: [PATCH 1/2] - Fix assertion failure 'off == cu_size' in recompute_abbrevs [swo#24764]. * dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch OBS-URL: https://build.opensuse.org/package/show/devel:tools:compiler/dwz?expand=0&rev=23 --- ...ion-off-cu_size-in-recompute_abbrevs.patch | 138 ++++++++++++++++++ dwz.changes | 7 + dwz.spec | 2 + 3 files changed, 147 insertions(+) create mode 100644 dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch diff --git a/dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch b/dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch new file mode 100644 index 0000000..ac42161 --- /dev/null +++ b/dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch @@ -0,0 +1,138 @@ +Fix assertion 'off == cu_size' in recompute_abbrevs + +[ Backport of master commit 331eabd. ] + +With an executable from PR25024, we manage to reproduce PR24764: +... +$ dwz -l0 clang-offload-bundler-10.0.0-0.20190817snap5.fc30.x86_64.debug +dwz: dwz.c:9920: recompute_abbrevs: Assertion `off == cu_size' failed. +Aborted (core dumped) +... + +The problem is that the cu_size as computed during recompute_abbrevs is not +the same as was computed before during compute_abbrevs. + +I tracked down the first DIE in the CU that has a different size, at 0xdf615: +... + <5>: Abbrev Number: 65 (DW_TAG_formal_parameter) + DW_AT_type : <0xe33be> + DW_AT_artificial : 1 +... + +Using a debug patch, we can track the size of the DIE during compute_abbrevs: +... +init_new_die_offsets: intracusize: 2 +init_new_die_offsets: start die_size: 0 +init_new_die_offsets: add DIE code size to die_size: 1 +init_new_die_offsets: add nr_refs * intracusize to die_size: 3 +update_new_die_offsets: die_size: 3 +update_new_die_offsets: die_size: 3 +finalize_new_die_offsets: die_size: 3 +... +and recompute_abbrevs: +... +init_new_die_offsets: intracusize: 3 +init_new_die_offsets: start die_size: 0 +init_new_die_offsets: add DIE code size to die_size: 1 +init_new_die_offsets: add nr_refs * intracusize to die_size: 4 +update_new_die_offsets: die_size: 4 +update_new_die_offsets: die_size: 4 +update_new_die_offsets: die_size: 4 +finalize_new_die_offsets: die_size: 4 +... + +The difference starts in init_new_die_offsets, when adding intracusize, which +is different for compute_abbrevs and recompute_abbrevs (2 vs. 3). + +The code in recompute_abbrevs that calculates intracusize for the relevant +init_new_die_offsets call is: +... + /* Need to be conservatively high estimate, as update_new_die_offsets + relies on the offsets always decreasing. cu_size at this point is + the size we will end up with in the end, but if cu_size is + sufficiently close (from bottom) to some uleb128 boundary (say + 16384), init_new_die_offsets might return off above that boundary + and then update_new_die_offsets might fail its assertions on + reference to DIEs that crossed the uleb128 boundary. */ + intracusize = size_of_uleb128 (2 * cu_size); + + off = init_new_die_offsets (cu->cu_die, headersz, intracusize); +... +where the '2 * cu_size' is the result of commit d16aa5e "Fix up +recompute_abbrevs if cu_size is close below an uleb128 boundary and +init_new_die_offsets would return offset above that uleb128 boundary": +... +- intracusize = size_of_uleb128 (cu_size); ++ intracusize = size_of_uleb128 (2 * cu_size); +... + +Reverting commit d16aa5e gets us an intracusize of 2 in recompute_abbrevs, and +fixes the assert. However, doing so reintroduces the assertion that was fixed +by the commit (at least, provided commit a4668e1 "Fix assertion failure in +create_import_tree" is also reverted): +... +$ dwz -l0 inkview.debug +dwz: dwz.c:8527: update_new_die_offsets: Assertion \ + `die->u.p2.die_intracu_udata_size >= intracu_udata_size' failed. +Aborted (core dumped) +... + +Fix the 'off == cu_size' assert (without introducing the regression for +inkview.debug) by: +- saving the intracusize used for the call to init_new_die_offsets in + compute_abbrevs, and +- reusing the saved intracusize for the call to init_new_die_offsets in + recompute_abbrevs. + +Also tested with clang and CheckerOptionHandlingAnalyzerPlugin.so, for which +this PR also triggered. + +2019-11-27 Tom de Vries + + PR dwz/24764 + * dwz.c (struct dw_cu): Add initial_intracusize field. + (compute_abbrevs): Initalize initial_intracusize. + (recompute_abbrevs): Use initial_intracusize. + +--- + dwz.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/dwz.c b/dwz.c +index 7c7b401..928fefa 100644 +--- a/dwz.c ++++ b/dwz.c +@@ -674,6 +674,9 @@ struct dw_cu + unsigned int cu_chunk; + /* Form chosen for intra-cu references. */ + enum dwarf_form cu_intracu_form; ++ /* Intracusize argument to init_new_die_offsets. Set in compute_abbrevs, ++ used in recompute_abbrevs. */ ++ unsigned int initial_intracusize; + }; + + /* Internal representation of a debugging information entry (DIE). +@@ -8405,6 +8408,7 @@ compute_abbrevs (DSO *dso) + intracusize = i; + } + while (1); ++ cu->initial_intracusize = intracusize; + off = init_new_die_offsets (cu->cu_die, headersz, intracusize); + do + { +@@ -9555,14 +9559,7 @@ recompute_abbrevs (dw_cu_ref cu, unsigned int cu_size) + } + else + { +- /* Need to be conservatively high estimate, as update_new_die_offsets +- relies on the offsets always decreasing. cu_size at this point is +- the size we will end up with in the end, but if cu_size is +- sufficiently close (from bottom) to some uleb128 boundary (say +- 16384), init_new_die_offsets might return off above that boundary +- and then update_new_die_offsets might fail its assertions on +- reference to DIEs that crossed the uleb128 boundary. */ +- intracusize = size_of_uleb128 (2 * cu_size); ++ intracusize = cu->initial_intracusize; + + off = init_new_die_offsets (cu->cu_die, headersz, intracusize); + do diff --git a/dwz.changes b/dwz.changes index a395b71..91c0bdb 100644 --- a/dwz.changes +++ b/dwz.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Wed Nov 27 18:50:07 UTC 2019 - Tom de Vries + +- Fix assertion failure 'off == cu_size' in recompute_abbrevs + [swo#24764]. + * dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch + ------------------------------------------------------------------- Tue Nov 5 09:55:50 UTC 2019 - Tom de Vries diff --git a/dwz.spec b/dwz.spec index 246d837..fc46d0d 100644 --- a/dwz.spec +++ b/dwz.spec @@ -75,6 +75,7 @@ NoSource: 0 Patch1: dwz-update-version-copyright-message.patch Patch2: dwz-fix-die-no-multifile-propagation.patch +Patch3: dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch %if %{build_main} %description @@ -105,6 +106,7 @@ This package contains the testsuite results from DWZ. %setup -q -n dwz %patch1 -p1 %patch2 -p1 +%patch3 -p1 %build make %{?_smp_mflags} CFLAGS="%{optflags}" From 9a6297a36862d27482f0491c13069b1865c571ee9be8ba68bdb637b9f6547f5a Mon Sep 17 00:00:00 2001 From: Tom de Vries Date: Thu, 28 Nov 2019 14:10:53 +0000 Subject: [PATCH 2/2] - Fix assertion failure 'refd != NULL' in write_die [swo#24169]. * dwz-fix-refd-NULL-assertion-in-write_die.patch OBS-URL: https://build.opensuse.org/package/show/devel:tools:compiler/dwz?expand=0&rev=24 --- ...fix-refd-NULL-assertion-in-write_die.patch | 55 +++++++++++++++++++ dwz.changes | 6 ++ dwz.spec | 2 + 3 files changed, 63 insertions(+) create mode 100644 dwz-fix-refd-NULL-assertion-in-write_die.patch diff --git a/dwz-fix-refd-NULL-assertion-in-write_die.patch b/dwz-fix-refd-NULL-assertion-in-write_die.patch new file mode 100644 index 0000000..e59fe64 --- /dev/null +++ b/dwz-fix-refd-NULL-assertion-in-write_die.patch @@ -0,0 +1,55 @@ +Fix 'refd != NULL' assertion in write_die + +[ Backport of master commits 6959430 and 7cc8aae. ] + +When running dwz on a file that contains invalid DW_FORM_ref_addr attributes +(which has been observed to be generated by a google go compiler) we run +either into an assert: +... +$ dwz multidictionary +dwz: dwz.c:9461: write_die: Assertion `refd != NULL' failed. +Aborted (core dumped) +... +or a segmentation fault in case of low-mem mode: +... +$ dwz -l0 multidictionary +Segmentation fault (core dumped) +... + +Fix this by erroring out instead: +... +$ dwz multidictionary +dwz: Couldn't find DIE at DW_FORM_ref_addr offset 0x97 +... + +2019-02-05 Tom de Vries + + PR dwz/24169 + * dwz.c (write_die): Error out on invalid DW_FORM_ref_addr. + +--- + dwz.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/dwz.c b/dwz.c +index 928fefa..c7db337 100644 +--- a/dwz.c ++++ b/dwz.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -9124,6 +9125,9 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die, + ? ptr_size : 4); + inptr += refcu->cu_version == 2 ? ptr_size : 4; + refd = off_htab_lookup (NULL, value); ++ if (refd == NULL || refd->die_tag == 0) ++ error (1, 0, "Couldn't find DIE at DW_FORM_ref_addr offset" ++ " 0x%" PRIx64, value); + assert (refd != NULL); + refdt = refd; + while (refdt->die_toplevel == 0) diff --git a/dwz.changes b/dwz.changes index 91c0bdb..0120513 100644 --- a/dwz.changes +++ b/dwz.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Nov 28 12:56:34 UTC 2019 - Tom de Vries + +- Fix assertion failure 'refd != NULL' in write_die [swo#24169]. + * dwz-fix-refd-NULL-assertion-in-write_die.patch + ------------------------------------------------------------------- Wed Nov 27 18:50:07 UTC 2019 - Tom de Vries diff --git a/dwz.spec b/dwz.spec index fc46d0d..c204639 100644 --- a/dwz.spec +++ b/dwz.spec @@ -76,6 +76,7 @@ NoSource: 0 Patch1: dwz-update-version-copyright-message.patch Patch2: dwz-fix-die-no-multifile-propagation.patch Patch3: dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch +Patch4: dwz-fix-refd-NULL-assertion-in-write_die.patch %if %{build_main} %description @@ -107,6 +108,7 @@ This package contains the testsuite results from DWZ. %patch1 -p1 %patch2 -p1 %patch3 -p1 +%patch4 -p1 %build make %{?_smp_mflags} CFLAGS="%{optflags}"