<div dir="auto">Hello Maurizio </div><div dir="auto"><br></div><div dir="auto">Thank you for your message and explanation. It makes sense to me. I followed these principles in all my other models but this particular model had this bug which I somehow missed and only after Qt 6.9.1 did it become a problem.</div><div dir="auto">I did actually try to get more debug data from Qt using windbg after I made the original post. I failed at my attempt to link Qt debug symbols but I did get a single line about the crash occurring in the new QSortFilterProxyModel create recursive mapping function, which confirmed my suspicion that the change comes from the Qt bug 76976.</div><div dir="auto">Thanks again.</div><div dir="auto"><br></div><div dir="auto">Kind regards</div><div dir="auto">Jakub</div><div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">st 19. 11. 2025 v 4:06 odesílatel Maurizio Berti <<a href="mailto:maurizio.berti@gmail.com">maurizio.berti@gmail.com</a>> napsal:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)"><div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Il giorno lun 17 nov 2025 alle ore 00:45 Jakub Fránek <<a href="mailto:j.franek95@gmail.com" target="_blank">j.franek95@gmail.com</a>> ha scritto:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)"><div dir="ltr">What my code did previously was something like this, in Pythonesque pseudocode:<br><div><br></div><div>custom_source_model.beginResetModel()</div><div>
custom_source_model.load_data(new_data)</div><div>source_index = custom_source_model.get_index(some_item)</div><div>proxy_index = proxy.mapFromSource(source_index) # crash occurs here<br></div><div># irrelevant lines of code which utilize the proxy_index somehow...</div><div>
custom_source_model.endResetModel()<br><br></div><div>My understanding is that what I did is incorrect and I should not perform any operations on the proxy model while the main model is in reset. When I postpone these index related operations until after the custom_source_model.endResetModel() call, the segmentation fault does not occur.</div></div></blockquote><div><br></div><div>Actually, you should avoid performing *any* other model operation within a begin/end model "block", as they cannot be nested.</div><div>Trying to get a QModelIndex in the middle of an operation that may change the shape or layout of a model is inappropriate, as that index would easily become invalid. Qt also uses internal pointers to map source indexes, and if you change the source (and therefore what those pointers refer to) before the proxy is notified, some issues may occur, as those pointers are completely managed by Qt on the "C++ side", which has a more delicate mechanism when dealing with memory access.</div><div><br></div><div>Also, as a rule of thumb, if a program using bindings like PyQt crashes without any Python traceback, you should always assume that the problem may as well (if not even more likely) be related to the underlying library used by the binding, so it's important to always check its bug report system and the changelogs for that original library. Also remember that PyQt and Qt version numbers don't always match, even though Phil is trying to make them more consistent than in the past, so always ensure if they actually match (and notify it in your posts if they do, or show both versions if they don't).<br></div><div><br></div><div>I'm quite inclined to think that the problem is caused by Qt indeed; PyQt may have some involvement, but I don't think it's that relevant, as the problem mostly resides on inappropriate implementation to begin with. Most importantly, QSortFilterProxyModel uses the "end" modelReset signal to actually reset its own pointers and persistent indexes, which it "believed" were valid up to that point in your code, even if they're not anymore, as the original model has already changed: the internal pointers used to create the related QModelIndexes don't match the mapping that the proxy has internally created.</div><div><br></div><div>I may be wrong, but I believe that the culprit could be the recent change done for QTBUG-76976 ( <a href="https://bugreports.qt.io/browse/QTBUG-76976" target="_blank">https://bugreports.qt.io/browse/QTBUG-76976</a> ), which seems to be quite compatible considering the accessed types and the specific version: the new implementation resides on a recursive search based on the existing mapping, and I think that the inconsistency created by the change in the source (which hasn't notified the proxy about its changes yet) is what causes the crash, as mapFromSource() is trying to *access* pointers that are not valid anymore.<br></div><div><br></div><div>I may be completely wrong about this and the problem is probably caused by a change in PyQt 6.9.1, but the following facts remain:</div><div>- never try to call any other Qt model function (including anything that may affect any related Qt type, such as emitting signals that would notify "watchers" of that model) within a change that involves begin/end functions and related signals, especially *after* changes have been made and *before* the "end" function call;</div><div>- remember that some aspects in the above "watchers" require that you follow the expected procedure: complex synchronous objects like proxy models expect that *both* "begin" and "end" signals are emitted consistently, and their behavior depends on when their internal calls happen, based on their known state: a "begin" signal possibly causes "storing" (or assuming) an internal state based on known aspects of the source *before* any change, and anything called *before* the "end" still expects that any call on the source would still be valid/consistent with the original state, or that the change would be taken into consideration;</div><div>- due to the above, you cannot reliably use an index of the source model in the proxy, if the source shape/layout has changed in the meantime but the change has not been finalized yet with the "end" signal;<br></div><div>- always try to follow proper encapsulation principles: beginResetModel() and endResetModel() should normally be called "internally" by the custom model (in your case, at the very beginning and end of load_data()); there are cases for which that's not possible/viable/acceptable due to complex implementation, but in those cases you should *really* know what you're doing and the consequences of those actions: make efforts to keep model changes by using "enclosed" functions, especially if they require more than one logic step on the Qt side;<br></div><div>- while the "Occam's razor" principle is always a good hint to begin with, never assume anything just because it's the most simple explanation: bindings require complex implementations, abstraction layers and some level of "hacking" the features of a programming language; if you're relying on "something external", you should consider it as a possible cause as well;</div><div><br></div><div>Best regards,</div><div>MaurizioB</div></div></div><div dir="ltr"><div class="gmail_quote"><div><br></div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature">È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div></div>
</blockquote></div></div>