diff --git a/lib/entropy/tools.py b/lib/entropy/tools.py index 65a569a5c..cb484826f 100644 --- a/lib/entropy/tools.py +++ b/lib/entropy/tools.py @@ -2724,8 +2724,6 @@ def read_elf_real_dynamic_libraries(elf_file): return outcome -ldd_avail_check = False - def read_elf_broken_symbols(elf_file): """ Extract broken symbols from ELF file. @@ -2735,14 +2733,45 @@ def read_elf_broken_symbols(elf_file): @return: list of broken symbols in ELF file. @rtype: set """ - global ldd_avail_check - if not ldd_avail_check: - if not const_file_readable("/usr/bin/ldd"): - raise FileNotFound('FileNotFound: no ldd') - ldd_avail_check = True - return set([x.strip().split("\t")[0].split()[-1] for x in \ - getstatusoutput('/usr/bin/ldd -r "%s"' % (elf_file,))[1].split("\n") \ - if (x.find("undefined symbol:") != -1)]) + proc = None + args = ("/usr/bin/ldd", "-r", elf_file) + out = None + + try: + proc = subprocess.Popen( + args, stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + exit_st = proc.wait() + if exit_st != 0: + raise FileNotFound("ldd error") + + out = "" + while True: + # make sure that stdout is flushed and won't block + proc.stdout.read() + tout = proc.stderr.read() + out += tout + if not tout: + break + + except (OSError, IOError) as err: + if err.errno != errno.ENOENT: + raise + raise FileNotFound("/usr/bin/ldd not found") + + finally: + if proc is not None: + proc.stderr.close() + proc.stdout.close() + + outcome = set() + if out is not None: + for line in out.split("\n"): + if line.startswith("undefined symbol: "): + symbol = line.split("\t")[0].split()[-1] + outcome.add(symbol) + + return outcome readelf_avail_check = False diff --git a/lib/tests/_misc.py b/lib/tests/_misc.py index a4873e965..0235eaf72 100644 --- a/lib/tests/_misc.py +++ b/lib/tests/_misc.py @@ -67,6 +67,10 @@ def get_test_video_file(): test_pkg = "test.flv" return get_test_generic_package(test_pkg) +def get_test_so_1(): + test_pkg = "sip.so" + return get_test_generic_package(test_pkg) + def get_test_packages_and_atoms(): data = { 'media-gfx/pdf2svg': get_test_entropy_package5(), diff --git a/lib/tests/packages/sip.so b/lib/tests/packages/sip.so new file mode 100755 index 000000000..8e6831116 Binary files /dev/null and b/lib/tests/packages/sip.so differ diff --git a/lib/tests/tools.py b/lib/tests/tools.py index c15bba528..94229f9ae 100644 --- a/lib/tests/tools.py +++ b/lib/tests/tools.py @@ -482,6 +482,69 @@ class ToolsTest(unittest.TestCase): metadata = et.read_elf_real_dynamic_libraries(elf_obj) self.assertEqual(metadata, known_meta) + def test_read_elf_broken_symbols(self): + elf_obj = _misc.get_test_so_1() + known_meta = set(['PyDict_SetItem', 'PyArg_ParseTuple', + 'PyList_New', 'PyList_Append', 'PyFunction_Type', + 'PyExc_AttributeError', 'PyImport_Import', 'PyObject_Init', + 'PyDict_Size', 'PyInt_AsLong', 'PyImport_ImportModule', + 'PyUnicodeUCS4_DecodeASCII', 'PyExc_DeprecationWarning', + 'PyErr_SetObject', 'PyExc_NotImplementedError', 'PyInt_Type', + 'PyErr_Occurred', 'PyClass_Type', 'PyWrapperDescr_Type', + 'PyDict_GetItemString', 'PyLong_FromLong', + 'PyObject_AsCharBuffer', 'Py_AtExit', 'PyLong_FromLongLong', + 'PyErr_Restore', 'PyErr_Print', 'PyObject_CallFunction', + 'PyLong_AsLong', 'PyOS_snprintf', 'PyErr_SetNone', + 'PyLong_AsUnsignedLongMask', 'PyEval_InitThreads', + 'PyProperty_Type', 'PyFloat_AsDouble', 'PyObject_GC_UnTrack', + 'PyWeakref_NewRef', 'PySequence_GetItem', 'PyCObject_Type', + 'PyFloat_FromDouble', 'PySlice_GetIndicesEx', + 'PyExc_SystemError', 'PyErr_NoMemory', 'PyMethod_New', + 'PyErr_SetString', 'PyLong_AsLongLong', 'PyObject_IsInstance', + 'Py_InitModule4_64', 'PyInt_FromSsize_t', 'PyType_Type', + 'PyCallable_Check', '_Py_NoneStruct', 'PyDescr_NewMethod', + 'PyUnicodeUCS4_AsASCIIString', 'PyBool_FromLong', + 'PyObject_CallObject', '_Py_NotImplementedStruct', + 'PyObject_GetBuffer', 'PySlice_Type', + 'PyUnicodeUCS4_DecodeLatin1', 'PyEval_CallObjectWithKeywords', + 'PyCapsule_GetPointer', 'PyExc_BufferError', + 'PyExc_ValueError', 'PyBuffer_Release', + 'PyThread_get_thread_ident', 'PyExc_NameError', + 'Py_FatalError', 'PyGILState_Ensure', 'PyObject_GetAttr', + 'PyDictProxy_New', 'PyExc_RuntimeError', + 'PyUnicodeUCS4_AsWideChar', 'PyInt_FromLong', 'PyTuple_Type', + 'PyBool_Type', 'PyObject_Str', 'PyGILState_Release', + 'PyUnicodeUCS4_FromObject', 'PyModule_GetDict', + 'PyLong_AsVoidPtr', 'PyCObject_AsVoidPtr', + 'PyString_FromString', 'PyObject_Call', + 'PyObject_CheckReadBuffer', 'PyObject_Print', + 'PyDict_GetItem', 'PyType_IsSubtype', 'PyObject_AsReadBuffer', + 'PyCFunction_NewEx', 'PyMem_Free', 'PyDict_SetItemString', + 'PyString_AsString', '_Py_TrueStruct', + 'PyUnicodeUCS4_DecodeUTF8', 'PyNumber_AsSsize_t', + 'PyErr_WarnEx', 'PyLong_FromVoidPtr', 'PyWeakref_GetObject', + 'PyDict_Contains', 'PyUnicodeUCS4_AsUTF8String', + 'PyErr_Fetch', 'PyInt_AsSsize_t', 'PyCapsule_New', + 'PyType_Modified', 'PyErr_Clear', 'PyFloat_Type', + 'PyType_Ready', 'PyExc_Exception', 'PyExc_TypeError', + 'PyObject_Malloc', 'PyImport_GetModuleDict', + 'PyLong_FromUnsignedLong', 'PyType_GenericAlloc', + 'PyTuple_GetSlice', 'PyMethod_Type', + 'PyLong_AsUnsignedLongLongMask', 'PyMem_Malloc', + 'PyUnicodeUCS4_AsLatin1String', 'PyErr_Format', + 'PyExc_IndexError', 'PyBuffer_FillInfo', 'PyTuple_Pack', + 'PyString_FromStringAndSize', 'Py_BuildValue', + 'PyObject_GetAttrString', 'PyTuple_New', + 'PyUnicodeUCS4_FromWideChar', 'PyArg_ParseTupleAndKeywords', + 'PyDict_Next', 'PyLong_FromUnsignedLongLong', 'PyDict_New', + 'PyString_ConcatAndDel', 'PyCFunction_Type', '_Py_ZeroStruct', + 'PyThreadState_Get', 'PyString_FromFormat', + 'PyObject_CallFunctionObjArgs', 'PyCapsule_Type', + 'PyErr_GivenExceptionMatches', 'PyCObject_FromVoidPtr', + 'PyBaseObject_Type', 'PyObject_SetAttr', 'PySequence_Size']) + metadata = et.read_elf_broken_symbols(elf_obj) + self.assertEqual(metadata, known_meta) + def test_read_elf_linker_paths(self): elf_obj = _misc.get_dl_so_amd_2() known_meta = ['/usr/lib64', '/usr/lib64']