the project is called Vivisect and it has been using PyQt5. Vivisect is a binary analysis framework (eg. a disassembler)
this is a relatively stable project, but while recently attempting to add in filtering capabilities to various QTreeView widgets using QSortFilterProxyModel, i'm getting somewhat inconsistent segfaults, with very little context (ie. none other than printed debug statements).
i've looked through this thread but i haven't been able to stop the segfaulting completely: https://www.qtcentre.org/threads/692...Source-segfalt
when i start up analysis, it always crashes (it populates the various widgets):
here's the relative code snippits (links to full code listed below):Code:
$ vivbin /bin/chown Loaded (0.0685 sec) /bin/chown Beginning analysis... ...analyzing exports. 0x0200ad31: Emulation Found 0x0200afd0 (from func: 0x0200ad20) via call 0x0200afd0 libpng warning: iCCP: known incorrect sRGB profile libpng warning: iCCP: known incorrect sRGB profile ... Dynamic Branch found at 0x2001d48 call rax Segmentation fault (core dumped)
Code:
def __init__(self, parent=None): self.setDynamicSortFilter(True) self.setFilterKeyColumn(-1) def __getattr__(self, name): # the existing "navModel" includes a couple functions return getattr(self.sourceModel(), name) ''' This is the primary window for the VQViv*Views if they want to include filtering ''' window_title = '__undefined__' view_type = None def __init__(self, vw, vwqgui, *args, **kwargs): self.view = self.view_type(vw, vwqgui, *args, **kwargs) self.ffilt = VQFilterWidget(self) layout = vq_basics.VBox(self.view, self.ffilt) self.setLayout(layout) self.ffilt.filterChanged.connect(self.textFilterChanged) self.setWindowTitle(self.view.window_title) def textFilterChanged(self): self.ffilt.caseSensitivity(), self.ffilt.patternSyntax()) self.view.filterModel.setFilterRegExp(regExp) ''' A QT tree model that uses the tree API from visgraph to hold the data... ''' columns = ( 'A first column!', 'The Second Column!') editable = None dragable = False def __init__(self, parent=None, columns=None): if columns != None: self.columns = columns self.rootnode = VQTreeItem((), None) if self.editable == None: self.editable = [False,] * len(self.columns) def vqEdited(self, pnode, col, value): return value def append(self, rowdata, parent=None): if parent == None: parent = self.rootnode pidx = self.createIndex(parent.row(), 0, parent) i = len(parent.children) self.beginInsertRows(pidx, i, i) node = parent.append(rowdata) self.endInsertRows() self.layoutChanged.emit() return node ... def sort(self, colnum, order=0): cmpf = VQTreeSorter(colnum, order) self.layoutAboutToBeChanged.emit() self.rootnode.children.sort(cmp=cmpf) self.layoutChanged.emit() def flags(self, index): if not index.isValid(): return 0 col = index.column() if self.editable[col]: flags |= QtCore.Qt.ItemIsEditable if self.dragable: flags |= QtCore.Qt.ItemIsDragEnabled return flags def columnCount(self, parent=None): return len(self.columns) def data(self, index, role): if not index.isValid(): return None item = index.internalPointer() if role == QtCore.Qt.DisplayRole: return item.data(index.column()) if role == QtCore.Qt.UserRole: return item return None def setData(self, index, value, role=QtCore.Qt.EditRole): node = index.internalPointer() if not node: return False # If this is the edit role, fire the vqEdited thing if role == QtCore.Qt.EditRole: value = self.vqEdited(node, index.column(), value) if value == None: return False node.rowdata[index.column()] = value self.dataChanged.emit(index, index) return True def headerData(self, column, orientation, role): if ( orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole): return self.columns[column] return None def index(self, row, column, parent): if not self.hasIndex(row, column, parent): pitem = parent.internalPointer() if not pitem: pitem = self.rootnode item = pitem.child(row) if not item: return self.createIndex(row, column, item) def parent(self, index): if not index.isValid(): item = index.internalPointer() if not item: pitem = item.parent if pitem == self.rootnode: if pitem == None: return self.createIndex(pitem.row(), 0, pitem) ...
the working pull request is here: https://github.com/vivisect/vivisect/pull/237/files
the full branch is here: https://github.com/atlas0fd00m/vivis...filtered_views
i expect the bug is some simple thing i'm doing (eg. not providing a parent, or maybe connecting signals in incompatible ways, etc...)
but i'm at a complete loss. i don't understand why adding in a QSortFilterProxyModel would cause the entire python interpreter to segfault.
thank you in advance for any help and guidance you can provide? i'm relatively new to pyqt and qt in general, so don't worry about offending me.
let me know if you need any other context (or clarification)
@
Added after 9 minutes:
i ran out of room for these bits of relevant code.
Code:
class VQVivFunctionsViewPart(VQVivTreeView): _viv_navcol = 0 window_title = 'Functions' columns = ('Name','Address', 'Size', 'Ref Count') def __init__(self, vw, vwqgui): VQVivTreeView.__init__(self, vw, vwqgui, withfilter=True) self.navModel = VivNavModel(self._viv_navcol, self, columns=self.columns) self.filterModel = VivFilterModel() self.filterModel.setSourceModel(self.navModel) self.setModel(self.filterModel) self.vqLoad() self.vqSizeColumns() class VQVivFunctionsView(VivFilterView): view_type = VQVivFunctionsViewPart def __init__(self, parent=None, cols=None, **kwargs): self.setSortingEnabled(True) self.setAlternatingRowColors(True) if cols != None: model = VQTreeModel(parent=self, columns=cols) self.setModel( model ) def vqSizeColumns(self): c = self.model().columnCount() for i in xrange(c): self.resizeColumnToContents(i) def setModel(self, model): model.dataChanged.connect( self.dataChanged ) model.rowsInserted.connect( self.rowsInserted ) class EnviNavModel(vq_tree.VQTreeModel): dragable = True def __init__(self, navcol, parent=None, columns=None): vq_tree.VQTreeModel.__init__(self, parent=parent, columns=columns) self.navcol = navcol def mimeData(self, idx): pnode = idx[0].internalPointer() expr = pnode.rowdata[self.navcol] mdata.setData('envi/expression',str(expr)) return mdata
if you are looking through the codebase, the PyQt5 files of interest should be:
vivisect/qt/views.py
vqt/tree.py
envi/qt/memory.py
vqt/common.py
vivisect/qt/main.py
i realize it's a little complex, but i appreciate the help, and i'm happy to provide whatever context may make it easier to troubleshoot.
thanks!
@