Skip to content

Commit d0a7e85

Browse files
committed
Early catch potential overflow issue #43
`m_width` and `m_height` are of `int` type in the OpenEXR library. We currently keep the same types in our class but this may case issue when mapping 1D memory. In the most favorable case, they are multiplied together (Y framebuffer). For RGB(A) case, the required memory can also be 4 time larger. We check if resp. `m_width * m_height` and `4 * m_width * m_heigh` stay within the `int` higher limit. Thanks to @GAP-dev for bringing this issue. This commit also cleans a bit raw memory allocation in favor of `std::vector` container.
1 parent 70cc941 commit d0a7e85

File tree

4 files changed

+43
-25
lines changed

4 files changed

+43
-25
lines changed

src/model/framebuffer/FramebufferModel.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939

4040
FramebufferModel::FramebufferModel(QObject* parent)
4141
: QObject(parent)
42-
, m_pixelBuffer(nullptr)
4342
, m_width(0)
4443
, m_height(0)
4544
, m_isImageLoaded(false)
@@ -59,7 +58,4 @@ QRect FramebufferModel::getDataWindow() const
5958
return m_dataWindow;
6059
}
6160

62-
FramebufferModel::~FramebufferModel()
63-
{
64-
delete[] m_pixelBuffer;
65-
}
61+
FramebufferModel::~FramebufferModel() {}

src/model/framebuffer/FramebufferModel.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#include <QObject>
3838
#include <QRect>
3939
#include <QVector>
40-
#include <array>
40+
#include <vector>
4141

4242
class FramebufferModel: public QObject
4343
{
@@ -67,8 +67,8 @@ class FramebufferModel: public QObject
6767
void loadFailed(QString message);
6868

6969
protected:
70-
float* m_pixelBuffer;
71-
QImage m_image;
70+
std::vector<float> m_pixelBuffer;
71+
QImage m_image;
7272

7373
// Right now, the width and height are defined as Vec2i in OpenEXR
7474
// i.e. int type.

src/model/framebuffer/RGBFramebufferModel.cpp

+22-13
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ void RGBFramebufferModel::load(
8181
m_displayWindow
8282
= QRect(dispW.min.x, dispW.min.y, dispW_width, dispW_height);
8383

84+
// Check to avoid type overflow, width and height are 32bits int
85+
// representing a 2 dimentional image. Can overflow the type when
86+
// multiplied together.
87+
// 0x1FFFFFFF is a save limit for 4 * 0x7FFFFFFF the max
88+
// representable int since we need 4 channels.
89+
// TODO: Use larger type when manipulating framebuffer
90+
const uint64_t partial_size
91+
= (uint64_t)m_width * (uint64_t)m_height;
92+
93+
if (partial_size > 0x1FFFFFFF) {
94+
throw std::runtime_error(
95+
"The total image size is too large. May be supported in a "
96+
"future revision.");
97+
}
98+
99+
m_pixelBuffer.resize(4 * m_width * m_height);
100+
84101
// Check if there is specific chromaticities tied to the color
85102
// representation in this part.
86103
const Imf::ChromaticitiesAttribute* c
@@ -93,8 +110,6 @@ void RGBFramebufferModel::load(
93110
chromaticities = c->value();
94111
}
95112

96-
m_pixelBuffer = new float[4 * m_width * m_height];
97-
98113
// Check if there is alpha channel
99114
if (hasAlpha) {
100115
std::string aLayer = m_parentLayer + "A";
@@ -190,12 +205,12 @@ void RGBFramebufferModel::load(
190205

191206
Imf::FrameBuffer framebuffer;
192207

193-
Imf::Rgba* buff1 = new Imf::Rgba[m_width * m_height];
194-
Imf::Rgba* buff2 = new Imf::Rgba[m_width * m_height];
208+
std::vector<Imf::Rgba> buff1(m_width * m_height);
209+
std::vector<Imf::Rgba> buff2(m_width * m_height);
195210

196-
float* yBuffer = new float[m_width * m_height];
197-
float* ryBuffer = new float[m_width / 2 * m_height / 2];
198-
float* byBuffer = new float[m_width / 2 * m_height / 2];
211+
std::vector<float> yBuffer(m_width * m_height);
212+
std::vector<float> ryBuffer(m_width / 2 * m_height / 2);
213+
std::vector<float> byBuffer(m_width / 2 * m_height / 2);
199214

200215
Imf::Slice ySlice = Imf::Slice::Make(
201216
Imf::PixelType::FLOAT,
@@ -335,12 +350,6 @@ void RGBFramebufferModel::load(
335350
m_pixelBuffer[4 * (y * m_width + x) + 2] = rgb.z;
336351
}
337352
}
338-
339-
delete[] yBuffer;
340-
delete[] ryBuffer;
341-
delete[] byBuffer;
342-
delete[] buff1;
343-
delete[] buff2;
344353
}
345354

346355
break;

src/model/framebuffer/YFramebufferModel.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,25 @@ void YFramebufferModel::load(Imf::MultiPartInputFile& file, int partId)
9090
dispW_width / 2,
9191
dispW_height / 2);
9292

93-
m_pixelBuffer = new float[m_width * m_height];
93+
// Check to avoid type overflow, width and height are 32bits int
94+
// representing a 2 dimentional image. Can overflow the type when
95+
// multiplied together
96+
// TODO: Use larger type when manipulating framebuffer
97+
const uint64_t partial_size
98+
= (uint64_t)m_width * (uint64_t)m_height;
99+
100+
if (partial_size > 0x7FFFFFFF) {
101+
throw std::runtime_error(
102+
"The total image size is too large. May be supported in "
103+
"a future revision.");
104+
}
105+
106+
m_pixelBuffer.resize(m_width * m_height);
94107

95108
// Luminance Chroma channels
96109
graySlice = Imf::Slice::Make(
97110
Imf::PixelType::FLOAT,
98-
m_pixelBuffer,
111+
m_pixelBuffer.data(),
99112
datW,
100113
sizeof(float),
101114
m_width * sizeof(float),
@@ -112,11 +125,11 @@ void YFramebufferModel::load(Imf::MultiPartInputFile& file, int partId)
112125
m_displayWindow
113126
= QRect(dispW.min.x, dispW.min.y, dispW_width, dispW_height);
114127

115-
m_pixelBuffer = new float[m_width * m_height];
128+
m_pixelBuffer.resize(m_width * m_height);
116129

117130
graySlice = Imf::Slice::Make(
118131
Imf::PixelType::FLOAT,
119-
m_pixelBuffer,
132+
m_pixelBuffer.data(),
120133
datW);
121134
}
122135

0 commit comments

Comments
 (0)