MXS-1703 Better strtoll() & strtoull() error detection

The functions do not set errno on all invalid input, so it's best to check
endptr.

Also, strtoll is now used for server id scanning through QueryResult.
This commit is contained in:
Esa Korhonen 2018-04-11 17:58:43 +03:00
parent ca9682f042
commit 7f36339f53
4 changed files with 12 additions and 32 deletions

View File

@ -155,8 +155,9 @@ Gtid Gtid::from_string(const char* str, char** endptr)
{
errno = 0;
parsed_numbers[i] = strtoull(ptr, &strtoull_endptr, 10);
// No parse error
if (errno != 0)
// Check for parse error. Even this is not quite enough because strtoull will silently convert
// negative values. Yet, strtoull is required for the third value.
if (errno != 0 || strtoull_endptr == ptr)
{
error = true;
}

View File

@ -179,7 +179,11 @@ bool MariaDBServer::do_show_slave_status()
server_version != MYSQL_SERVER_VERSION_51)
{
/* Get Master_Server_Id */
master_server_id = scan_server_id(result->get_string(i_master_server_id).c_str());
auto parsed = result->get_uint(i_master_server_id);
if (parsed >= 0)
{
master_server_id = parsed;
}
}
if (server_version == MYSQL_SERVER_VERSION_100)

View File

@ -13,8 +13,6 @@
#include "utilities.hh"
#include <inttypes.h>
#include <limits>
#include <string>
#include <maxscale/debug.h>
@ -23,22 +21,6 @@ using std::string;
/** Server id default value */
const int64_t SERVER_ID_UNKNOWN = -1;
int64_t scan_server_id(const char* id_string)
{
int64_t server_id = SERVER_ID_UNKNOWN;
ss_debug(int rv = ) sscanf(id_string, "%" PRId64, &server_id);
ss_dassert(rv == 1);
// Server id can be 0, which was even the default value until 10.2.1.
// KB is a bit hazy on this, but apparently when replicating, the server id should not be 0. Not sure,
// so MaxScale allows this.
#if defined(SS_DEBUG)
const int64_t SERVER_ID_MIN = std::numeric_limits<uint32_t>::min();
const int64_t SERVER_ID_MAX = std::numeric_limits<uint32_t>::max();
#endif
ss_dassert(server_id >= SERVER_ID_MIN && server_id <= SERVER_ID_MAX);
return server_id;
}
QueryResult::QueryResult(MYSQL_RES* resultset)
: m_resultset(resultset)
, m_columns(-1)
@ -107,11 +89,12 @@ int64_t QueryResult::get_uint(int64_t column_ind) const
ss_dassert(column_ind < m_columns);
char* data = m_rowdata[column_ind];
int64_t rval = -1;
if (data)
if (data && *data)
{
errno = 0; // strtoll sets this
auto parsed = strtoll(data, NULL, 10);
if (parsed >= 0 && errno == 0)
char* endptr = NULL;
auto parsed = strtoll(data, &endptr, 10);
if (parsed >= 0 && errno == 0 && *endptr == '\0')
{
rval = parsed;
}

View File

@ -31,14 +31,6 @@
extern const int64_t SERVER_ID_UNKNOWN;
/**
* Scan a server id from a string.
*
* @param id_string
* @return Server id, or -1 if scanning fails
*/
int64_t scan_server_id(const char* id_string);
/**
* Helper class for simplifying working with resultsets. Used in MariaDBServer.
*/