Skip to content

Commit bf7888f

Browse files
committed
Avoid recursion in resolve_unit_addrs_overlap
This patch replaces recursion with explicit stack of enclosing ranges. This fixes stack overflow on certain binaries when initialization happens inside a fiber. See #155 for original discussion.
1 parent 7939218 commit bf7888f

1 file changed

Lines changed: 77 additions & 68 deletions

File tree

dwarf.c

Lines changed: 77 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,8 +1615,7 @@ unit_addrs_search (const void *vkey, const void *ventry)
16151615

16161616
static int
16171617
resolve_unit_addrs_overlap_walk (struct backtrace_state *state,
1618-
size_t *pfrom, size_t *pto,
1619-
struct unit_addrs *enclosing,
1618+
struct backtrace_vector *enclosing,
16201619
struct unit_addrs_vector *old_vec,
16211620
backtrace_error_callback error_callback,
16221621
void *data,
@@ -1627,91 +1626,100 @@ resolve_unit_addrs_overlap_walk (struct backtrace_state *state,
16271626
struct unit_addrs *new_addrs;
16281627
size_t from;
16291628
size_t to;
1629+
size_t enclosing_count;
16301630

16311631
old_addrs = (struct unit_addrs *) old_vec->vec.base;
16321632
old_count = old_vec->count;
16331633
new_addrs = (struct unit_addrs *) new_vec->vec.base;
16341634

1635-
for (from = *pfrom, to = *pto; from < old_count; from++, to++)
1635+
enclosing_count = 0;
1636+
1637+
to = 0;
1638+
for (from = 0; from < old_count; from++)
16361639
{
1637-
/* If we are in the scope of a larger range that can no longer
1638-
cover any further ranges, return back to the caller. */
1640+
struct unit_addrs *current_enclosing;
1641+
new_addrs[to] = old_addrs[from];
1642+
to++;
1643+
1644+
/* While we are in the scope of a larger range that can no longer
1645+
cover any further ranges, pop it from the enclosing stack. */
1646+
while (enclosing_count > 0
1647+
&& ((struct unit_addrs**)enclosing->base)[enclosing_count-1]->high <= old_addrs[from].low)
1648+
{
1649+
enclosing_count--;
1650+
enclosing->alc += sizeof (struct unit_addrs*);
1651+
}
1652+
if (enclosing_count > 0) {
1653+
current_enclosing = ((struct unit_addrs**)enclosing->base)[enclosing_count-1];
1654+
} else {
1655+
current_enclosing = NULL;
1656+
}
16391657

1640-
if (enclosing != NULL
1641-
&& enclosing->high <= old_addrs[from].low)
1642-
{
1643-
*pfrom = from;
1644-
*pto = to;
1645-
return 1;
1646-
}
16471658

1648-
new_addrs[to] = old_addrs[from];
16491659

16501660
/* If we are in scope of a larger range, fill in any gaps
16511661
between this entry and the next one.
16521662
16531663
There is an extra entry at the end of the vector, so it's
16541664
always OK to refer to from + 1. */
16551665

1656-
if (enclosing != NULL
1657-
&& enclosing->high > old_addrs[from].high
1658-
&& old_addrs[from].high < old_addrs[from + 1].low)
1659-
{
1660-
void *grew;
1661-
size_t new_high;
1666+
if (current_enclosing != NULL
1667+
&& current_enclosing->high > old_addrs[from].high
1668+
&& old_addrs[from].high < old_addrs[from + 1].low)
1669+
{
1670+
void *grew;
1671+
size_t new_high;
16621672

1663-
grew = backtrace_vector_grow (state, sizeof (struct unit_addrs),
1673+
grew = backtrace_vector_grow (state, sizeof (struct unit_addrs),
16641674
error_callback, data, &new_vec->vec);
1665-
if (grew == NULL)
1666-
return 0;
1667-
new_addrs = (struct unit_addrs *) new_vec->vec.base;
1668-
to++;
1669-
new_addrs[to].low = old_addrs[from].high;
1670-
new_high = old_addrs[from + 1].low;
1671-
if (enclosing->high < new_high)
1672-
new_high = enclosing->high;
1673-
new_addrs[to].high = new_high;
1674-
new_addrs[to].u = enclosing->u;
1675-
}
1675+
if (grew == NULL)
1676+
return 0;
1677+
new_addrs = (struct unit_addrs *) new_vec->vec.base;
1678+
new_addrs[to].low = old_addrs[from].high;
1679+
new_high = old_addrs[from + 1].low;
1680+
if (current_enclosing->high < new_high)
1681+
new_high = current_enclosing->high;
1682+
new_addrs[to].high = new_high;
1683+
new_addrs[to].u = current_enclosing->u;
1684+
to++;
1685+
}
16761686

16771687
/* If this range has a larger scope than the next one, use it to
1678-
fill in any gaps. */
1688+
fill in any gaps. */
16791689

16801690
if (old_addrs[from].high > old_addrs[from + 1].high)
1681-
{
1682-
*pfrom = from + 1;
1683-
*pto = to + 1;
1684-
if (!resolve_unit_addrs_overlap_walk (state, pfrom, pto,
1685-
&old_addrs[from], old_vec,
1686-
error_callback, data, new_vec))
1687-
return 0;
1688-
from = *pfrom;
1689-
to = *pto;
1690-
1691-
/* Undo the increment the loop is about to do. */
1692-
from--;
1693-
to--;
1694-
}
1691+
{
1692+
void* grew;
1693+
struct unit_addrs **enclosing_top;
1694+
1695+
grew = backtrace_vector_grow (state, sizeof (struct unit_addrs *),
1696+
error_callback, data, enclosing);
1697+
if (grew == NULL)
1698+
return 0;
1699+
enclosing_top = ((struct unit_addrs **) (enclosing->base)) + enclosing_count;
1700+
1701+
*enclosing_top = &old_addrs[from];
1702+
}
16951703
}
16961704

1697-
if (enclosing == NULL)
1698-
{
1699-
struct unit_addrs *pa;
1705+
1706+
1707+
struct unit_addrs *pa;
17001708

1701-
/* Add trailing entry. */
1709+
/* Add trailing entry. */
17021710

1703-
pa = ((struct unit_addrs *)
1704-
backtrace_vector_grow (state, sizeof (struct unit_addrs),
1705-
error_callback, data, &new_vec->vec));
1706-
if (pa == NULL)
1707-
return 0;
1708-
pa->low = 0;
1709-
--pa->low;
1710-
pa->high = pa->low;
1711-
pa->u = NULL;
1711+
pa = ((struct unit_addrs *)
1712+
backtrace_vector_grow (state, sizeof (struct unit_addrs),
1713+
error_callback, data, &new_vec->vec));
1714+
if (pa == NULL)
1715+
return 0;
1716+
pa->low = 0;
1717+
--pa->low;
1718+
pa->high = pa->low;
1719+
pa->u = NULL;
17121720

1713-
new_vec->count = to;
1714-
}
1721+
new_vec->count = to;
1722+
17151723

17161724
return 1;
17171725
}
@@ -1756,8 +1764,8 @@ resolve_unit_addrs_overlap (struct backtrace_state *state,
17561764
size_t i;
17571765
struct unit_addrs_vector new_vec;
17581766
void *grew;
1759-
size_t from;
1760-
size_t to;
1767+
int walk_ok;
1768+
struct backtrace_vector enclosing;
17611769

17621770
addrs = (struct unit_addrs *) addrs_vec->vec.base;
17631771
count = addrs_vec->count;
@@ -1787,15 +1795,16 @@ resolve_unit_addrs_overlap (struct backtrace_state *state,
17871795
error_callback, data, &new_vec.vec);
17881796
if (grew == NULL)
17891797
return 0;
1798+
memset (&enclosing, 0, sizeof enclosing);
17901799

1791-
from = 0;
1792-
to = 0;
1793-
resolve_unit_addrs_overlap_walk (state, &from, &to, NULL, addrs_vec,
1800+
walk_ok = resolve_unit_addrs_overlap_walk (state, &enclosing, addrs_vec,
17941801
error_callback, data, &new_vec);
17951802
backtrace_vector_free (state, &addrs_vec->vec, error_callback, data);
1796-
*addrs_vec = new_vec;
1803+
backtrace_vector_free (state, &enclosing, error_callback, data);
1804+
if (walk_ok)
1805+
*addrs_vec = new_vec;
17971806

1798-
return 1;
1807+
return walk_ok;
17991808
}
18001809

18011810
/* Sort the line vector by PC. We want a stable sort here to maintain

0 commit comments

Comments
 (0)