mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-03 17:34:12 +02:00
Fix a symbol with a huge size aborting QElectroTech in its preview
ElementPictureFactory::pixmap() made a pixmap of whatever width and height the symbol file declares. A symbol whose parts span 280 000 px (made by the GUI fuzzer in the symbol editor) asked for a ~315 GB pixmap. Under AddressSanitizer that aborts QElectroTech; the symbol then sat in the user collection and every later start died loading its icon. The preview is now drawn scaled down to fit 4096 px on its longer side. The largest symbols in the shipped collection are 3160 px, so none of them changes. The size is also bounded before it is rounded up to a multiple of 10, so a crafted value near INT_MAX cannot overflow. Checked with a user collection holding one symbol declared 280000 x 280000, on ASan builds: master aborts (out of memory, exit 1) 3/3 when the collection is expanded; with this change QElectroTech keeps running and lists the symbol, 3/3. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -135,14 +135,29 @@ QPixmap ElementPictureFactory::pixmap(const ElementsLocation &location)
|
||||
{
|
||||
auto doc = location.pugiXml();
|
||||
//size
|
||||
int w = doc.document_element().attribute("width").as_int();
|
||||
int h = doc.document_element().attribute("height").as_int();
|
||||
//Bounded first, so the rounding below cannot overflow on a
|
||||
//crafted file.
|
||||
int w = qBound(0, doc.document_element().attribute("width").as_int(), 1000000);
|
||||
int h = qBound(0, doc.document_element().attribute("height").as_int(), 1000000);
|
||||
while (w % 10) ++ w;
|
||||
while (h % 10) ++ h;
|
||||
//hotspot
|
||||
int hsx = qMin(doc.document_element().attribute("hotspot_x").as_int(), w);
|
||||
int hsy = qMin(doc.document_element().attribute("hotspot_y").as_int(), h);
|
||||
|
||||
//The size comes straight from the file. A symbol whose parts
|
||||
//span hundreds of thousands of pixels would ask for a pixmap of
|
||||
//hundreds of gigabytes; draw it scaled down to fit instead. The
|
||||
//largest symbols in the shipped collection are about 3200 px,
|
||||
//so this only changes files nobody would draw on purpose.
|
||||
const int max_side = 4096;
|
||||
qreal scale = 1.0;
|
||||
if (w > max_side || h > max_side) {
|
||||
scale = qreal(max_side) / qMax(w, h);
|
||||
w = qMax(1, qRound(w * scale));
|
||||
h = qMax(1, qRound(h * scale));
|
||||
}
|
||||
|
||||
QPixmap pix(w, h);
|
||||
//Element definitions almost always draw with a hardcoded black
|
||||
//stroke color, on the assumption of the white diagram sheet they
|
||||
@@ -157,6 +172,7 @@ QPixmap ElementPictureFactory::pixmap(const ElementsLocation &location)
|
||||
QPainter painter(&pix);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
painter.scale(scale, scale);
|
||||
painter.translate(hsx, hsy);
|
||||
painter.drawPicture(0, 0, m_pictures_H.value(uuid));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user