From ddcad361d6ff2c3336221f27c4e31bfc8d1913b1 Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Fri, 4 Sep 2015 11:10:57 +0530 Subject: Bug #21503595 : --QUERY-ALLOC-BLOCK-SIZE=-1125899906842624 + PID_FILE CHECK LEADS TO OOM SIG 11 Description:- A server started with 'query_alloc_block_size' option set to a certain range of negative values on a machine without enough memory may lead to OOM. Analysis:- Server uses 'strtoull()' to convert server variable values of type 'GET_UINT', 'GET_ULONG' or 'GET_ULL' from string to unsigned long long. According to the man page, 'strtoull()' function returns either the result of the conversion or, if there was a leading minus sign, the negation of the result of the conversion represented as an unsigned value, unless the original(nonnegated) value would overflow; in the latter case, strtoull() returns ULLONG_MAX and sets errno to ERANGE. So 'strtoull()' converts a small negative value to a larger postive value. For example string '-1125899906842624' will be converted to an unsigned value, '18445618173802708992' (ulonglong typecast of '-1125899906842624'). So a server started with 'query_alloc_block_size' set to "-1125899906842624" on a machine without enough memory will lead to OOM since server allocates '18445618173802708992' bytes(17178820608 GB) for query allocation block. Fix:- When server is started with any server variable, of type "GET_UINT", "GET_ULONG" or "GET_ULL", set to a negative value, a warning, "option xxx: value -yyy adjusted to zzz" is thrown and the value is adjusted to the lowest possible value for that variable. The dynamic server variable which is configured through the client exhibit the same behavior as fix made for variables configured during the server start up. --- mysys/my_getopt.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'mysys') diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 03469589173..6d27c9a9e73 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1005,6 +1005,14 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, return num; } +static inline my_bool is_negative_num(char* num) +{ + while (my_isspace(&my_charset_latin1, *num)) + num++; + + return (*num == '-'); +} + /* function: getopt_ull @@ -1014,7 +1022,20 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err) { - ulonglong num= eval_num_suffix(arg, err, (char*) optp->name); + char buf[255]; + ulonglong num; + + /* If a negative number is specified as a value for the option. */ + if (arg == NULL || is_negative_num(arg) == TRUE) + { + num= (ulonglong) optp->min_value; + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s': value %s adjusted to %s", + optp->name, arg, ullstr(num, buf)); + } + else + num= eval_num_suffix(arg, err, (char*) optp->name); + return getopt_ull_limit_value(num, optp, NULL); } -- cgit v1.2.1