summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2013-07-02 16:36:16 +0200
committerMark Wielaard <mjw@redhat.com>2013-07-10 12:03:32 +0200
commit4aacfc156995739d388de524b5dd8c55e952e568 (patch)
tree5410a7773b3ec5d3650e374f78c0e8dd70ff3493 /libdw
parent8e5393c6799cdf07ab5f05bc8ab5d44929940e5f (diff)
downloadelfutils-4aacfc156995739d388de524b5dd8c55e952e568.tar.gz
libdw. Don't blow up stack in dwarf_getsrclines with lots of lines.
When a CU has a really large number of lines dwarf_getsrclines could blow up the stack because it uses alloca for temporary storage. Use malloc and free if the number of lines gets too big.
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog6
-rw-r--r--libdw/dwarf_getsrclines.c35
2 files changed, 33 insertions, 8 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 22f8b0c3..aa1e2ccf 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,11 @@
2013-07-02 Mark Wielaard <mjw@redhat.com>
+ * dwarf_getsrclines.c (dwarf_getsrclines): Add new stack allocation
+ limit MAX_STACK_ALLOC. After MAX_STACK_ALLOC lines use malloc in
+ NEW_LINE macro. Free malloced line records if any at the end.
+
+2013-07-02 Mark Wielaard <mjw@redhat.com>
+
* dwarf_getcfi_elf.c (getcfi_shdr): Check sh_type == SHT_PROGBITS.
2013-06-26 Mark Wielaard <mjw@redhat.com>
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index fa4dd18c..7b174cfc 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -75,6 +75,15 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
int res = -1;
+ struct linelist *linelist = NULL;
+ unsigned int nlinelist = 0;
+
+ /* If there are a large number of lines don't blow up the stack.
+ Keep track of the last malloced linelist record and free them
+ through the next pointer at the end. */
+#define MAX_STACK_ALLOC 4096
+ struct linelist *malloc_linelist = NULL;
+
/* Get the information if it is not already known. */
struct Dwarf_CU *const cu = cudie->cu;
if (cu->lines == NULL)
@@ -325,20 +334,26 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
}
/* Process the instructions. */
- struct linelist *linelist = NULL;
- unsigned int nlinelist = 0;
/* Adds a new line to the matrix.
We cannot simply define a function because we want to use alloca. */
#define NEW_LINE(end_seq) \
do { \
- if (unlikely (add_new_line (alloca (sizeof (struct linelist)), \
- end_seq))) \
+ struct linelist *ll = (nlinelist < MAX_STACK_ALLOC \
+ ? alloca (sizeof (struct linelist)) \
+ : malloc (sizeof (struct linelist))); \
+ if (nlinelist >= MAX_STACK_ALLOC) \
+ malloc_linelist = ll; \
+ if (unlikely (add_new_line (ll, end_seq))) \
goto invalid_data; \
} while (0)
inline bool add_new_line (struct linelist *new_line, bool end_sequence)
{
+ new_line->next = linelist;
+ linelist = new_line;
+ ++nlinelist;
+
/* Set the line information. For some fields we use bitfields,
so we would lose information if the encoded values are too large.
Check just for paranoia, and call the data "invalid" if it
@@ -365,10 +380,6 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
#undef SET
- new_line->next = linelist;
- linelist = new_line;
- ++nlinelist;
-
return false;
}
@@ -732,6 +743,14 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
}
out:
+ /* Free malloced line records, if any. */
+ for (unsigned int i = MAX_STACK_ALLOC; i < nlinelist; i++)
+ {
+ struct linelist *ll = malloc_linelist->next;
+ free (malloc_linelist);
+ malloc_linelist = ll;
+ }
+
// XXX Eventually: unlocking here.
return res;