Skip to content

PHPC-1411: Accept 64-bit integers for wTimeoutMS #1042

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

Merged
merged 4 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
37 changes: 36 additions & 1 deletion phongo_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@
#define ADD_ASSOC_ZVAL(_zv, _key, _value) add_assoc_zval(_zv, _key, _value);
#define ADD_ASSOC_NULL_EX(_zv, _key) add_assoc_null_ex(_zv, ZEND_STRL(_key));
#define ADD_ASSOC_BOOL_EX(_zv, _key, _value) add_assoc_bool_ex(_zv, ZEND_STRL(_key), _value);
#define ZVAL_INT64_STRING(_zv, _value) \
do { \
char tmp[24]; \
int tmp_len; \
tmp_len = snprintf(tmp, sizeof(tmp), "%" PRId64, (_value)); \
ZVAL_STRINGL((_zv), tmp, tmp_len); \
} while (0)
#define ADD_ASSOC_INT64_AS_STRING(_zv, _key, _value) \
do { \
zval z_int; \
ZVAL_INT64_STRING(&z_int, (_value)); \
ADD_ASSOC_ZVAL_EX((_zv), (_key), &z_int); \
} while (0)
#define ADD_NEXT_INDEX_STRINGL(_zv, _value, _len) add_next_index_stringl(_zv, _value, _len);
#define phongo_free_object_arg zend_object
#define phongo_zpp_char_len size_t
Expand All @@ -107,7 +120,7 @@
0 \
} \
}
#else
#else /* PHP_VERSION_ID < 70000 */
#define phongo_char char
#define phongo_long long
#define PHONGO_LONG_FORMAT "ld"
Expand All @@ -127,6 +140,21 @@
#define ADD_ASSOC_ZVAL(_zv, _key, _value) add_assoc_zval(_zv, _key, _value);
#define ADD_ASSOC_NULL_EX(_zv, _key) add_assoc_null_ex(_zv, ZEND_STRS(_key));
#define ADD_ASSOC_BOOL_EX(_zv, _key, _value) add_assoc_bool_ex(_zv, ZEND_STRS(_key), _value);
#define ZVAL_INT64_STRING(_zv, _value) \
do { \
char tmp[24]; \
int tmp_len; \
tmp_len = snprintf(tmp, sizeof(tmp), "%" PRId64, (_value)); \
ZVAL_STRINGL((_zv), tmp, tmp_len, 1); \
} while (0)

#define ADD_ASSOC_INT64_AS_STRING(_zv, _key, _value) \
do { \
zval* z_int; \
MAKE_STD_ZVAL(z_int); \
ZVAL_INT64_STRING(z_int, (_value)); \
ADD_ASSOC_ZVAL_EX((_zv), (_key), z_int); \
} while (0)
#define ADD_NEXT_INDEX_STRINGL(_zv, _value, _len) add_next_index_stringl(_zv, _value, _len, 1);
#define Z_PHPDATE_P(object) ((php_date_obj*) zend_object_store_get_object(object TSRMLS_CC))
#define Z_ISUNDEF(x) !x
Expand Down Expand Up @@ -160,6 +188,7 @@
#define ADD_INDEX_INT64(_zv, _index, _value) add_index_long((_zv), (_index), (_value))
#define ADD_NEXT_INDEX_INT64(_zv, _value) add_next_index_long((_zv), (_value))
#define ADD_ASSOC_INT64(_zv, _key, _value) add_assoc_long((_zv), (_key), (_value))
#define ZVAL_INT64(_zv, _value) ZVAL_LONG((_zv), (_value))
#elif SIZEOF_PHONGO_LONG == 4
#if PHP_VERSION_ID >= 70000
#define ADD_INDEX_INT64(_zv, _index, _value) \
Expand Down Expand Up @@ -218,6 +247,12 @@
add_assoc_long((_zv), (_key), (_value)); \
}
#endif /* PHP_VERSION_ID */
#define ZVAL_INT64(_zv, _value) \
if ((_value) > INT32_MAX || (_value) < INT32_MIN) { \
php_phongo_bson_new_int64((_zv), (_value) TSRMLS_CC); \
} else { \
ZVAL_LONG((_zv), (_value)); \
}
#else /* SIZEOF_PHONGO_LONG != 8 && SIZEOF_PHONGO_LONG != 4 */
#error Unsupported architecture (integers are neither 32-bit nor 64-bit)
#endif /* SIZEOF_PHONGO_LONG */
Expand Down
37 changes: 29 additions & 8 deletions php_phongo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1365,10 +1365,15 @@ void php_phongo_write_concern_to_zval(zval* retval, const mongoc_write_concern_t
}

if (wtimeout != 0) {
/* Note: PHP currently enforces that wimeoutMS is a 32-bit integer, so
* casting will never truncate the value. This may change with
* PHPC-1411. */
ADD_ASSOC_LONG_EX(retval, "wtimeout", (int32_t) wtimeout);
#if SIZEOF_LONG == 4
if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) {
ADD_ASSOC_INT64_AS_STRING(&retval, "wtimeout", wtimeout);
} else {
ADD_ASSOC_LONG_EX(retval, "wtimeout", wtimeout);
}
#else
ADD_ASSOC_LONG_EX(retval, "wtimeout", wtimeout);
#endif
}
} /* }}} */
/* }}} */
Expand Down Expand Up @@ -1966,10 +1971,8 @@ static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t* uri, bson_t* option
if (!strcasecmp(key, MONGOC_URI_WTIMEOUTMS)) {
int64_t wtimeout;

/* Although the write concern spec defines wtimeoutMS as 64-bit, PHP has
* historically required 32-bit. This may change with PHPC-1411. */
if (!BSON_ITER_HOLDS_INT32(&iter)) {
PHONGO_URI_INVALID_TYPE(iter, "32-bit integer");
if (!BSON_ITER_HOLDS_INT(&iter)) {
PHONGO_URI_INVALID_TYPE(iter, "integer");
mongoc_write_concern_destroy(new_wc);

return false;
Expand Down Expand Up @@ -2746,6 +2749,24 @@ void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string,
#endif
} /* }}} */

bool php_phongo_parse_int64(int64_t* retval, const char* data, phongo_zpp_char_len data_len) /* {{{ */
{
int64_t value;
char* endptr = NULL;

/* bson_ascii_strtoll() sets errno if conversion fails. If conversion
* succeeds, we still want to ensure that the entire string was parsed. */
value = bson_ascii_strtoll(data, &endptr, 10);

if (errno || (endptr && endptr != ((const char*) data + data_len))) {
return false;
}

*retval = value;

return true;
} /* }}} */

/* {{{ Memory allocation wrappers */
static void* php_phongo_malloc(size_t num_bytes) /* {{{ */
{
Expand Down
2 changes: 2 additions & 0 deletions php_phongo.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ void php_phongo_cursor_to_zval(zval* retval, const mongoc_cursor_t* cursor);
void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string, zval* options, zval* driverOptions TSRMLS_DC);
int php_phongo_set_monitoring_callbacks(mongoc_client_t* client);

bool php_phongo_parse_int64(int64_t* retval, const char* data, phongo_zpp_char_len data_len);

zend_bool phongo_writeerror_init(zval* return_value, bson_t* bson TSRMLS_DC);
zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson TSRMLS_DC);

Expand Down
35 changes: 7 additions & 28 deletions src/BSON/Int64.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,8 @@ static bool php_phongo_int64_init(php_phongo_int64_t* intern, int64_t integer) /
static bool php_phongo_int64_init_from_string(php_phongo_int64_t* intern, const char* s_integer, phongo_zpp_char_len s_integer_len TSRMLS_DC) /* {{{ */
{
int64_t integer;
char* endptr = NULL;

/* bson_ascii_strtoll() sets errno if conversion fails. If conversion
* succeeds, we still want to ensure that the entire string was parsed. */
integer = bson_ascii_strtoll(s_integer, &endptr, 10);

if (errno || (endptr && endptr != ((const char*) s_integer + s_integer_len))) {
if (!php_phongo_parse_int64(&integer, s_integer, s_integer_len)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error parsing \"%s\" as 64-bit integer for %s initialization", s_integer, ZSTR_VAL(php_phongo_int64_ce->name));
return false;
}
Expand Down Expand Up @@ -88,39 +83,31 @@ static bool php_phongo_int64_init_from_hash(php_phongo_int64_t* intern, HashTabl
static PHP_METHOD(Int64, __toString)
{
php_phongo_int64_t* intern;
char s_integer[24];
int s_integer_len;

if (zend_parse_parameters_none() == FAILURE) {
return;
}

intern = Z_INT64_OBJ_P(getThis());

s_integer_len = snprintf(s_integer, sizeof(s_integer), "%" PRId64, intern->integer);

PHONGO_RETVAL_STRINGL(s_integer, s_integer_len);
ZVAL_INT64_STRING(return_value, intern->integer);
} /* }}} */

/* {{{ proto array MongoDB\BSON\Int64::jsonSerialize()
*/
static PHP_METHOD(Int64, jsonSerialize)
{
php_phongo_int64_t* intern;
char s_integer[24];
int s_integer_len;

if (zend_parse_parameters_none() == FAILURE) {
return;
}

intern = Z_INT64_OBJ_P(getThis());

s_integer_len = snprintf(s_integer, sizeof(s_integer), "%" PRId64, intern->integer);

array_init_size(return_value, 1);

ADD_ASSOC_STRINGL(return_value, "$numberLong", s_integer, s_integer_len);
ADD_ASSOC_INT64_AS_STRING(return_value, "$numberLong", intern->integer);
} /* }}} */

/* {{{ proto string MongoDB\BSON\Int64::serialize()
Expand All @@ -131,24 +118,20 @@ static PHP_METHOD(Int64, serialize)
ZVAL_RETVAL_TYPE retval;
php_serialize_data_t var_hash;
smart_str buf = { 0 };
char s_integer[24];
int s_integer_len;

if (zend_parse_parameters_none() == FAILURE) {
return;
}

intern = Z_INT64_OBJ_P(getThis());

s_integer_len = snprintf(s_integer, sizeof(s_integer), "%" PRId64, intern->integer);

#if PHP_VERSION_ID >= 70000
array_init_size(&retval, 1);
ADD_ASSOC_STRINGL(&retval, "integer", s_integer, s_integer_len);
ADD_ASSOC_INT64_AS_STRING(&retval, "integer", intern->integer);
#else
ALLOC_INIT_ZVAL(retval);
array_init_size(retval, 1);
ADD_ASSOC_STRINGL(retval, "integer", s_integer, s_integer_len);
ADD_ASSOC_INT64_AS_STRING(retval, "integer", intern->integer);
#endif

PHP_VAR_SERIALIZE_INIT(var_hash);
Expand Down Expand Up @@ -323,8 +306,6 @@ HashTable* php_phongo_int64_get_properties_hash(zval* object, bool is_debug TSRM
{
php_phongo_int64_t* intern;
HashTable* props;
char s_integer[24];
int s_integer_len;

intern = Z_INT64_OBJ_P(object);

Expand All @@ -334,21 +315,19 @@ HashTable* php_phongo_int64_get_properties_hash(zval* object, bool is_debug TSRM
return props;
}

s_integer_len = snprintf(s_integer, sizeof(s_integer), "%" PRId64, intern->integer);

#if PHP_VERSION_ID >= 70000
{
zval value;

ZVAL_STRINGL(&value, s_integer, s_integer_len);
ZVAL_INT64_STRING(&value, intern->integer);
zend_hash_str_update(props, "integer", sizeof("integer") - 1, &value);
}
#else
{
zval* value;

MAKE_STD_ZVAL(value);
ZVAL_STRINGL(value, s_integer, s_integer_len, 1);
ZVAL_INT64_STRING(value, intern->integer);
zend_hash_update(props, "integer", sizeof("integer"), &value, sizeof(value), NULL);
}
#endif
Expand Down
12 changes: 2 additions & 10 deletions src/BSON/Timestamp.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,13 @@ static bool php_phongo_timestamp_init(php_phongo_timestamp_t* intern, int64_t in
static bool php_phongo_timestamp_init_from_string(php_phongo_timestamp_t* intern, const char* s_increment, phongo_zpp_char_len s_increment_len, const char* s_timestamp, phongo_zpp_char_len s_timestamp_len TSRMLS_DC) /* {{{ */
{
int64_t increment, timestamp;
char* endptr = NULL;

/* bson_ascii_strtoll() sets errno if conversion fails. If conversion
* succeeds, we still want to ensure that the entire string was parsed. */

increment = bson_ascii_strtoll(s_increment, &endptr, 10);

if (errno || (endptr && endptr != ((const char*) s_increment + s_increment_len))) {
if (!php_phongo_parse_int64(&increment, s_increment, s_increment_len)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error parsing \"%s\" as 64-bit integer increment for %s initialization", s_increment, ZSTR_VAL(php_phongo_timestamp_ce->name));
return false;
}

timestamp = bson_ascii_strtoll(s_timestamp, &endptr, 10);

if (errno || (endptr && endptr != ((const char*) s_timestamp + s_timestamp_len))) {
if (!php_phongo_parse_int64(&timestamp, s_timestamp, s_timestamp_len)) {
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error parsing \"%s\" as 64-bit integer timestamp for %s initialization", s_timestamp, ZSTR_VAL(php_phongo_timestamp_ce->name));
return false;
}
Expand Down
Loading