Skip to content

Resolve MSVC C4244 level 2 warnings #17076

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

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft

Resolve MSVC C4244 level 2 warnings #17076

wants to merge 5 commits into from

Conversation

cmb69
Copy link
Member

@cmb69 cmb69 commented Dec 7, 2024

Level 2 C4244 warnings hint at possible loss of data. So far this PR silences them by explicitly casting, what actually may be appropriate in some cases (possibly for FFI); in some other cases the warnings might be bogus, in which case we may want to add suitable assertions. There may be some cases, though, which hint at edge case bugs (in which case these should better be fixed).

It would be great if we can properly solve this. Maybe some of the code owners can have a look?

Note that the change to the CFLAGS for CI is not supposed to be committed; it's just to see whether I've missed some of these warnings when testing locally.

PS: any changes to the bundled libgd should be coordinated with upstream.

@@ -473,7 +473,7 @@ PHPAPI zend_long php_mt_rand_common(zend_long min, zend_long max)
/* This is an inlined version of the RAND_RANGE_BADSCALING macro that does not invoke UB when encountering
* (max - min) > ZEND_LONG_MAX.
*/
zend_ulong offset = (double) ( (double) max - min + 1.0) * (r / (PHP_MT_RAND_MAX + 1.0));
zend_ulong offset = (zend_ulong) (((double) max - min + 1.0) * (r / (PHP_MT_RAND_MAX + 1.0)));
Copy link
Member Author

Choose a reason for hiding this comment

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

The old version appears to "over-cast", so I simplified. @TimWolla, @zeriyoshi, thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

looks good!

@@ -1028,7 +1028,7 @@ static zval *to_zval_double(zval *ret, encodeTypePtr type, xmlNodePtr data)
whiteSpace_collapse(data->children->content);
switch (is_numeric_string((char*)data->children->content, strlen((char*)data->children->content), &lval, &dval, 0)) {
case IS_LONG:
ZVAL_DOUBLE(ret, lval);
ZVAL_DOUBLE(ret, (double) lval);
Copy link
Member Author

Choose a reason for hiding this comment

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

Is this cast fine, @nielsdos?

Copy link
Member

Choose a reason for hiding this comment

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

Yes

@alexdowad
Copy link
Contributor

alexdowad commented Dec 7, 2024 via email

@@ -156,7 +156,7 @@ void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
if (quality >= gdWebpLossless) {
out_size = WebPEncodeLosslessRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, &out);
} else {
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, (float) quality, &out);
Copy link
Member Author

Choose a reason for hiding this comment

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

The simple cast is fine here to suppress the warning. ext/gd catches values < -1 early, and for libgd, such values cause WebPEncodeRGBA() to fail.

@@ -2137,8 +2137,7 @@ gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, in
/* round to two decimals and keep the 100x multiplication to use it in the common square angles
case later. Keep the two decimal precisions so smaller rotation steps can be done, useful for
slow animations. */
const int angle_rounded = fmod((int) floorf(angle * 100), 360 * 100);

const int angle_rounded = (int) fmod((int) floorf(angle * 100), 360 * 100);
Copy link
Member Author

Choose a reason for hiding this comment

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

This looks seriously overengineered. Why are there even float operations, instead of

Suggested change
const int angle_rounded = (int) fmod((int) floorf(angle * 100), 360 * 100);
const int angle_rounded = ((int) (angle * 100)) % (360 * 100);

@@ -1134,7 +1134,7 @@ void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
TBB: but watch out for /0! */
double ac = cos (atan2 (dy, dx));
if (ac != 0) {
wid = thick / ac;
wid = (int) (thick / ac);
Copy link
Member Author

Choose a reason for hiding this comment

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

It seems to me that rounding would make sense here, but likely introduces a subtle BC break; as such casting to int is okay.

@@ -2827,7 +2827,7 @@ void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
* same footprint.
*/
if (y >= y1 && y < y2) {
im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1);
Copy link
Member Author

Choose a reason for hiding this comment

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

This one is okay.

@@ -81,7 +81,7 @@ static int quality2Quantizer(int quality) {

float scaleFactor = (float) AVIF_QUANTIZER_WORST_QUALITY / (float) MAX_QUALITY;

return round(scaleFactor * (MAX_QUALITY - clampedQuality));
return (int) round(scaleFactor * (MAX_QUALITY - clampedQuality));
Copy link
Member Author

Choose a reason for hiding this comment

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

I think the float calculation is unnecessary here. The following should be good enough:

Suggested change
return (int) round(scaleFactor * (MAX_QUALITY - clampedQuality));
return clampedQuality * AVIF_QUANTIZER_WORST_QUALITY / MAX_QUALITY;

But changing this now would introduce a subtle BC break, so just casting to int appears to be sensible for now.

@@ -103,7 +103,7 @@ static avifBool setEncoderTilesAndThreads(avifEncoder *encoder, avifRGBImage *rg

// The number of tiles in any dimension will always be a power of 2. We can only specify log(2)tiles.

tilesLog2 = floor(log2(tiles));
tilesLog2 = (int) floor(log2(tiles));
Copy link
Member Author

Choose a reason for hiding this comment

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

Why do we even floor() here instead of casting to int right away:

Suggested change
tilesLog2 = (int) floor(log2(tiles));
tilesLog2 = (int) log2(tiles);

And given we're interested in the log2 of an integer, there are even options not requiring an FP instruction (especially since tiles <= 8). But okay.

Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

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

FFI changes look good to me.

cmb69 added a commit that referenced this pull request Dec 10, 2024
These got already approval by the respective code owners in GH-17076.
* master:
  Resolve some MSVC C4244 level 2 warnings
cmb69 added a commit to cmb69/php-src that referenced this pull request Jan 26, 2025
C4146[1] is about unary minus applied to unsigned operands; that
behavior is well defined, and apparently used deliberately in the code
base.

C4244[2] is about possible loss of data when converting to another
arithmetic type.  This is addressed by another PR[3].

Anyhow, it seems like a no brainer to elevate to `/W2` even if we have
to exempt two categories of warnings, since we can catch some others.

[1] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4146?view=msvc-170>
[2] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4244>
[3] <php#17076>
cmb69 added a commit that referenced this pull request Feb 1, 2025
C4146[1] is about unary minus applied to unsigned operands; that
behavior is well defined, and apparently used deliberately in the code
base.

C4244[2] is about possible loss of data when converting to another
arithmetic type.  This is addressed by another PR[3].

Anyhow, it seems like a no brainer to elevate to `/W2` even if we have
to exempt two categories of warnings, since we can catch some others.

[1] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4146?view=msvc-170>
[2] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4244>
[3] <#17076>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants