Commit 7ab5c682 authored by unknown's avatar unknown
Browse files

Fixed buffer overflow cases (should not be possible to do...)

Fixed for autoincrement support/GUID


client/client_priv.h:
  Option for autoincrement
client/mysqlslap.c:
  Fixed buffer overflow where sprintf is used (now removed).
  Fixed for auto-increment support/GUID.
mysql-test/t/mysqlslap.test:
  Added test for auto increment, update, write, read, and mixed.
parent 793a137d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ enum options_client
  OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_CREATE_SLAP_SCHEMA,
  OPT_SLAP_CSV, OPT_SLAP_CREATE_STRING,
  OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
  OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
  OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
  OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID,
  OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT,
  OPT_DEBUG_INFO, OPT_COLUMN_TYPES
+342 −29
Original line number Diff line number Diff line
@@ -71,9 +71,16 @@

#define SHOW_VERSION "0.9"

#define HUGE_STRING_LENGTH 8096
#define HUGE_STRING_LENGTH 8196
#define RAND_STRING_SIZE 126

/* Types */
#define SELECT_TYPE 0
#define UPDATE_TYPE 1
#define INSERT_TYPE 2
#define UPDATE_TYPE_REQUERIES_PREFIX 3
#define CREATE_TABLE_TYPE 4

#include "client_priv.h"
#ifdef HAVE_LIBPTHREAD
#include <my_pthread.h>
@@ -107,6 +114,9 @@ static char *shared_memory_base_name=0;

static char **defaults_argv;

char *primary_keys;
unsigned long long primary_keys_number_of;

static char *host= NULL, *opt_password= NULL, *user= NULL,
            *user_supplied_query= NULL,
            *default_engine= NULL,
@@ -127,6 +137,8 @@ static my_bool opt_slave;

static my_bool opt_compress= FALSE, tty_password= FALSE,
               opt_silent= FALSE,
               auto_generate_sql_autoincrement= FALSE,
               auto_generate_sql_guid_primary= FALSE,
               auto_generate_sql= FALSE;
const char *auto_generate_sql_type= "mixed";

@@ -159,6 +171,7 @@ typedef struct statement statement;
struct statement {
  char *string;
  size_t length;
  unsigned char type;
  statement *next;
};

@@ -206,7 +219,10 @@ static int drop_schema(MYSQL *mysql, const char *db);
uint get_random_string(char *buf);
static statement *build_table_string(void);
static statement *build_insert_string(void);
static statement *build_update_string(void);
static statement *build_query_string(void);
static int generate_primary_key_list(MYSQL *mysql);
static int drop_primary_key_list(void);
static int create_schema(MYSQL *mysql, const char *db, statement *stmt, 
              statement *engine_stmt);
static int run_scheduler(stats *sptr, statement *stmts, uint concur, 
@@ -344,6 +360,13 @@ int main(int argc, char **argv)
        if (create_statements)
          create_schema(&mysql, create_schema_string, create_statements, eptr);
        
        /*
          If we generated GUID we need to build a list of them from creation that
          we can later use.
        */
        if (auto_generate_sql_guid_primary)
          generate_primary_key_list(&mysql);

        run_scheduler(sptr, query_statements, *current, client_limit); 
      }

@@ -359,6 +382,10 @@ int main(int argc, char **argv)

    if (!opt_preserve)
      drop_schema(&mysql, create_schema_string);

    if (auto_generate_sql_guid_primary)
      drop_primary_key_list();

  } while (eptr ? (eptr= eptr->next) : 0);

  if (!opt_only_print) 
@@ -397,8 +424,18 @@ static struct my_option my_long_options[] =
    "Generate SQL where not supplied by file or command line.",
    (gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql,
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
    "Add autoincrement to auto-generated tables.",
    (gptr*) &auto_generate_sql_autoincrement, 
    (gptr*) &auto_generate_sql_autoincrement,
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
    "Add GUID based primary keys to auto-generated tables.",
    (gptr*) &auto_generate_sql_guid_primary, 
    (gptr*) &auto_generate_sql_guid_primary,
    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
    "Load types are mixed, write, or read. Default is mixed\n",
    "Load types are mixed, update, write, or read. Default is mixed\n",
    (gptr*) &auto_generate_sql_type, (gptr*) &auto_generate_sql_type,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
@@ -614,7 +651,7 @@ get_random_string(char *buf)
static statement *
build_table_string(void)
{
  char       buf[512];
  char       buf[HUGE_STRING_LENGTH];
  int        col_count;
  statement *ptr;
  DYNAMIC_STRING table_string;
@@ -626,22 +663,63 @@ build_table_string(void)
  init_dynamic_string(&table_string, "", 1024, 1024);

  dynstr_append(&table_string, "CREATE TABLE `t1` (");

  if (auto_generate_sql_autoincrement)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, "id serial") > HUGE_STRING_LENGTH)
    {
        fprintf(stderr, "Memory Allocation error in create table\n");
        exit(1);
    }
    dynstr_append(&table_string, buf);

    if (num_int_cols || num_char_cols)
      dynstr_append(&table_string, ",");
  }

  if (auto_generate_sql_guid_primary)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, "id varchar(32) primary key") > HUGE_STRING_LENGTH)
    {
        fprintf(stderr, "Memory Allocation error in create table\n");
        exit(1);
    }
    dynstr_append(&table_string, buf);

    if (num_int_cols || num_char_cols)
      dynstr_append(&table_string, ",");
  }

  if (num_int_cols)
    for (col_count= 1; col_count <= num_int_cols; col_count++)
    {
    sprintf(buf, "intcol%d INT(32)", col_count); 
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32)", col_count) 
          > HUGE_STRING_LENGTH)
      {
        fprintf(stderr, "Memory Allocation error in create table\n");
        exit(1);
      }
      dynstr_append(&table_string, buf);

      if (col_count < num_int_cols || num_char_cols > 0)
        dynstr_append(&table_string, ",");
    }

  if (num_char_cols)
    for (col_count= 1; col_count <= num_char_cols; col_count++)
    {
    sprintf(buf, "charcol%d VARCHAR(128)", col_count);
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)", col_count)
          > HUGE_STRING_LENGTH)
      {
        fprintf(stderr, "Memory Allocation error in creating table\n");
        exit(1);
      }
      dynstr_append(&table_string, buf);

      if (col_count < num_char_cols)
        dynstr_append(&table_string, ",");
    }

  dynstr_append(&table_string, ")");
  ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
  ptr->string = (char *)my_malloc(table_string.length+1, MYF(MY_WME));
@@ -651,6 +729,94 @@ build_table_string(void)
  DBUG_RETURN(ptr);
}

/*
  build_update_string()

  This function builds insert statements when the user opts to not supply
  an insert file or string containing insert data
*/
static statement *
build_update_string(void)
{
  char       buf[HUGE_STRING_LENGTH];
  int        col_count;
  statement *ptr;
  DYNAMIC_STRING update_string;
  DBUG_ENTER("build_update_string");

  init_dynamic_string(&update_string, "", 1024, 1024);

  dynstr_append(&update_string, "UPDATE t1 SET ");

  if (num_int_cols)
    for (col_count= 1; col_count <= num_int_cols; col_count++)
    {
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count, 
                   random()) > HUGE_STRING_LENGTH)
      {
        fprintf(stderr, "Memory Allocation error in creating update\n");
        exit(1);
      }
      dynstr_append(&update_string, buf);

      if (col_count < num_int_cols || num_char_cols > 0)
        dynstr_append_mem(&update_string, ",", 1);
    }

  if (num_char_cols)
    for (col_count= 1; col_count <= num_char_cols; col_count++)
    {
      char rand_buffer[RAND_STRING_SIZE];
      int buf_len= get_random_string(rand_buffer);

      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count, 
                   buf_len, rand_buffer) 
          > HUGE_STRING_LENGTH)
      {
        fprintf(stderr, "Memory Allocation error in creating update\n");
        exit(1);
      }
      dynstr_append(&update_string, buf);

      if (col_count < num_char_cols)
        dynstr_append_mem(&update_string, ",", 1);
    }

  if (auto_generate_sql_autoincrement)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, " WHERE id = %ld", 
                 (long int)(random() % auto_generate_sql_number) ) 
        > HUGE_STRING_LENGTH)
    {
      fprintf(stderr, "Memory Allocation error in creating update_string\n");
      exit(1);
    }
    dynstr_append(&update_string, buf);
  }

  if (auto_generate_sql_guid_primary)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, " WHERE id = ") > HUGE_STRING_LENGTH)
    {
      fprintf(stderr, "Memory Allocation error in creating update_string\n");
      exit(1);
    }
    dynstr_append(&update_string, buf);
  }


  ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
  ptr->string= (char *)my_malloc(update_string.length+1, MYF(MY_WME));
  ptr->length= update_string.length+1;
  if (auto_generate_sql_guid_primary)
    ptr->type= UPDATE_TYPE_REQUERIES_PREFIX ;
  else
    ptr->type= UPDATE_TYPE;
  strmov(ptr->string, update_string.str);
  dynstr_free(&update_string);
  DBUG_RETURN(ptr);
}


/*
  build_insert_string()
@@ -661,7 +827,7 @@ build_table_string(void)
static statement *
build_insert_string(void)
{
  char       buf[RAND_STRING_SIZE];
  char       buf[HUGE_STRING_LENGTH];
  int        col_count;
  statement *ptr;
  DYNAMIC_STRING insert_string;
@@ -669,15 +835,49 @@ build_insert_string(void)

  init_dynamic_string(&insert_string, "", 1024, 1024);

  dynstr_append_mem(&insert_string, "INSERT INTO t1 VALUES (", 23);
  dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");

  if (auto_generate_sql_autoincrement)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, "NULL") > HUGE_STRING_LENGTH)
    {
      fprintf(stderr, "Memory Allocation error in creating insert\n");
      exit(1);
    }
    dynstr_append(&insert_string, buf);

    if (num_int_cols || num_char_cols)
      dynstr_append(&insert_string, ",");
  }

  if (auto_generate_sql_guid_primary)
  {
    if (snprintf(buf, HUGE_STRING_LENGTH, "uuid()") > HUGE_STRING_LENGTH)
    {
        fprintf(stderr, "Memory Allocation error in create table\n");
        exit(1);
    }
    dynstr_append(&insert_string, buf);

    if (num_int_cols || num_char_cols)
      dynstr_append(&insert_string, ",");
  }

  if (num_int_cols)
    for (col_count= 1; col_count <= num_int_cols; col_count++)
    {
    sprintf(buf, "%ld", random());
      if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
      {
        fprintf(stderr, "Memory Allocation error in creating insert\n");
        exit(1);
      }
      dynstr_append(&insert_string, buf);

      if (col_count < num_int_cols || num_char_cols > 0)
        dynstr_append_mem(&insert_string, ",", 1);
    }

  if (num_char_cols)
    for (col_count= 1; col_count <= num_char_cols; col_count++)
    {
      int buf_len= get_random_string(buf);
@@ -688,11 +888,13 @@ build_insert_string(void)
      if (col_count < num_char_cols)
        dynstr_append_mem(&insert_string, ",", 1);
    }

  dynstr_append_mem(&insert_string, ")", 1);

  ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
  ptr->string= (char *)my_malloc(insert_string.length+1, MYF(MY_WME));
  ptr->length= insert_string.length+1;
  ptr->type= INSERT_TYPE;
  strmov(ptr->string, insert_string.str);
  dynstr_free(&insert_string);
  DBUG_RETURN(ptr);
@@ -708,7 +910,7 @@ build_insert_string(void)
static statement *
build_query_string(void)
{
  char       buf[512];
  char       buf[HUGE_STRING_LENGTH];
  int        col_count;
  statement *ptr;
  static DYNAMIC_STRING query_string;
@@ -719,7 +921,12 @@ build_query_string(void)
  dynstr_append_mem(&query_string, "SELECT ", 7);
  for (col_count= 1; col_count <= num_int_cols; col_count++)
  {
    sprintf(buf, "intcol%d", col_count);
    if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count) 
        > HUGE_STRING_LENGTH)
    {
      fprintf(stderr, "Memory Allocation error in creating select\n");
      exit(1);
    }
    dynstr_append(&query_string, buf);

    if (col_count < num_int_cols || num_char_cols > 0)
@@ -728,7 +935,12 @@ build_query_string(void)
  }
  for (col_count= 1; col_count <= num_char_cols; col_count++)
  {
    sprintf(buf, "charcol%d", col_count);
    if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
        > HUGE_STRING_LENGTH)
    {
      fprintf(stderr, "Memory Allocation error in creating select\n");
      exit(1);
    }
    dynstr_append(&query_string, buf);

    if (col_count < num_char_cols)
@@ -739,6 +951,7 @@ build_query_string(void)
  ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
  ptr->string= (char *)my_malloc(query_string.length+1, MYF(MY_WME));
  ptr->length= query_string.length+1;
  ptr->type= SELECT_TYPE;
  strmov(ptr->string, query_string.str);
  dynstr_free(&query_string);
  DBUG_RETURN(ptr);
@@ -773,6 +986,14 @@ get_options(int *argc,char ***argv)
      exit(1);
  }

  if (auto_generate_sql && auto_generate_sql_guid_primary && auto_generate_sql_autoincrement)
  {
      fprintf(stderr,
              "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
              my_progname);
      exit(1);
  }

  parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);

  if (lock_directory)
@@ -836,6 +1057,23 @@ get_options(int *argc,char ***argv)
        ptr_statement->next= build_insert_string();
      }
    }
    else if (auto_generate_sql_type[0] == 'u')
    {
      for (ptr_statement= create_statements, x= 0; 
           x < auto_generate_sql_number; 
           x++, ptr_statement= ptr_statement->next)
      {
        ptr_statement->next= build_insert_string();
      }

      query_statements= build_update_string();
      for (ptr_statement= query_statements, x= 0; 
           x < auto_generate_sql_number; 
           x++, ptr_statement= ptr_statement->next)
      {
          ptr_statement->next= build_update_string();
      }
    }
    else /* Mixed mode is default */
    {
      int coin= 0;
@@ -943,6 +1181,59 @@ static int run_query(MYSQL *mysql, const char *query, int len)
}


static int
generate_primary_key_list(MYSQL *mysql)
{
  char query[HUGE_STRING_LENGTH];
  int len;
  MYSQL_RES *result;
  MYSQL_ROW row;
  char *ptr;
  DBUG_ENTER("create_schema");

  len= snprintf(query, HUGE_STRING_LENGTH, "SELECT id from t1");

  if (run_query(mysql, query, len))
  {
    fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
            mysql_error(mysql));
    exit(1);
  }

  if (opt_only_print)
  {
    primary_keys_number_of= 1;
    primary_keys= (char *)my_malloc(sizeof(char) * primary_keys_number_of * 32, 
                                    MYF(MY_ZEROFILL));
    memcpy(primary_keys, "796c4422-1d94-102a-9d6d-00e0812d", 32); 
    DBUG_RETURN(0);
  }
  result= mysql_store_result(mysql);
  DBUG_ASSERT(result);
  primary_keys_number_of= mysql_num_rows(result);
  /*
    We know the GUID are 32 characters in length, so we preallocate.
  */
  primary_keys= (char *)my_malloc(sizeof(char) * primary_keys_number_of * 32, 
                                  MYF(MY_ZEROFILL));
  ptr= primary_keys;
  while ((row = mysql_fetch_row(result)))
  {
    memcpy(ptr, row[0], 32);
    ptr+= 32;
  }
  DBUG_ASSERT(ptr == primary_keys + (primary_keys_number_of * 32));
  mysql_free_result(result);

  DBUG_RETURN(0);
}

static int
drop_primary_key_list(void)
{
  my_free(primary_keys, MYF(0));
  return 0;
}

static int
create_schema(MYSQL *mysql, const char *db, statement *stmt, 
@@ -1218,6 +1509,27 @@ run_task(thread_context *con)

limit_not_met:
    for (ptr= con->stmt; ptr && ptr->length; ptr= ptr->next)
    {
      /* 
        We have to execute differently based on query type. This should become a function.
      */
      if (ptr->type == UPDATE_TYPE_REQUERIES_PREFIX)
      {
        char buffer[HUGE_STRING_LENGTH];
        char *key= primary_keys + (random() % primary_keys_number_of);
        int length;

        length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%.*s'", 
                         (int)ptr->length, ptr->string, 32, key);
        
        if (run_query(mysql, buffer, length))
        {
          fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
                  my_progname, (uint)length, buffer, mysql_error(mysql));
          goto end;
        }
      }
      else
      {
        if (run_query(mysql, ptr->string, ptr->length))
        {
@@ -1225,6 +1537,7 @@ run_task(thread_context *con)
                  my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
          goto end;
        }
      }
      if (mysql_field_count(mysql))
      {
        result= mysql_store_result(mysql);
+14 −0
Original line number Diff line number Diff line
@@ -14,3 +14,17 @@
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --delimiter=";" --query="select * from t1;select * from t2" --create="CREATE TABLE t1 (id int, name varchar(64)); create table t2(foo1 varchar(32), foo2 varchar(32)); INSERT INTO t1 VALUES (1, 'This is a test'); insert into t2 values ('test', 'test2')"

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --create-schema=test_env

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=20 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --create-schema=test_env --auto-generate-sql-add-autoincrement 

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement 

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=update

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=read

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=write

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-add-autoincrement --auto-generate-sql-load-type=mixed

--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=update