Skip to content

Commit f4ecbb9

Browse files
committed
f3
1 parent 5609fcf commit f4ecbb9

File tree

2 files changed

+78
-25
lines changed

2 files changed

+78
-25
lines changed

src/CanvasRenderingContext2d.cc

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,11 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
840840

841841
int dstStride = canvas()->stride();
842842
int Bpp = dstStride / canvas()->getWidth();
843+
844+
if (imageData->width() > (uint32_t)INT32_MAX / Bpp) {
845+
Napi::Error::New(env, "ImageData width too large").ThrowAsJavaScriptException();
846+
return;
847+
}
843848
int srcStride = Bpp * imageData->width();
844849

845850
int sx = 0
@@ -851,11 +856,20 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
851856
, rows
852857
, cols;
853858

859+
if (imageData->height() > INT32_MAX) {
860+
Napi::Error::New(env, "ImageData height too large").ThrowAsJavaScriptException();
861+
return;
862+
}
863+
864+
int iw = imageData->width();
865+
int ih = imageData->height();
866+
867+
// https://searchfox.org/firefox-main/rev/0900c19de62c07b977fe103b3816616b75d63b0a/dom/canvas/CanvasRenderingContext2D.cpp#6736
854868
switch (info.Length()) {
855869
// imageData, dx, dy
856870
case 3:
857-
sw = imageData->width();
858-
sh = imageData->height();
871+
sw = iw;
872+
sh = ih;
859873
break;
860874
// imageData, dx, dy, sx, sy, sw, sh
861875
case 7:
@@ -864,23 +878,62 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
864878
sw = info[5].ToNumber().UnwrapOr(zero).Int32Value();
865879
sh = info[6].ToNumber().UnwrapOr(zero).Int32Value();
866880
// fix up negative height, width
867-
if (sw < 0) sx += sw, sw = -sw;
868-
if (sh < 0) sy += sh, sh = -sh;
869-
// clamp the left edge
870-
if (sx < 0) sw += sx, sx = 0;
871-
if (sy < 0) sh += sy, sy = 0;
872-
// clamp the right edge
873-
if (sx + sw > imageData->width()) sw = imageData->width() - sx;
874-
if (sy + sh > imageData->height()) sh = imageData->height() - sy;
875-
// start destination at source offset
876-
dx += sx;
877-
dy += sy;
881+
if (sw < 0) {
882+
if (sw == INT32_MIN) {
883+
Napi::Error::New(env, "dirty width invalid").ThrowAsJavaScriptException();
884+
return;
885+
}
886+
int64_t result = (int64_t)sx + sw;
887+
if (result < INT_MIN) {
888+
Napi::Error::New(env, "dirty width invalid").ThrowAsJavaScriptException();
889+
return;
890+
} else {
891+
sx = result;
892+
}
893+
sw = -sw;
894+
}
895+
896+
if (sh < 0) {
897+
if (sh == INT32_MIN) {
898+
Napi::Error::New(env, "dirty height invalid").ThrowAsJavaScriptException();
899+
return;
900+
}
901+
int64_t result = (int64_t)sy + sh;
902+
if (result < INT_MIN) {
903+
Napi::Error::New(env, "dirty height invalid").ThrowAsJavaScriptException();
904+
return;
905+
} else {
906+
sy = result;
907+
}
908+
sh = -sh;
909+
}
910+
// fix up negative x, y
911+
if (sx < 0) sw = std::max(0, sx + sw), sx = 0;
912+
if (sy < 0) sh = std::max(0, sy + sh), sy = 0;
913+
// clamp the right, bottom edges (sx + sw > iw reorganized for overflow)
914+
if (sx > iw - sw) sw = std::max(0, iw - sx);
915+
if (sy > ih - sh) sh = std::max(0, ih - sy);
878916
break;
879917
default:
880918
Napi::Error::New(env, "invalid arguments").ThrowAsJavaScriptException();
881919
return;
882920
}
883921

922+
// start destination at source offset
923+
// eliminiating INT_MIN makes it safe to subtract dx, dy from sx, sy below
924+
if (int64_t result = (int64_t)dx + sx; dx > INT_MIN && result <= INT_MAX) {
925+
dx = result; // dx += sx
926+
} else {
927+
Napi::Error::New(env, "destination x invalid").ThrowAsJavaScriptException();
928+
return;
929+
}
930+
if (int64_t result = (int64_t)dy + sy; dy > INT_MIN && result <= INT_MAX) {
931+
dy = result; // dy += sy
932+
} else {
933+
Napi::Error::New(env, "destination y invalid").ThrowAsJavaScriptException();
934+
return;
935+
}
936+
884937
// chop off outlying source data
885938
if (dx < 0) sw += dx, sx -= dx, dx = 0;
886939
if (dy < 0) sh += dy, sy -= dy, dy = 0;
@@ -894,8 +947,8 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
894947

895948
switch (canvas()->getFormat()) {
896949
case CAIRO_FORMAT_ARGB32: {
897-
src += sy * srcStride + sx * 4;
898-
dst += dstStride * dy + 4 * dx;
950+
src += (ptrdiff_t)sy * srcStride + sx * 4;
951+
dst += (ptrdiff_t)dstStride * dy + 4 * dx;
899952
for (int y = 0; y < rows; ++y) {
900953
uint8_t *dstRow = dst;
901954
uint8_t *srcRow = src;
@@ -933,8 +986,8 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
933986
break;
934987
}
935988
case CAIRO_FORMAT_RGB24: {
936-
src += sy * srcStride + sx * 4;
937-
dst += dstStride * dy + 4 * dx;
989+
src += (ptrdiff_t)sy * srcStride + sx * 4;
990+
dst += (ptrdiff_t)dstStride * dy + 4 * dx;
938991
for (int y = 0; y < rows; ++y) {
939992
uint8_t *dstRow = dst;
940993
uint8_t *srcRow = src;
@@ -957,8 +1010,8 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
9571010
break;
9581011
}
9591012
case CAIRO_FORMAT_A8: {
960-
src += sy * srcStride + sx;
961-
dst += dstStride * dy + dx;
1013+
src += (ptrdiff_t)sy * srcStride + sx;
1014+
dst += (ptrdiff_t)dstStride * dy + dx;
9621015
if (srcStride == dstStride && cols == dstStride) {
9631016
// fast path: strides are the same and doing a full-width put
9641017
memcpy(dst, src, cols * rows);
@@ -978,8 +1031,8 @@ Context2d::PutImageData(const Napi::CallbackInfo& info) {
9781031
break;
9791032
}
9801033
case CAIRO_FORMAT_RGB16_565: {
981-
src += sy * srcStride + sx * 2;
982-
dst += dstStride * dy + 2 * dx;
1034+
src += (ptrdiff_t)sy * srcStride + sx * 2;
1035+
dst += (ptrdiff_t)dstStride * dy + 2 * dx;
9831036
for (int y = 0; y < rows; ++y) {
9841037
memcpy(dst, src, cols * 2);
9851038
dst += dstStride;

src/ImageData.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ class ImageData : public Napi::ObjectWrap<ImageData> {
1212
Napi::Value GetWidth(const Napi::CallbackInfo& info);
1313
Napi::Value GetHeight(const Napi::CallbackInfo& info);
1414

15-
inline int width() { return _width; }
16-
inline int height() { return _height; }
15+
inline uint32_t width() { return _width; }
16+
inline uint32_t height() { return _height; }
1717
inline uint8_t *data() { return _data; }
1818

1919
Napi::Env env;
2020

2121
private:
22-
int _width;
23-
int _height;
22+
uint32_t _width;
23+
uint32_t _height;
2424
uint8_t *_data;
2525

2626
};

0 commit comments

Comments
 (0)