成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Mysql bug#64624:備庫(kù)開(kāi)啟query cache后crash的分析

運(yùn)維 系統(tǒng)運(yùn)維
理論上講,只有SQL導(dǎo)致數(shù)據(jù)變更了才會(huì)寫(xiě)binlog,而select語(yǔ)句是不會(huì)被備庫(kù)復(fù)制執(zhí)行的,那為何備庫(kù)在do_apply_event時(shí)會(huì)訪問(wèn)query cache?

  主庫(kù):mysql-5.1.48

  備庫(kù):percona server 5.5.18(query cache on)

  重現(xiàn):

  備庫(kù)在valgrind下啟動(dòng):

 valgrind –leak-check=full –trace-children=yes –log-file=$HOME/valgrind.1 ./bin/mysqld –defaults-file=my.s.s.cnf

  主庫(kù)上執(zhí)行:

 /*!40000 ALTER TABLE `t1` DISABLE KEYS */;

  出錯(cuò)結(jié)果:

  1. Thread 21:  
  2. Conditional jump or move depends on uninitialised value(s)  
  3. at 0x***6743: Query_cache::send_result_to_client(THD*, char*, unsigned int) (sql_cache.cc:2051)  
  4. by 0x5EDE27: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:5756)  
  5. by 0x800B79: Query_log_event::do_apply_event(Relay_log_info const*, char const*, unsigned int) (log_event.cc:3398)  
  6. by 0×800157: Query_log_event::do_apply_event(Relay_log_info const*) (log_event.cc:3166)  
  7. by 0×572005: Log_event::apply_event(Relay_log_info const*) (log_event.h:1135)  
  8. by 0x56B1A9: apply_event_and_update_pos(Log_event*, THD*, Relay_log_info*) (slave.cc:2351)  
  9. by 0x56B6E9: exec_relay_log_event(THD*, Relay_log_info*) (slave.cc:2511)  
  10. by 0x56D8F6: handle_slave_sql (slave.cc:3329)  
  11. by 0x3A01806D63: start_thread (pthread_create.c:308) 

  原因分析:

  理論上講,只有SQL導(dǎo)致數(shù)據(jù)變更了才會(huì)寫(xiě)binlog,而select語(yǔ)句是不會(huì)被備庫(kù)復(fù)制執(zhí)行的,那為何備庫(kù)在do_apply_event時(shí)會(huì)訪問(wèn)query cache?

  因?yàn)閙ysql執(zhí)行sql的入口是mysql_parse,對(duì)于從主庫(kù)上復(fù)制過(guò)來(lái)的binlog,如果是SQL形式(DDL或者binlog format為statement),會(huì)進(jìn)入mysql_parse,而mysql_parse的邏輯是首先查看query cache,如果不能返回結(jié)果就執(zhí)行mysql_execute_command,并且對(duì)于select query,之后還會(huì)將結(jié)果寫(xiě)到query cache.

  在Query_cache::send_result_to_client函數(shù)中會(huì)對(duì)sql語(yǔ)句進(jìn)行檢查,如果不是SELECT語(yǔ)句會(huì)直接返回,檢查邏輯如下:

  1. if (!((i + 2 < query_length) &&  
  2. ((my_toupper(system_charset_info, sql[i])     == ‘S’ &&  
  3. my_toupper(system_charset_info, sql[i + 1]) == ‘E’ &&  
  4. my_toupper(system_charset_info, sql[i + 2]) == ‘L’) ||  
  5. sql[i] == ‘/’)))  
  6. {  
  7. DBUG_PRINT(“qcache”, (“The statement is not a SELECT; Not cached”));  
  8. goto err;  

  因此,備庫(kù)復(fù)制執(zhí)行binlog時(shí)雖然會(huì)進(jìn)入到query cache,但是由于它們不是SELECT QUERY會(huì)直接返回,其實(shí)并沒(méi)有真正訪問(wèn)query cache,然而上述判斷邏輯也有出現(xiàn)問(wèn)題的時(shí)候,那就是類(lèi)似這樣的SQL:

 /*!40000 ALTER TABLE `t1` DISABLE KEYS */;

  會(huì)和SELECT一樣繼續(xù)往下執(zhí)行…,直到:

  1. size_t db_len;  
  2. memcpy((char *) &db_len, (sql + query_length + 1), sizeof(size_t));  
  3. if (thd->db_length != db_len)          <– 出錯(cuò)!  
  4. {  
  5. …  
  6. DBUG_PRINT(“qcache”, (“Current database has changed since start of query”));  
  7. goto err;  

  這是因?yàn)閙emcpy讀到的未初始化的數(shù)據(jù)!

  在alloc_query中,querybuffer的內(nèi)存布局如下:

  +———–+———–+—————————————-+———–+
  | Query  |db len  |       db_name                    | FLAGS |
  +———–+———–+—————————————-+———–+

  其中db len類(lèi)型為size_t,保存db_name的長(zhǎng)度

  send_result_to_client中的計(jì)算tot_length的方式可以說(shuō)明:

 tot_length= query_length + 1 + sizeof(size_t) + thd->db_length + QUERY_CACHE_FLAGS_SIZE;

  而在Query_log_event::Query_log_event函數(shù)中,data buffer如下:(下面的接在上面之后):

  +———-+—————–+——-+————-+————-+—-+
  | catlog | time_zone | user|   host    |db name | \0 |
  +———-+—————–+——-+————-+————-+—-+
  +———-+———————————————————+———-+
  | Query | uninitiatlized space of size of db len | FLAGS |
  +———-+———————————————————+———-+

  其中為query buffer分配的空間從Query開(kāi)始,比較可知,相對(duì)于alloc_query中的缺少了db len部分(sizeof(size_t))

  在將其傳入到send_result_to_client函數(shù)中時(shí),就導(dǎo)致了memecpy讀取未初始化的數(shù)據(jù),從而使得條件不滿足而退出query cache,但是這并不會(huì)導(dǎo)致任何問(wèn)題,因?yàn)閭鋷?kù)執(zhí)行binlog本該不訪問(wèn)query cache,由于memcpy只是copy了未初始化的數(shù)據(jù)(后面還有空間)而并沒(méi)有訪問(wèn)NULL pointer,因此不會(huì)出現(xiàn)問(wèn)題,而這也是重現(xiàn)crash比較困難的原因!

  但是,這里存在一個(gè)隱患,如果讀取的未初始化數(shù)據(jù)db_len正好和thd->db_length相同,那么Query_cache::send_result_to_client還將繼續(xù)執(zhí)行下去,直到…

 memcpy((uchar *)(sql + (tot_length – QUERY_CACHE_FLAGS_SIZE)),
(uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);

  悲劇發(fā)生了…tot_length是按照alloc_query中的內(nèi)存布局計(jì)算出來(lái)的,但是實(shí)際傳給send_result_to_client的query是缺少一個(gè)字段的,于是memcpy訪問(wèn)越界,導(dǎo)致slave crash

  mysql官方和percona都為此bug提供了patch,percona通過(guò)thd->alloc重新分配了一個(gè)query buffer,而mysql官方直接修改了bug的源頭,都放進(jìn)來(lái)。

patch:

  http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/3837

  https://bugs.launchpad.net/percona-server/+bug/915814

責(zé)任編輯:黃丹 來(lái)源: taobaodba.com
相關(guān)推薦

2010-07-05 09:07:42

2009-06-29 09:00:42

Hibernate的Q

2023-11-15 17:23:30

測(cè)試軟件開(kāi)發(fā)

2021-07-04 22:29:12

MySQL死鎖云日志

2010-05-19 16:39:11

MySQL查詢

2014-07-29 15:44:33

Linux內(nèi)核Crash

2021-12-30 10:43:21

Android函數(shù)Crash

2025-05-26 03:55:00

MySQLCrash代碼

2010-06-03 08:59:50

MySQL Query

2010-01-25 11:55:41

MySQL數(shù)據(jù)庫(kù)備份數(shù)據(jù)庫(kù)安全

2015-10-08 11:43:10

華為云災(zāi)備雙活數(shù)據(jù)

2010-06-02 14:57:38

MySQL cache

2010-05-14 16:49:43

MySQL 數(shù)據(jù)庫(kù)

2020-07-08 07:50:50

OOM虛擬機(jī)Java

2025-05-26 04:00:20

2021-09-28 11:15:49

MySQL備份數(shù)據(jù)庫(kù)

2021-12-05 21:06:27

軟件

2024-04-03 08:33:31

MySQLCursorcursor

2019-01-15 14:44:02

CPU Cache L共享存儲(chǔ)器

2011-08-15 09:16:01

虛擬化企業(yè)災(zāi)備
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 夜夜艹天天干 | 91精品在线看 | 热99在线 | 欧美激情精品久久久久久免费 | 精品国产一区二区国模嫣然 | 精品久久亚洲 | 久久久婷 | 欧美午夜精品理论片a级按摩 | 9色视频在线 | www.国产 | 国产综合精品 | 久久久tv | 在线三级电影 | 久久久精品影院 | 中文字幕在线一区二区三区 | 中文字幕在线免费视频 | 国产福利二区 | 日韩视频在线一区二区 | 黄色在线免费网站 | 99热热精品 | 中文久久 | 人人做人人澡人人爽欧美 | 久久久久亚洲av毛片大全 | 成人免费淫片aa视频免费 | 欧美一级欧美三级在线观看 | 蜜桃五月天| 一区二区中文 | 91精品国产综合久久香蕉麻豆 | 中文日本在线 | 蜜桃色网 | 日韩亚洲一区二区 | 91高清视频| 91成人| 亚洲视频一 | 亚洲情综合五月天 | 国外成人在线视频网站 | 中文字幕二区 | 日本精品久久 | 国产精品综合网 | 欧美日韩在线免费 | 国产精品久久久久久久岛一牛影视 |