Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: set max row count to avoid iterating off the end of the data buffer #22

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions pycaqtimage/pycaqtimage.sip
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,17 @@ static int rowIncMult1[8] = { 0, 0, -1, -1, 0, 0, 1, 1}; /* Scaled
static int rowIncMult2[8] = { 0, 2, 0, 0, 0, -2, 0, 0}; /* Scaled by srcwidth */
static int rowIncK[8] = { 0, 0, -1, 1, 0, 0, 1, -1}; /* Constant */

int _max_row(ImageBuffer *imageBuffer, long count)
{
if (imageBuffer->imgwidth > 0) {
return std::min(imageBuffer->imgheight, (int) std::floor(count / imageBuffer->imgwidth));
} else {
return 0;
}
}

Comment on lines +352 to +360
Copy link

@janeliu-slac janeliu-slac Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is minor but if using a modern C++ approach I think a smart pointer is considered best practice. Raw pointers should be used only when performance/memory management are critical.

If only one pointer for ImageBuffer is needed, std::unique_ptr would work.

#include <memory> 

int _max_row(unique_ptr<ImageBuffer> imageBuffer, long count)
{
    if (imageBuffer->imgwidth > 0) {
        return std::min(imageBuffer->imgheight, (int) std::floor(count / imageBuffer->imgwidth));
    } else {
        return 0;
    }
}

Regarding the buffer overflow problem--if the program uses std::vector, std::array or other dynamically sized containers similar to a python list maybe this issue can be avoided. Raw arrays is probably one of the major reasons the world moved away from C.

template <class T>
void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata)
void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata, long count)
{
T *src = cadata;
uint32_t *dst = imageBuffer->imageData;
Expand All @@ -365,10 +374,11 @@ void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata)
int col_inc = imageBuffer->srcwidth * colIncMult[orientation] +
colIncK[orientation];
int iNewAverage = imageBuffer->iNumAveraged + 1;
int row_max = _max_row(imageBuffer, count);

src += init_offset;
if (iNewAverage == 1) {
for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) {
for (int iRow = 0; iRow < row_max; ++iRow) {
for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) {
*dstF++ = *src;
*dst++ = *src;
Expand All @@ -377,7 +387,7 @@ void _pyDoAvg(ImageBuffer *imageBuffer, T *cadata)
src += row_inc;
}
} else {
for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) {
for (int iRow = 0; iRow < row_max; ++iRow) {
for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) {
*dstF += (*src - *dstF) / iNewAverage;
*dst++ = *dstF++;
Expand Down Expand Up @@ -408,14 +418,14 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void*
int col_inc = imageBuffer->srcwidth * colIncMult[orientation] +
colIncK[orientation];
int iNewAverage = imageBuffer->iNumAveraged + 1;
int row_max = _max_row(imageBuffer, count);

UNUSED(count);
UNUSED(size);

/* If we're using the color image, don't average, just copy and we're done! */
if (!imageBuffer->useGray) {
src += 3 * init_offset;
for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) {
for (int iRow = 0; iRow < row_max; ++iRow) {
for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) {
*dst++ = RGB(src);
src += 3 * col_inc;
Expand All @@ -426,7 +436,7 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void*
} else {
if (iNewAverage == 1) {
src += 3 * init_offset;
for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) {
for (int iRow = 0; iRow < row_max; ++iRow) {
for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) {
*dstF = GRAY(src);
*dst++ = *dstF++;
Expand All @@ -436,7 +446,7 @@ static void _pyColorImagePvCallback(void* cadata, long count, size_t size, void*
}
} else {
src += 3 * init_offset;
for (int iRow = 0; iRow < imageBuffer->imgheight; ++iRow) {
for (int iRow = 0; iRow < row_max; ++iRow) {
for (int iCol = 0; iCol < imageBuffer->imgwidth; ++iCol) {
*dstF += (GRAY(src) - *dstF) / iNewAverage;
*dst++ = *dstF++;
Expand All @@ -456,16 +466,15 @@ static void _pyImagePvCallback(void* cadata, long count, size_t size, void* usr)
{
ImageBuffer* imageBuffer = reinterpret_cast<ImageBuffer*>(usr);

UNUSED(count);
switch (size) {
case 4:
_pyDoAvg(imageBuffer, reinterpret_cast<uint32_t*>(cadata));
_pyDoAvg(imageBuffer, reinterpret_cast<uint32_t*>(cadata), count);
break;
case 2:
_pyDoAvg(imageBuffer, reinterpret_cast<uint16_t*>(cadata));
_pyDoAvg(imageBuffer, reinterpret_cast<uint16_t*>(cadata), count);
break;
case 1:
_pyDoAvg(imageBuffer, reinterpret_cast<uint8_t*>(cadata));
_pyDoAvg(imageBuffer, reinterpret_cast<uint8_t*>(cadata), count);
break;
default:
fprintf(stderr, "Image pixel size is %d bytes?\n", (int) size);
Expand Down