-
Notifications
You must be signed in to change notification settings - Fork 7.9k
ext/sockets: socket_set_option switch from convert_to_long to zval_tr… #17135
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
Conversation
…y_get_long. to be explicit when the expected type is not met.
ext/sockets/sockets.c
Outdated
@@ -1811,6 +1811,7 @@ PHP_FUNCTION(socket_set_option) | |||
HashTable *opt_ht; | |||
zval *l_onoff, *l_linger; | |||
zval *sec, *usec; | |||
bool failed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bleh the indent doesn't match here. I would say to not bother, or remove the param name alignment.
ext/sockets/sockets.c
Outdated
lv.l_onoff = (unsigned short)zl_onoff; | ||
lv.l_linger = (unsigned short)zl_linger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably the zend_long should be checked to see if it fits in an unsigned short before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already happens in the lines above.
ext/sockets/sockets.c
Outdated
@@ -1898,6 +1907,7 @@ PHP_FUNCTION(socket_set_option) | |||
case SO_SNDTIMEO: { | |||
const char sec_key[] = "sec"; | |||
const char usec_key[] = "usec"; | |||
bool failed; | |||
|
|||
convert_to_array(arg4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could also be updated to check that the value is an array, as if it is not the zend_hash_str_find
calls below will fail. Similarly for the other function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This convert_to_array()
appears to be superfluous.
ext/sockets/sockets.c
Outdated
convert_to_long(arg4); | ||
zend_long fval = zval_try_get_long(arg4, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "must be an int, %s given", zend_zval_value_name(arg4)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zend_argument_type_error(4, "must be an int, %s given", zend_zval_value_name(arg4)); | |
zend_argument_type_error(4, "must be of type int, %s given", zend_zval_value_name(arg4)); |
ext/sockets/sockets.c
Outdated
ov = Z_LVAL_P(arg4); | ||
ov = zval_try_get_long(arg4, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "must be an int, %s given", zend_zval_value_name(arg4)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
ext/sockets/sockets.c
Outdated
convert_to_long(usec); | ||
zend_long zsec = zval_try_get_long(sec, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "\"%s\" must be an int, %s given", sec_key, zend_zval_value_name(sec)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording
ext/sockets/sockets.c
Outdated
} | ||
zend_long zusec = zval_try_get_long(usec, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "\"%s\" must be an int, %s given", usec_key, zend_zval_value_name(usec)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
ext/sockets/sockets.c
Outdated
} | ||
zend_long zl_linger = zval_try_get_long(l_linger, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "\"%s\" must be an int, %s given", l_linger_key, zend_zval_value_name(l_linger)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording
ext/sockets/sockets.c
Outdated
convert_to_long(l_linger); | ||
zend_long zl_onoff = zval_try_get_long(l_onoff, &failed); | ||
if (failed) { | ||
zend_argument_type_error(4, "\"%s\" must be an int, %s given", l_onoff_key, zend_zval_value_name(l_onoff)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording
8d4b825
to
6c5f436
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for taking a stab at this!
ext/sockets/sockets.c
Outdated
zend_argument_type_error(4, "must be of type array, %s given", zend_zval_value_name(arg4)); | ||
RETURN_THROWS(); | ||
} | ||
|
||
convert_to_array(arg4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be superfluous, since we just checked that it is an array (and otherwise bailed out).
ext/sockets/sockets.c
Outdated
@@ -1883,11 +1889,29 @@ PHP_FUNCTION(socket_set_option) | |||
RETURN_THROWS(); | |||
} | |||
|
|||
convert_to_long(l_onoff); | |||
convert_to_long(l_linger); | |||
zend_long zl_onoff = zval_try_get_long(l_onoff, &failed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might also use zval_get_long()
for better BC, but I don't have a strong opinion on this.
ext/sockets/sockets.c
Outdated
lv.l_onoff = (unsigned short)zl_onoff; | ||
lv.l_linger = (unsigned short)zl_linger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already happens in the lines above.
ext/sockets/sockets.c
Outdated
@@ -1898,6 +1907,7 @@ PHP_FUNCTION(socket_set_option) | |||
case SO_SNDTIMEO: { | |||
const char sec_key[] = "sec"; | |||
const char usec_key[] = "usec"; | |||
bool failed; | |||
|
|||
convert_to_array(arg4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This convert_to_array()
appears to be superfluous.
ext/sockets/sockets.c
Outdated
optlen = sizeof(tv); | ||
opt_ptr = &tv; | ||
#else | ||
timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000; | ||
timeout = zsec * 1000 + zusec / 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've missed that in the other PR: timeout
is DWORD
(that is 32bit unsigned), so the assignment might cause wrap-around. I think we should catch that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've missed that in the other PR:
timeout
isDWORD
(that is 32bit unsigned), so the assignment might cause wrap-around. I think we should catch that.
DWORD on master tough here still int but issue can definitively occur very much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I've mixed that up! If this targets PHP-8.3, we cannot change convert_to_long()
to use zval_try_get_long()
(too much BC break). Should better use zval_get_long()
instead.
ext/sockets/sockets.c
Outdated
@@ -1911,15 +1940,23 @@ PHP_FUNCTION(socket_set_option) | |||
RETURN_THROWS(); | |||
} | |||
|
|||
convert_to_long(sec); | |||
convert_to_long(usec); | |||
zend_long zsec = zval_try_get_long(sec, &failed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming is confusing here. zsec
would appear to be a zval
, and sec
its corresponding long
, but it's the other way round.
5c7768b
to
1e1b1be
Compare
1e1b1be
to
1a14443
Compare
ext/sockets/sockets.c
Outdated
if (valsec < 0 || valsec > INT_MAX / 1000) { | ||
zend_argument_value_error(4, "\"%s\" must be between 0 and %d", sec_key, INT_MAX / 1000); | ||
RETURN_THROWS(); | ||
} | ||
|
||
timeout = valsec * 1000; | ||
|
||
if (valusec < 0 || timeout > INT_MAX - (valusec / 1000)) { | ||
zend_argument_value_error(4, "\"%s\" must be between 0 and %u", usec_key, (DWORD)(INT_MAX - (valusec / 1000))); | ||
RETURN_THROWS(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this works for very large usec
. We may also need to take BC into account (currently, negative usec
are likely allowed for Windows). Maybe leave the overflow checking for master; while technically UB can happen, I think wrap-around is happening in practice (and nothing really bad).
ext/sockets/sockets.c
Outdated
@@ -1971,15 +1990,15 @@ PHP_FUNCTION(socket_set_option) | |||
|
|||
#ifdef SO_ATTACH_REUSEPORT_CBPF | |||
case SO_ATTACH_REUSEPORT_CBPF: { | |||
convert_to_long(arg4); | |||
zend_long fval = zval_get_long(arg4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fval
? what does the f
stand for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f for function (for CBPF) val.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer cbpf_val
then, as when I see fval
I'm thinking "float val".
ext/sockets/sockets.c
Outdated
zend_long vall_lonoff = zval_get_long(l_onoff); | ||
zend_long vall_linger = zval_get_long(l_linger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why it is vall
?
zend_long vall_lonoff = zval_get_long(l_onoff); | |
zend_long vall_linger = zval_get_long(l_linger); | |
zend_long val_lonoff = zval_get_long(l_onoff); | |
zend_long val_linger = zval_get_long(l_linger); |
--EXPECTF-- | ||
socket_set_option(): Argument #4 ($value) must be of type array, stdClass given | ||
|
||
Warning: Object of class stdClass could not be converted to int in %s on line %d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only "detail" I'm not sure about regarding BC: is it okay to drop support for stdClass
, ArrayObject
and purpose built "data classes" (and maybe even objects in general)?
Maybe wait what @Girgias (or others) have to say about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are talking about the warning, I don't see how this is a BC breaks.
All the cases you mention already trigger this warning.
If you are talking about not supporting casting random objects to arrays, that is a recurring "problem" with PHP objects being structs, reference pointers, and everything in between. I don't think it is a problem is properly documented in UPGRADING for master, as most functions do not allow objects in those cases. Nor does ZPP unless one uses the special Z_PARAM_ARRAY_OR_OBJECT(_*)
specifier (or A
/H
for non-fast ZPP).
Moreover, this causes issues when the value in question possibly needs to be interpreted like a string
.
However, as this is a bugfix, I would do if (zval != IS_ARRAY) { /* slow path */ if (zval != IS_OBJECT) { /* throw */ } else { /* get HT from props */ } }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring to the BC if we apply to stable branches (it's okay to be more strict for master).
ext/sockets/sockets.c
Outdated
@@ -1971,15 +1990,15 @@ PHP_FUNCTION(socket_set_option) | |||
|
|||
#ifdef SO_ATTACH_REUSEPORT_CBPF | |||
case SO_ATTACH_REUSEPORT_CBPF: { | |||
convert_to_long(arg4); | |||
zend_long fval = zval_get_long(arg4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer cbpf_val
then, as when I see fval
I'm thinking "float val".
--EXPECTF-- | ||
socket_set_option(): Argument #4 ($value) must be of type array, stdClass given | ||
|
||
Warning: Object of class stdClass could not be converted to int in %s on line %d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are talking about the warning, I don't see how this is a BC breaks.
All the cases you mention already trigger this warning.
If you are talking about not supporting casting random objects to arrays, that is a recurring "problem" with PHP objects being structs, reference pointers, and everything in between. I don't think it is a problem is properly documented in UPGRADING for master, as most functions do not allow objects in those cases. Nor does ZPP unless one uses the special Z_PARAM_ARRAY_OR_OBJECT(_*)
specifier (or A
/H
for non-fast ZPP).
Moreover, this causes issues when the value in question possibly needs to be interpreted like a string
.
However, as this is a bugfix, I would do if (zval != IS_ARRAY) { /* slow path */ if (zval != IS_OBJECT) { /* throw */ } else { /* get HT from props */ } }
ext/sockets/sockets.c
Outdated
@@ -1871,7 +1871,11 @@ PHP_FUNCTION(socket_set_option) | |||
const char l_onoff_key[] = "l_onoff"; | |||
const char l_linger_key[] = "l_linger"; | |||
|
|||
convert_to_array(arg4); | |||
if (Z_TYPE_P(arg4) != IS_ARRAY) { | |||
zend_argument_type_error(4, "must be of type array, %s given", zend_zval_value_name(arg4)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think adding what option we are talking about would help the error message.
zend_argument_type_error(4, "must be of type array, %s given", zend_zval_value_name(arg4)); | |
zend_argument_type_error(4, "must be of type array when argument #3 ($option) is SO_LINGER, %s given", zend_zval_value_name(arg4)); |
And ditto for the other error cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks good now, @CMB?
If Note that I'm @cmb69, though. :) |
…t_long. to be explicit when the expected type is not met. Check SO_LINGER values for possible overflow. close phpGH-17135
…y_get_long.
to be explicit when the expected type is not met.