Plug leak of debug info handles

On recent elfutils where the libdw's function dwarf_getalt exists, we
don't need to try and find the alternate debug info file ourselves by
using the function dwfl_standard_find_debuginfo.  Furthermore, when we
use that function on those recent elfutils versions, we leak the elf
resources allocated in the debug info resources; we also leak the file
descriptor to access the alternate debug info sections.

More generally, we also leak debug info handles used to access debug
info when using get_soname_of_elf_file and get_type_of_elf_file.

This patch plugs those leaks.

In the first case, if the function dwarf_getalt exists, the patch just
uses it to get the alternate debug info.  Otherwise, the patch uses
the dwfl_standard_find_debuginfo function like we used to, but then it
tries hard to free the file descriptor and debuginfo memory of the
alternate debug info.

	* configure.ac: Check the presence of dwarf_getalt in libdw.  If
	it's present, define the preprocessor macro
	LIBDW_HAS_DWARF_GETALT.  Update the autoconf configuration
	summary.
	* src/abg-dwarf-reader.cc: Add config.h.
	(find_alt_debug_info_location): Factorize this out of ...
	(find_alt_debug_info): ... this function.  Use dwarf_getalt if
	present, otherwise, keep using dwfl_standard_find_debuginfo.  In
	the later case, return the file descriptor opened to access the
	alternate debug info, by parameter, so that the caller can fclose
	it.
	(read_context::alt_fd_): New data member.
	(read_context::read_context): Initialize the new alt_fd_ data
	member.
	(read_context::load_debug_info): Store the file descriptor used to
	access the alternate debug info into the new alt_fd_ data member.
	(read_context::~read_context): New desctructor.
	(get_soname_of_elf_file, get_type_of_elf_file): Free the elf
	handle.
	(read_context::load_debug_info): Be paranoid in making sure we
	never override alt_dwarf_.
	* tests/data/test-alt-dwarf-file/test0-report.txt: Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2016-05-22 11:39:33 +02:00
parent 00f79732fb
commit ce5e4889b1
3 changed files with 129 additions and 49 deletions

View File

@ -124,11 +124,14 @@ AC_CHECK_HEADER([libelf.h],
DW_LIBS=
AC_CHECK_LIB(dw, dwfl_begin, [DW_LIBS=-ldw])
AC_CHECK_LIB(dw, dwarf_getalt,
[FOUND_DWARF_GETALT_IN_LIBDW=yes],
[FOUND_DWARF_GETALT_IN_LIBDW=no])
AC_CHECK_HEADER(elfutils/libdwfl.h,
[],
[AC_MSG_ERROR([could not find elfutils/libdwfl.h installed])])
if test x$ELF_LIBS = x; then
AC_MSG_ERROR([could not find elfutils elf library installed])
fi
@ -137,6 +140,11 @@ if test x$DW_LIBS = x; then
AC_MSG_ERROR([could not find elfutils dwarf library installed])
fi
if test x$FOUND_DWARF_GETALT_IN_LIBDW=xyes; then
AC_DEFINE([LIBDW_HAS_DWARF_GETALT], 1,
[Defined if libdw has the function dwarf_getalt])
fi
AC_SUBST(DW_LIBS)
AC_SUBST([ELF_LIBS])
@ -477,6 +485,7 @@ AC_MSG_NOTICE([
OPTIONAL FEATURES:
Enable zip archives : ${ENABLE_ZIP_ARCHIVE}
Use a C++-11 compiler : ${ENABLE_CXX11}
libdw has the dwarf_getalt function : ${FOUND_DWARF_GETALT_IN_LIBDW}
Enable rpm support in abipkgdiff : ${ENABLE_RPM}
Enable deb support in abipkgdiff : ${ENABLE_DEB}
Enable GNU tar archive support in abipkgdiff : ${ENABLE_TAR}

View File

@ -26,6 +26,7 @@
/// de-serialize an instance of @ref abigail::corpus from a file in
/// elf format, containing dwarf information.
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -839,30 +840,27 @@ get_binary_load_address(Elf *elf_handle,
return false;
}
/// Return the alternate debug info associated to a given main debug
/// info file.
/// Find the file name of the alternate debug info file, as well as
/// its build ID.
///
/// @param elf_module the elf module to consider.
///
/// @param alt_file_name output parameter. This is set to the file
/// path of the alternate debug info file associated to @p elf_module.
/// This is set iff the function returns a non-null result.
/// @param out parameter. Is set to the file name of the alternate
/// debug info file, iff this function returns true.
///
/// Note that the alternate debug info file is a DWARF extension as of
/// DWARF 4 ans is decribed at
/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
/// @param out parameter. Is set to the build ID of the alternate
/// debug info file.
///
/// @return the alternate debuginfo, or null
///
static Dwarf*
find_alt_debug_info(Dwfl_Module *elf_module,
string& alt_file_name)
/// @return true iff the location of the alternate debug info file was
/// found.
static bool
find_alt_debug_info_location(Dwfl_Module *elf_module,
string &alt_file_name,
string &build_id)
{
if (elf_module == 0)
return 0;
GElf_Addr bias = 0;
Elf *elf = dwarf_getelf(dwfl_module_getdwarf(elf_module, &bias));
Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
Elf *elf = dwarf_getelf(dwarf);
GElf_Ehdr ehmem, *elf_header;
elf_header = gelf_getehdr(elf, &ehmem);
@ -879,8 +877,8 @@ find_alt_debug_info(Dwfl_Module *elf_module,
header->sh_name);
char *alt_name = 0;
char *build_id = 0;
size_t build_id_len = 0;
char *buildid = 0;
size_t buildid_len = 0;
if (section_name != 0
&& strcmp(section_name, ".gnu_debugaltlink") == 0)
{
@ -890,39 +888,91 @@ find_alt_debug_info(Dwfl_Module *elf_module,
alt_name = (char*) data->d_buf;
char *end_of_alt_name =
(char *) memchr(alt_name, '\0', data->d_size);
build_id_len = data->d_size - (end_of_alt_name - alt_name + 1);
if (build_id_len == 0)
return 0;
build_id = end_of_alt_name + 1;
buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
if (buildid_len == 0)
return false;
buildid = end_of_alt_name + 1;
}
}
else
continue;
if (build_id == 0 || alt_name == 0)
return 0;
if (buildid == 0 || alt_name == 0)
return false;
const char *file_name = 0;
void **user_data = 0;
Dwarf_Addr low_addr = 0;
char *alt_file = 0;
file_name = dwfl_module_info(elf_module, &user_data,
&low_addr, 0, 0, 0, 0, 0);
int alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
file_name, low_addr,
alt_name, file_name,
0, &alt_file);
Dwarf *result = dwarf_begin(alt_fd, DWARF_C_READ);
if (alt_file)
alt_file_name = alt_file;
return result;
build_id = buildid;
alt_file_name = alt_name;
return true;
}
return 0;
return false;
}
/// Return the alternate debug info associated to a given main debug
/// info file.
///
/// @param elf_module the elf module to consider.
///
/// @param alt_file_name output parameter. This is set to the file
/// path of the alternate debug info file associated to @p elf_module.
/// This is set iff the function returns a non-null result.
///
/// @param alt_fd the file descriptor used to access the alternate
/// debug info. If this parameter is set by the function, then the
/// caller needs to fclose it, otherwise the file descriptor is going
/// to be leaked. Note however that on recent versions of elfutils
/// where libdw.h contains the function dwarf_getalt(), this parameter
/// is set to 0, so it doesn't need to be fclosed.
///
/// Note that the alternate debug info file is a DWARF extension as of
/// DWARF 4 ans is decribed at
/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
///
/// @return the alternate debuginfo, or null. If @p alt_fd is
/// non-zero, then the caller of this function needs to call
/// dwarf_end() on the returned alternate debuginfo pointer,
/// otherwise, it's going to be leaked.
static Dwarf*
find_alt_debug_info(Dwfl_Module *elf_module,
string& alt_file_name,
int& alt_fd)
{
if (elf_module == 0)
return 0;
Dwarf* result = 0;
string build_id;
find_alt_debug_info_location(elf_module, alt_file_name, build_id);
#ifdef LIBDW_HAS_DWARF_GETALT
// We are on recent versions of elfutils where the function
// dwarf_getalt exists, so let's use it.
Dwarf_Addr bias = 0;
Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
result = dwarf_getalt(dwarf);
alt_fd = 0;
#else
// We are on an old version of elfutils where the function
// dwarf_getalt doesn't exist yet, so let's open code its
// functionality
char *alt_name = 0;
const char *file_name = 0;
void **user_data = 0;
Dwarf_Addr low_addr = 0;
char *alt_file = 0;
file_name = dwfl_module_info(elf_module, &user_data,
&low_addr, 0, 0, 0, 0, 0);
alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
file_name, low_addr,
alt_name, file_name,
0, &alt_file);
result = dwarf_begin(alt_fd, DWARF_C_READ);
#endif
return result;
}
/// Compare a symbol name against another name, possibly demangling
@ -1999,7 +2049,12 @@ class read_context
Dwarf* dwarf_;
// The alternate debug info. Alternate debug info sections are a
// DWARF extension as of DWARF4 and are described at
// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1. Below are
// the file desctor used to access the alternate debug info
// sections, and the representation of the DWARF debug info. Both
// need to be freed after we are done using them, with fclose and
// dwarf_end.
int alt_fd_;
Dwarf* alt_dwarf_;
string alt_debug_info_path_;
// The address range of the offline elf file we are looking at.
@ -2086,6 +2141,7 @@ public:
dwarf_version_(),
handle_(),
dwarf_(),
alt_fd_(),
alt_dwarf_(),
elf_module_(),
elf_handle_(),
@ -2106,6 +2162,17 @@ public:
memset(&offline_callbacks_, 0, sizeof(offline_callbacks_));
}
/// Detructor of the @ref read_context type.
~read_context()
{
if (alt_fd_)
{
close(alt_fd_);
if (alt_dwarf_)
dwarf_end(alt_dwarf_);
}
}
/// Clear the data that is relevant only for the current translation
/// unit being read. The rest of the data is relevant for the
/// entire ABI corpus.
@ -2283,9 +2350,11 @@ public:
dwfl_report_end(dwfl_handle().get(), 0, 0);
Dwarf_Addr bias = 0;
dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
alt_dwarf_ = find_alt_debug_info(elf_module_, alt_debug_info_path_);
if (!alt_dwarf_)
alt_dwarf_ = find_alt_debug_info(elf_module_,
alt_debug_info_path_,
alt_fd_);
return dwarf_;
}
@ -9772,6 +9841,7 @@ get_soname_of_elf_file(const string& path, string &soname)
}
}
elf_end(elf);
close(fd);
return true;
@ -9797,6 +9867,7 @@ get_type_of_elf_file(const string& path, elf_type& type)
elf_version (EV_CURRENT);
Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
type = elf_file_type(elf);
elf_end(elf);
close(fd);
return true;

View File

@ -1 +1 @@
found the alternate debug info file '7088580c513b439c9ed95fe6a8b29496495f26.debug'
found the alternate debug info file 'test0-common-dwz.debug'