Browse Source

sh: Fix memory leak in dwarf_unwind_stack()

If we broke out of the while (1) loop because the return address of
"frame" was zero, then "frame" needs to be free'd before we return.

Signed-off-by: Matt Fleming <matt@console-pimps.org>
Matt Fleming 16 years ago
parent
commit
ed4fe7f488
2 changed files with 17 additions and 6 deletions
  1. 1 0
      arch/sh/include/asm/dwarf.h
  2. 16 6
      arch/sh/kernel/dwarf.c

+ 1 - 0
arch/sh/include/asm/dwarf.h

@@ -376,6 +376,7 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
 
 extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
 					      struct dwarf_frame *);
+extern void dwarf_free_frame(struct dwarf_frame *);
 extern int dwarf_parse_section(char *, char *, struct module *);
 extern void dwarf_module_unload(struct module *);
 

+ 16 - 6
arch/sh/kernel/dwarf.c

@@ -529,6 +529,16 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
 	return 0;
 }
 
+/**
+ *	dwarf_free_frame - free the memory allocated for @frame
+ *	@frame: the frame to free
+ */
+void dwarf_free_frame(struct dwarf_frame *frame)
+{
+	dwarf_frame_free_regs(frame);
+	mempool_free(frame, dwarf_frame_pool);
+}
+
 /**
  *	dwarf_unwind_stack - recursively unwind the stack
  *	@pc: address of the function to unwind
@@ -649,8 +659,7 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
 	return frame;
 
 bail:
-	dwarf_frame_free_regs(frame);
-	mempool_free(frame, dwarf_frame_pool);
+	dwarf_free_frame(frame);
 	return NULL;
 }
 
@@ -837,10 +846,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
 	while (1) {
 		frame = dwarf_unwind_stack(return_addr, _frame);
 
-		if (_frame) {
-			dwarf_frame_free_regs(_frame);
-			mempool_free(_frame, dwarf_frame_pool);
-		}
+		if (_frame)
+			dwarf_free_frame(_frame);
 
 		_frame = frame;
 
@@ -850,6 +857,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
 		return_addr = frame->return_addr;
 		ops->address(data, return_addr, 1);
 	}
+
+	if (frame)
+		dwarf_free_frame(frame);
 }
 
 static struct unwinder dwarf_unwinder = {