Details
-
Epic
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.2.4, 6.3.0 RC, 6.4
-
None
-
qsizetype
-
-
144
-
8a1eb24de (dev), c1e1d133c (dev), 834062c5a (6.5)
Description
Let's be honest: the change from int to qsizetype sizes in Qt 6.0 was more than rushed. Half the API and a good chunk of implementation code is still using int when it should be using qsizetype, and we have been papering over this issue by making qMin() allow mixed-type arguments and, apparently, by removing the annoying MSVC warnings that, in Qt 5, so nicely pin-pointed all these implicit conversions as hard errors.
This epic collects all the BRs that have, in one way or the other, crept up by incomplete ports to qsizetype.
Porting Guide (ongoing)
General remarks
- keep the commits small
- please use topic "qsizetype" in Gerrit
- if you find a user-visible bug, commit separately, consider adding a test. Examples:
- don't mix different changes into the same commit
- helps reviewers do quicker passes by just looking for a pattern repeating
- don't take short-cuts
- really look at each int/uint whether it needs replacing with qsizetype/size_t
- not just now, but eventually, when this epic is done
- we're in this mess because we did take shortcuts in Qt 6.0
- really look at each int/uint whether it needs replacing with qsizetype/size_t
3rd-party code
- make sure to check what 3rd-party APIs expect (incl. OS APIs) and do range checks to avoid truncation
- either error out
- or chunk up the input and feed it bite-sized into size-constrained APIs
"int is enough"
- If your API is physically constrained to 16-bit or 32-bit sizes, it's fine to keep using qint16/int in the API
- but if your API accepts Qt containers, it has to reject containers that are too large
- once a large container makes it into your implementation, it can wreak havoc otherwise
- Note that 16/32-byte-sized API is the lazy programmer's way out, because it puts the onus to check for modulo arithmetic upon conversion from qsizetype/size_t squarely on the user of the API. This is neither Qt-ish nor C++-ish!
- Qt prides itself with ease of use, and difficulty to abuse, its APIs. An API that doesn't defend against silent modulo arithmetic is neither easy to use nor particularly hard to abuse.
- C++ puts the onus of complexity on the implementation of an API, not on the user.
- Taken together, an API that wants to restrict sizes to less-than-machine-word-sized should actively defend against narrowing conversions (modulo arithmetic) at the API level, e.g. by providing a function template and statically asserting that no narrowing happens.
- but if your API accepts Qt containers, it has to reject containers that are too large
sized for loops
- Check whether the loop must be sized (e.g. it's modified under iteration, or it iterates only a subset of the range)
- port to qsizetype counter variable if it has to stay sized
- port to ranged for loops if you're sure it can be
private API
- Just change it, port all in-tree callers
public non-exported API
- For setters, just change them, inspect all in-tree callers
- For getters, just change them
public exported API
- For setters:
- use QT_<MODULE>_REMOVED_SINCE && QT_POINTER_SIZE != 4 to remove the old function
- add the qsizetype overload alongside
- For getters:
- use QT6_ONLY/QT7_ONLY
- if this happens more often, we may want to add a q7sizetype that's int in Qt 6 and qsizetype in Qt 7
- use QT6_ONLY/QT7_ONLY