본문 바로가기
SWE/C++ OOP

실행 에러 AddressSanitizer odr violation 해결 방법

by S나라라2 2023. 1. 20.
반응형

문제 발생 상황은 프로그램을 실행하였더니 라이브러리 로딩하는 중에 아래 로그를 남기고 종료되었다.

 

 

에러 로그

29-Jan-2021 11:25:04.597 loading DynDB instance 'sample' driver '../driver/lib/sample.so'
=================================================================
==2511090==ERROR: AddressSanitizer: odr-violation (0x7f9e15d78d00):
  [1] size=8 'dns_lctx' log.c:69:33
  [2] size=8 'dns_lctx' log.c:69:33
These globals were registered at these points:
  [1]:
    #0 0x7f9e324a7328  (/lib64/libasan.so.6+0x37328)
    #1 0x7f9e14913fb2 in _sub_I_00099_1 (../driver/lib/sample.so+0xaa8fb2)
    #2 0x7f9e32e6f8dd in call_init.part.0 (/lib64/ld-linux-x86-64.so.2+0x108dd)

  [2]:
    #0 0x7f9e324a7328  (/lib64/libasan.so.6+0x37328)
    #1 0x737dad in _sub_I_00099_1 (/home/newman/isc/ws/bind9/bin/named/named+0x737dad)
    #2 0xe634bc in __libc_csu_init (/home/newman/isc/ws/bind9/bin/named/named+0xe634bc)

==2511090==HINT: if you don't care about these errors you may set ASAN_OPTIONS=detect_odr_violation=0
SUMMARY: AddressSanitizer: odr-violation: global 'dns_lctx' at log.c:69:33
Thread T13 created by T0 here:
    #0 0x7f9e324c5f46 in __interceptor_pthread_create (/lib64/libasan.so.6+0x55f46)
    #1 0xe5ecfa in isc_thread_create /home/newman/isc/ws/bind9/lib/isc/pthreads/thread.c:73
    #2 0xe08c5a in isc_taskmgr_create /home/newman/isc/ws/bind9/lib/isc/task.c:1434
    #3 0x45a841 in create_managers main.c:924
    #4 0x45a841 in setup main.c:1265
    #5 0x45a841 in main main.c:1568
    #6 0x7f9e312541e1 in __libc_start_main (/lib64/libc.so.6+0x281e1)

==2511090==ABORTING

(회사 코드 가져오면 안될 것 같아서 타 사이트에서 동일한 로그 복사해왔다.)

 

 

에러 내용

로그를 자세히 살펴보면 shared library인 sample.so를 로딩하다가 ODR 위반 에러가 발생했다.

 

 

ODR이란?

One Definition Rule.  간단히 말하면 C++의 모든 객체들이 딱 한 번만 정의되어야 한다는 규칙이다. 보통은 링커에 의해서 문제가 감지되지만, 동적 라이브러리가 연관된 문제일 경우 링커는 아무런 감지도 하지 못한다. 

따라서 AddressSanitizer가 실행 초반 과정에서 ODR violations을 감지한다.

 

 

문제가 발생하는 예시 코드를 보면 아래와 같다.

==> odr0.cc <==
int XXX;
int main(){}

==> odr1.cc <==
long long XXX;

==> odr2.cc <==
float XXX;

코드를 살펴보면 각각 다른 파일에서 같은 이름(XXX)의 전역 변수가 선언되어 있다.

이런 경우, odr0.cc 파일에서 int XXX를 읽고 메모리에 register하였는데, odr1.cc에서 같은 이름 XXX 의 변수를 주소에 등록하려고 하면서 에러를 감지하게 된다.

 

 

해결 방법

근본적인 해결 방법은 같은 이름의 전역변수를 사용하지 않는 것, 같은 라이브러리를 중복으로 링킹하지 않는 것이다.

 

일시적인 해결 방법도 있다.

AddressSanitizer에서 ODR위반 에러가 발생할 경우, 무시하도록 환경 설정해놓는 것이다.

프로그램 실행 전에 아래 명령어를 입력하면 된다.

$ export ASAN_OPTIONS=detect_odr_violation=0

 

 

문제 발생 환경 : gcc (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0

stackoverflow 에서 봤을 때 gcc 버전 11 만 이 문제가 발생하는 것 같다.

 

 

 

 

참고:

https://github.com/google/sanitizers/wiki/AddressSanitizerOneDefinitionRuleViolation

https://stackoverflow.com/questions/57390595/asan-detects-odr-violation-of-vtable-of-class-which-is-shared-with-dynamically-l

address sanitizer - How to set ASAN_OPTIONS environment variable in CMake? - Stack Overflow

https://maskray.me/blog/2022-11-13-odr-violation-detection

https://gitlab.isc.org/isc-projects/bind9/-/issues/2449

반응형