Details
Description
The following code crashes only on arm64 (not tested on armv7) without JIT:
let o = []; o[10000] = 10; o[20000] = 20; for (let k in o) delete o[k]
but not
let o = {}; o.a = 10; o.b = 20; for (let k in o) delete o[k]
The difference is that in the first case, we are dealing with a SparseArray optimization.
The destructor of SparseArray shows that root() is nullable:
~SparseArray() { if (root()) freeTree(header.left, Q_ALIGNOF(SparseArrayNode)); } inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const { const SparseArrayNode *lb = root()->lowerBound(akey); ... } inline SparseArrayNode *SparseArrayNode::lowerBound(uint akey) { SparseArrayNode *n = this; SparseArrayNode *last = nullptr; while (n) { ... } return last; }
In debug mode, it probably will never crash because root()->lowerBound(akey) never dereferences this if this is null.
However, in release mode, the compiler knows that this is not nullable, so it can optimize the first `while( n )` check to `do {} while( n )` which it does on arm64 at least
Attachments
For Gerrit Dashboard: QTBUG-123596 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
552654,2 | V4: Don't call methods on nullptr | dev | qt/qtdeclarative | Status: MERGED | +2 | 0 |
553151,2 | V4: Don't call methods on nullptr | 6.7 | qt/qtdeclarative | Status: MERGED | +2 | 0 |
553278,2 | V4: Don't call methods on nullptr | tqtc/lts-6.5 | qt/tqtc-qtdeclarative | Status: MERGED | +2 | 0 |
553445,2 | V4: Don't call methods on nullptr | tqtc/lts-6.2 | qt/tqtc-qtdeclarative | Status: MERGED | +2 | 0 |
553628,3 | V4: Don't call methods on nullptr | tqtc/lts-5.15 | qt/tqtc-qtdeclarative | Status: MERGED | +2 | 0 |