버그 분석을 도입하기 위해 GreatSQL sp에 새로운 sp_instr을 추가합니다.

버그 분석을 도입하기 위해 GreatSQL sp에 새로운 sp_instr을 추가합니다.

1. 문제 발견

개발에 사용되는 sp는 수요를 충족시키기 위해 새로운 sp_instr을 추가해야 하는데, 여러 개의 sp_instr을 추가한 후 새로운 sp를 실행하면 코어가 발생하는 것으로 나타났습니다.

참고: 이번에는 GreatSQL 8.0.32-25가 사용됩니다.

1. sp_head.cc의 init_sp_psi_keys() 코드에 10개의 새로운 sp_instr을 추가합니다.

void init_sp_psi_keys() {
  mysql_statement_register(category, &sp_instr_stmt1::psi_info, 1);
  mysql_statement_register(category, &sp_instr_stmt2::psi_info, 1);
  mysql_statement_register(category, &sp_instr_stmt3::psi_info, 1);
  ......
  mysql_statement_register(category, &sp_instr_stmt10::psi_info, 1);
}

2. sp_instr.cc에 새로운 sp_instr_stmt 관련 구현 코드를 추가합니다. 그 중 sql_yacc.yy 및 sql_lex.cc에 그에 따라 새로운 구문을 추가해야 합니다.

3. sp_rcontext.h는 sp_rcontext 클래스에 있으며 몇 가지 새로운 멤버 변수를 추가합니다. 다음 코드는 단지 예시일 뿐 실제적인 가치는 없습니다.

  Field *m_return_value_fld_tmp{m_return_value_fld};
  Field *m_return_value_fld_tmp1{m_return_value_fld};
  Field *m_return_value_fld_tmp2{m_return_value_fld};

4. 새 sp_instr_stmt의 내용이 포함된 새 sp를 생성한 다음 sp를 호출합니다. 목록의 멤버 값이 지워져 충돌이 발생하므로 코드 논리가 지워지는 것으로 나타났습니다. 아래는 관련 스택입니다. 코드 기밀성이 관련되어 있으므로 오픈 소스 부분의 관련 스택만 가져옵니다.

#0  0x0000555558f3f3d9 in base_list_iterator::next_fast (this=0x7fffe01e9de0)
    at /sql/sql_list.h:371
#1  0x0000555558fc59b7 in List_iterator_fast<Create_field>::operator++ (this=0x7fffe01e9de0)
    at /sql/sql_list.h:605
#2  0x0000555559753ea2 in create_tmp_table_from_fields (thd=0x7fff20001050, field_list=..., 
    is_virtual=false, select_options=0, alias=0x0)
    at /sql/sql_tmp_table.cc:2131
#3  0x0000555559084a09 in Item_xx::val_str (this=0x7fff20b673c8)
    at /sql/item_func.cc:10796
#4  0x0000555558fa408b in Item::save_in_field_inner (this=0x7fff20b673c8, field=0x7fff20b9b1a8, 
    no_conversions=false) at /sql/item.cc:8202
#5  0x0000555558fa3c43 in Item::save_in_field (this=0x7fff20b673c8, field=0x7fff20b9b1a8, 
    no_conversions=false) at /sql/item.cc:8144
#6  0x0000555559400322 in sp_eval_expr (thd=0x7fff20001050, result_field=0x7fff20b9b1a8, 
    expr_item_ptr=0x7fff20b67620) at /sql/sp.cc:3613
#7  0x000055555943b1d1 in sp_rcontext::set_variable (this=0x7fff20b85d80, thd=0x7fff20001050, 
    field=0x7fff20b9b1a8, value=0x7fff20b67620)
    at /sql/sp_rcontext.cc:1023
#8  0x0000555558fc3a8e in sp_rcontext::set_variable (this=0x7fff20b85d80, thd=0x7fff20001050, 
    var_idx=1, value=0x7fff20b67620)
    at /sql/sp_rcontext.h:176
打印crash处的信息,发现list里面的值被清空了。
(gdb) p tmp
$1 = (list_node *) 0x0

2. 문제 조사 프로세스

1. 코드를 잘 확인하여 코드 로직에 문제가 없는지 확인합니다. 실제로는 목록의 값이 성공적으로 할당되었지만 실행하면 목록이 지워지는 것으로 확인됩니다. 이는 분명히 메모리 누수이거나 목록의 요소 공간을 차지하거나 비워지게 만드는 다른 곳의 메모리 오버플로입니다. sp 코드를 다른 것으로 교체하면 충돌이 발생할 때도 있고 그렇지 않을 때도 있습니다. 트리거링 메커니즘이 명확하지 않으며, 메모리 누수를 일으킨 특정 코드 줄을 알 수 없습니다.

2. 그래서 처음 코드를 추가했던 곳을 다시 살펴보니, sp_instr_stmt를 10개 추가한 것과 관련이 있을 것 같았습니다. 관련 배열이나 메모리가 확장되지 않았기 때문일 가능성이 매우 높습니다. 메모리 오버플로.

3. 의심되는 문제 영역을 찾은 후 관련 코드 조사를 시작할 수 있습니다. sp_instr 추가와 관련된 코드를 확인하세요.

添加sp_instr实现代码如下:
mysql_statement_register(category, &sp_instr_stmt1::psi_info, 1);

于是继续往下面调查mysql_statement_register实现的代码,看到这里果然用到了statement_class_max:
PFS_statement_key register_statement_class(const char *name, uint name_length,
                                           PSI_statement_info *info) {
  /* See comments in register_mutex_class */
  uint32 index;
  PFS_statement_class *entry;

  REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max,
                           name, name_length)

接着查看statement_class_max的赋值的地方:
int init_statement_class(uint statement_class_sizing) {
  int result = 0;
  statement_class_dirty_count = statement_class_allocated_count = 0;
  statement_class_max = statement_class_sizing;

通过搜索代码查到statement_class_sizing相关的参数配置的地方,看到这里有一个SP_PSI_STATEMENT_INFO_COUNT宏定义,这个值跟sp_instr的数量有关。
static Sys_var_ulong Sys_pfs_max_statement_classes(
    "performance_schema_max_statement_classes",
    "Maximum number of statement instruments.",
    READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing),
    CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
    DEFAULT((ulong)SQLCOM_END + (ulong)COM_END + 5 +
            SP_PSI_STATEMENT_INFO_COUNT + CLONE_PSI_STATEMENT_COUNT),
    BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);

继续全文搜索,发现在sp_head.h定义了,这里的值为16,数了一下现存的sp_instr个数刚好为16个,至此问题原因发现,因为我加了10个sp_instr,而这个宏定义的值没有跟着增加,导致内存溢出。
#define SP_PSI_STATEMENT_INFO_COUNT 16

3. 문제 해결 방법

위 코드를 파싱한 후, 다음과 같이 수정하면 해당 문제 코드를 수정할 수 있습니다. 다시 컴파일하면 문제가 해결됩니다.

sp_head.h修改SP_PSI_STATEMENT_INFO_COUNT宏定义:
#define SP_PSI_STATEMENT_INFO_COUNT 26

因为增加了Sys_pfs_max_statement_classes的default值,因为相关配置范围也要跟着增加,因此把range相应加大。
static Sys_var_ulong Sys_pfs_max_statement_classes(
    "performance_schema_max_statement_classes",
    "Maximum number of statement instruments.",
    READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing),
    CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256 * 2),
    DEFAULT((ulong)SQLCOM_END + (ulong)COM_END + 5 +
            SP_PSI_STATEMENT_INFO_COUNT + CLONE_PSI_STATEMENT_COUNT),
    BLOCK_SIZE(1), PFS_TRAILING_PROPERTIES);

4. 문제 요약

GreatSQL의 sp에 새로운 sp_instr을 추가할 때 메모리 오버플로를 방지하기 위해 그에 따라 해당 매개변수 값을 늘려야 합니다. 다른 기능도 비슷하게 수정해야 하는 경우 관련 매개변수 구성이나 매크로 정의가 포함되어 있는지 먼저 주의 깊게 조사해야 합니다. 그렇지 않으면 설명할 수 없는 온갖 종류의 문제에 직면하게 되며 조사하는 데 많은 시간이 걸립니다.

이번에 발견된 문제는 새로 추가된 기능으로 인해 발생한 버그로, 실제 개발 및 적용 시에도 유사한 문제에 주의해야 합니다.

위의 문제는 MySQL/Percona에도 존재합니다.


GreatSQL을 즐겨보세요 :)

GreatSQL 소개

GreatSQL은 금융 수준의 애플리케이션에 적합한 국내 독립 오픈소스 데이터베이스로, 고성능, 높은 신뢰성, 높은 사용 편의성, 높은 보안성 등 많은 핵심 기능을 갖추고 있으며 MySQL 또는 Percona Server를 대체하여 사용할 수 있습니다. 온라인 생산 환경에서 사용되며 완전 무료이며 MySQL 또는 Percona Server와 호환됩니다.

관련 링크: GreatSQL 커뮤니티 Gitee GitHub Bilibili

GreatSQL 커뮤니티:

영상

커뮤니티 보상 제안 및 피드백: https://greatsql.cn/thread-54-1-1.html

커뮤니티 블로그 수상작 제출 세부정보: https://greatsql.cn/thread-100-1-1.html

(기사에 대해 궁금한 점이 있거나 남다른 통찰력이 있다면 공식 커뮤니티 홈페이지에 가서 질문하거나 공유해 보세요~)

기술교류그룹:

위챗 & QQ 그룹:

QQ 그룹: 533341697

WeChat 그룹: GreatSQL 커뮤니티 도우미(WeChat ID: wanlidbc)를 친구로 추가하고 커뮤니티 도우미가 귀하를 그룹에 추가할 때까지 기다립니다.

1990년대에 태어난 프로그래머가 비디오 포팅 소프트웨어를 개발하여 1년도 안 되어 700만 개 이상의 수익을 올렸습니다. 결말은 매우 처참했습니다! 고등학생들이 성인식으로 자신만의 오픈소스 프로그래밍 언어 만든다 - 네티즌 날카로운 지적: 만연한 사기로 러스트데스크 의존, 가사 서비스 타오바오(taobao.com)가 가사 서비스를 중단하고 웹 버전 최적화 작업 재개 자바 17은 가장 일반적으로 사용되는 Java LTS 버전입니다. Windows 10 시장 점유율 70%에 도달, Windows 11은 계속해서 Open Source Daily를 지원합니다. Google은 Docker가 지원하는 오픈 소스 Rabbit R1을 지원합니다. Electric, 개방형 플랫폼 종료 Apple, M4 칩 출시 Google, Android 범용 커널(ACK) 삭제 RISC-V 아키텍처 지원 Yunfeng은 Alibaba에서 사임하고 향후 Windows 플랫폼에서 독립 게임을 제작할 계획
{{o.이름}}
{{이름}}

추천

출처my.oschina.net/GreatSQL/blog/11102185