<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>http://junhoahn.kr/noriwiki/index.php?action=history&amp;feed=atom&amp;title=AddressSanitizer_Optimization</id>
	<title>AddressSanitizer Optimization - 편집 역사</title>
	<link rel="self" type="application/atom+xml" href="http://junhoahn.kr/noriwiki/index.php?action=history&amp;feed=atom&amp;title=AddressSanitizer_Optimization"/>
	<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=AddressSanitizer_Optimization&amp;action=history"/>
	<updated>2026-05-16T16:15:02Z</updated>
	<subtitle>이 문서의 편집 역사</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=AddressSanitizer_Optimization&amp;diff=7091&amp;oldid=prev</id>
		<title>Ahn9807: 새 문서: 분류:AddressSanitizer 분류:Program Analysis 분류:Optimization  == 개요 == 이 문서는 AddressSanitizer(ASan)의 실행 오버헤드를 줄이기 위한 다양한 최적화 기법들을 정리한 문서이다.  ASan은 heap, stack, global object에 대한 out-of-bounds access와 heap use-after-free를 효과적으로 검출하지만, 각 memory access마다 shadow memory를 확인하는 check를 삽입하므로 실행 시간 오버헤드가 크다.   == Remo...</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=AddressSanitizer_Optimization&amp;diff=7091&amp;oldid=prev"/>
		<updated>2026-03-23T07:11:34Z</updated>

		<summary type="html">&lt;p&gt;새 문서: &lt;a href=&quot;/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:AddressSanitizer&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;분류:AddressSanitizer (없는 문서)&quot;&gt;분류:AddressSanitizer&lt;/a&gt; &lt;a href=&quot;/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:Program_Analysis&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;분류:Program Analysis (없는 문서)&quot;&gt;분류:Program Analysis&lt;/a&gt; &lt;a href=&quot;/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:Optimization&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;분류:Optimization (없는 문서)&quot;&gt;분류:Optimization&lt;/a&gt;  == 개요 == 이 문서는 AddressSanitizer(ASan)의 실행 오버헤드를 줄이기 위한 다양한 최적화 기법들을 정리한 문서이다.  ASan은 heap, stack, global object에 대한 out-of-bounds access와 heap use-after-free를 효과적으로 검출하지만, 각 memory access마다 shadow memory를 확인하는 check를 삽입하므로 실행 시간 오버헤드가 크다.   == Remo...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;새 문서&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[분류:AddressSanitizer]]&lt;br /&gt;
[[분류:Program Analysis]]&lt;br /&gt;
[[분류:Optimization]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
이 문서는 AddressSanitizer(ASan)의 실행 오버헤드를 줄이기 위한 다양한 최적화 기법들을 정리한 문서이다.&lt;br /&gt;
&lt;br /&gt;
ASan은 heap, stack, global object에 대한 out-of-bounds access와 heap use-after-free를 효과적으로 검출하지만, 각 memory access마다 shadow memory를 확인하는 check를 삽입하므로 실행 시간 오버헤드가 크다. &lt;br /&gt;
&lt;br /&gt;
== Removing Unsatisfiable Checks ==&lt;br /&gt;
이 범주는 프로그램 의미론 상 절대로 실패할 수 없는 ASan check를 제거하는 방식이다.&lt;br /&gt;
&lt;br /&gt;
ASan check는 기본적으로 어떤 주소 &amp;lt;math&amp;gt;addr&amp;lt;/math&amp;gt;에 접근하기 전에 그 주소에 대응되는 shadow byte를 확인한다. 그런데 접근 대상 object의 크기와 offset, access size가 모두 정적으로 계산 가능하고, 모든 경로에서 범위 내 접근임이 보장되면 shadow를 확인할 이유가 없다. 이런 check는 남겨 두어도 항상 통과하기만 하므로 순수 오버헤드가 된다.&lt;br /&gt;
&lt;br /&gt;
일반적으로 다음 조건이 모든 실행 경로에서 성립하면 제거 가능하다.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;offset \ge 0&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;offset + access\_size \le object\_size&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
예를 들어 다음 코드는 접근 위치가 완전히 정적으로 결정된다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
int foo() {&lt;br /&gt;
    char buf[20];&lt;br /&gt;
    buf[10] = 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
이 최적화는 특히 다음과 같은 경우에 잘 적용된다.&lt;br /&gt;
&lt;br /&gt;
* stack object에 대한 상수 인덱스 접근&lt;br /&gt;
* global array에 대한 정적 인덱스 접근&lt;br /&gt;
* 구조체 필드 접근처럼 layout이 compile time에 확정되는 경우&lt;br /&gt;
* inlining과 constant propagation 이후 값이 상수로 환원되는 경우&lt;br /&gt;
&lt;br /&gt;
반대로 다음과 같은 경우는 조심해야 한다.&lt;br /&gt;
&lt;br /&gt;
* pointer arithmetic 결과가 외부 입력에 의존하는 경우&lt;br /&gt;
* heap object 크기가 정적으로 불명확한 경우&lt;br /&gt;
* alias를 통해 실제 object 경계가 바뀔 수 있는 경우&lt;br /&gt;
* signed/unsigned cast 때문에 정적 범위 추론이 깨지는 경우&lt;br /&gt;
&lt;br /&gt;
=== LLVM Backward tracing ===&lt;br /&gt;
실제 코드에서는 인덱스가 항상 상수로 직접 나타나지 않는다. 따라서 단순히 &amp;#039;&amp;#039;배열 첨자에 상수가 들어갔는가&amp;#039;&amp;#039;만 보면 많은 기회를 놓친다. 이를 보완하는 방식이 backward tracing이다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
int foo() {&lt;br /&gt;
    char buf[20];&lt;br /&gt;
    unsigned int i = 10;&lt;br /&gt;
    i++;&lt;br /&gt;
    buf[i] = 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
표면적으로는 &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt;가 변수이므로 동적 접근처럼 보인다. 하지만 SSA 기반 IR에서 보면 최종 값은 &amp;lt;math&amp;gt;11&amp;lt;/math&amp;gt;로 환원 가능하다. 즉, 컴파일러가 정의-사용 사슬을 거슬러 올라가며 값을 역추적하면 이 접근 역시 항상 안전하다고 판단할 수 있다.&lt;br /&gt;
&lt;br /&gt;
이 과정에서 주로 필요한 분석은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* SSA 기반 value propagation&lt;br /&gt;
* constant folding&lt;br /&gt;
* backward slicing&lt;br /&gt;
* simple range analysis&lt;br /&gt;
* dead path pruning&lt;br /&gt;
&lt;br /&gt;
예를 들어 다음과 같은 패턴도 같은 부류이다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
int foo() {&lt;br /&gt;
    int idx = 4;&lt;br /&gt;
    int j = idx * 2;&lt;br /&gt;
    char buf[16];&lt;br /&gt;
    buf[j] = 1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
여기서 &amp;lt;code&amp;gt;j = 8&amp;lt;/code&amp;gt;로 환원되므로 check를 제거할 수 있다.&lt;br /&gt;
&lt;br /&gt;
== Removing Recurring Checks ==&lt;br /&gt;
이 범주는 서로 다른 위치에 삽입된 ASan check들이 논리적으로 같은 안전성 조건을 중복해서 확인하는 경우, 뒤의 check를 제거하는 방식이다.&lt;br /&gt;
&lt;br /&gt;
핵심 질문은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* 이 check가 검사하는 주소는 이전에 검사한 주소와 같은가&lt;br /&gt;
* 이전 check가 더 넓은 범위를 이미 검사했는가&lt;br /&gt;
* control-flow 상 이전 check 이후에 대상 pointer나 object 상태가 바뀌지 않는가&lt;br /&gt;
&lt;br /&gt;
가장 단순한 예시는 같은 pointer를 짧은 구간 안에서 반복 접근하는 경우이다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
int *p;&lt;br /&gt;
ASan(p);&lt;br /&gt;
&lt;br /&gt;
if (*p == 0) {&lt;br /&gt;
    ASan(p);&lt;br /&gt;
    *p = 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
두 번째 check는 첫 번째 check와 완전히 같은 대상에 대해 같은 조건을 다시 확인한다. 첫 번째 check 이후에 &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;가 바뀌지 않고, free가 발생하지 않고, 더 좁아진 memory object로 바뀌지도 않았다면 두 번째 check는 redundant하다.&lt;br /&gt;
&lt;br /&gt;
보다 일반적으로는 다음 조건이 필요하다.&lt;br /&gt;
&lt;br /&gt;
* 두 접근이 must-alias 관계&lt;br /&gt;
* 앞선 check가 동일하거나 더 넓은 범위를 검사&lt;br /&gt;
* 앞선 check가 뒤 check를 dominance 또는 post-dominance 관계로 덮음&lt;br /&gt;
* 두 check 사이에 pointer/object 상태를 깨뜨릴 수 있는 연산이 없음&lt;br /&gt;
&lt;br /&gt;
예를 들어 폭이 다른 access에도 같은 논리가 적용될 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
char *p;&lt;br /&gt;
ASan_8B(p);&lt;br /&gt;
x = *(long long *)p;&lt;br /&gt;
ASan_1B(p);&lt;br /&gt;
y = *p;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
앞의 8-byte check가 성공했다면 그 범위 안에 포함되는 1-byte access를 다시 검사할 필요가 없는 경우가 있다. 물론 이는 두 access가 같은 object 내에 있고 중간에 상태 변화가 없을 때만 성립한다.&lt;br /&gt;
&lt;br /&gt;
이 최적화는 특히 다음 상황에서 효과적이다.&lt;br /&gt;
&lt;br /&gt;
* 같은 필드를 여러 번 load/store하는 코드&lt;br /&gt;
* optimizer가 값을 레지스터로 들고 있지 못해 메모리 재접근이 반복되는 경우&lt;br /&gt;
* C++ method chain이나 inline expansion으로 같은 base pointer 검사 코드가 복제되는 경우&lt;br /&gt;
* sanitizer slow path를 피하기 위해 원래부터 보수적으로 많은 check가 들어간 경우&lt;br /&gt;
&lt;br /&gt;
하지만 제거가 위험한 경우도 많다.&lt;br /&gt;
&lt;br /&gt;
* 함수 호출이 사이에 있으면 callee가 free를 수행할 수 있다&lt;br /&gt;
* unknown store가 object metadata를 바꿀 수 있다&lt;br /&gt;
* pointer recast나 integer-to-pointer 변환이 있으면 alias 보장이 약해진다&lt;br /&gt;
* signal, longjmp, exceptional control flow 등 비정상 흐름이 있으면 보수적으로 남겨야 한다&lt;br /&gt;
&lt;br /&gt;
따라서 필요한 분석은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* alias analysis&lt;br /&gt;
* dominance/post-dominance analysis&lt;br /&gt;
* escape analysis&lt;br /&gt;
* interprocedural mod/ref analysis&lt;br /&gt;
* call effect summary&lt;br /&gt;
&lt;br /&gt;
이 계열의 최적화는 check 수를 줄이는 효과가 직접적이며, 특히 대형 C/C++ 프로그램에서 같은 base pointer에 대한 repeated field access가 많기 때문에 체감 효과가 크다.&amp;lt;ref&amp;gt;SANRAZOR: Reducing Redundant Sanitizer Checks in C/C++ Programs. OSDI 2021.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Debloating Address Sanitizer. USENIX Security 2022.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Optimizing Neighbor Checks ==&lt;br /&gt;
이 범주는 인접한 memory access들이 shadow memory 수준에서는 거의 같은 검사를 수행한다는 점을 이용해, 여러 check를 병합하거나 일부를 제거하는 방식이다.&lt;br /&gt;
&lt;br /&gt;
ASan은 보통 주소를 8:1 shadow mapping으로 변환해 shadow byte를 읽는다. 따라서 주소가 서로 가깝다면 결국 같은 shadow byte 또는 인접한 몇 개의 shadow byte만 확인하게 된다. 이때 source-level access는 여러 개여도 shadow-level 정보는 거의 중복일 수 있다.&lt;br /&gt;
&lt;br /&gt;
=== Mergeable Neighbor Checks ===&lt;br /&gt;
서로 인접한 access가 같은 shadow 영역에 속하면, 여러 개의 ASan check를 하나의 묶음 검사로 합칠 수 있다.&lt;br /&gt;
&lt;br /&gt;
예를 들어 다음과 같은 구조체 field access를 생각할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
struct S {&lt;br /&gt;
    int a;&lt;br /&gt;
    int b;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void foo(struct S *ptr) {&lt;br /&gt;
    ptr-&amp;gt;a = 1;&lt;br /&gt;
    ptr-&amp;gt;b = 2;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
일반적인 instrumentation은 다음처럼 각 access마다 독립 check를 넣는다.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;ASan(ptr-&amp;gt;a)&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ASan(ptr-&amp;gt;b)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
하지만 &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;와 &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt;가 메모리상 연속해 있고 같은 shadow block 또는 매우 가까운 shadow block을 사용한다면, 두 access를 위해 shadow를 두 번 읽는 것은 낭비다. 이때 다음과 같은 병합이 가능하다.&lt;br /&gt;
&lt;br /&gt;
* 먼저 더 큰 범위의 shadow 상태를 한 번 확인&lt;br /&gt;
* fast path에서는 두 access를 모두 safe로 간주&lt;br /&gt;
* slow path에서만 원래의 세밀한 개별 check로 분기&lt;br /&gt;
&lt;br /&gt;
즉, 논리는 &amp;#039;&amp;#039;넓게 한 번 보고, 이상이 있을 때만 자세히 본다&amp;#039;&amp;#039;이다.&lt;br /&gt;
&lt;br /&gt;
이 방식은 다음 이점을 준다.&lt;br /&gt;
&lt;br /&gt;
* shadow load 수 감소&lt;br /&gt;
* conditional branch 수 감소&lt;br /&gt;
* instruction cache pressure 감소&lt;br /&gt;
* 같은 base address 계산의 중복 감소&lt;br /&gt;
&lt;br /&gt;
다만 병합 가능한지는 다음에 좌우된다.&lt;br /&gt;
&lt;br /&gt;
* 두 access의 상대 위치가 정적으로 알려져 있는가&lt;br /&gt;
* 병합한 범위가 false negative 없이 원래 두 check를 커버하는가&lt;br /&gt;
* alignment와 access width 차이 때문에 coarse check가 지나치게 커지지 않는가&lt;br /&gt;
&lt;br /&gt;
=== Removable Neighbor Checks ===&lt;br /&gt;
인접 access 중 일부는 주변 access만으로도 오류가 검출되므로 완전히 제거할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
ptr-&amp;gt;a = ...;&lt;br /&gt;
ptr-&amp;gt;b = ...;&lt;br /&gt;
ptr-&amp;gt;c = ...;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
여기서 &amp;lt;code&amp;gt;ptr-&amp;gt;b&amp;lt;/code&amp;gt;가 가리키는 위치에서 위반이 발생한다면, 그 위반이 구조상 반드시 &amp;lt;code&amp;gt;ptr-&amp;gt;a&amp;lt;/code&amp;gt; 또는 &amp;lt;code&amp;gt;ptr-&amp;gt;c&amp;lt;/code&amp;gt;의 check에서도 드러나는 경우가 있다. 이 경우 &amp;lt;code&amp;gt;ptr-&amp;gt;b&amp;lt;/code&amp;gt; check는 새로운 오류 검출 능력을 추가하지 않는다.&lt;br /&gt;
&lt;br /&gt;
이 최적화는 직관적으로는 애매해 보이지만, 핵심은 &amp;#039;&amp;#039;이 access가 독립적인 정보량을 제공하는가&amp;#039;&amp;#039;이다. 만약 가운데 access가 주변 access들의 union으로 커버되는 memory safety boundary 안에 있다면 중간 check는 제거 가능하다.&lt;br /&gt;
&lt;br /&gt;
대표적으로 다음 상황에서 기회가 생긴다.&lt;br /&gt;
&lt;br /&gt;
* packed struct field access&lt;br /&gt;
* compiler가 분해한 memcpy/memset의 이웃 store들&lt;br /&gt;
* vectorized access가 scalar access로 다시 쪼개진 경우&lt;br /&gt;
* small-width field들이 연달아 접근되는 경우&lt;br /&gt;
&lt;br /&gt;
이 범주의 최적화는 correctness 조건이 섬세하므로 보통 보수적으로 적용한다. 잘못 적용하면 false negative가 생기기 때문이다.&lt;br /&gt;
&lt;br /&gt;
== Optimizing Checks in Loops ==&lt;br /&gt;
loop 내부 check는 ASan overhead의 핵심 원인 중 하나다. 루프는 본질적으로 같은 패턴의 access를 대량 반복하므로, per-iteration instrumentation은 비용이 눈덩이처럼 커진다.&lt;br /&gt;
&lt;br /&gt;
이 범주의 핵심은 다음 두 가지다.&lt;br /&gt;
&lt;br /&gt;
* loop를 도는 동안 변하지 않는 것은 밖으로 빼기&lt;br /&gt;
* 반복되는 접근을 chunk 단위로 묶기&lt;br /&gt;
&lt;br /&gt;
=== Loop-invariant Checks ===&lt;br /&gt;
루프 안에서 같은 주소를 계속 접근한다면 매 iteration마다 ASan check를 할 필요가 없다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    ASan(ptr);&lt;br /&gt;
    *ptr = i;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
이 코드는 실제로는 같은 위치 &amp;lt;code&amp;gt;ptr&amp;lt;/code&amp;gt;를 반복해서 쓴다. 따라서 다음처럼 바꿀 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
ASan(ptr);&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    *ptr = i;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
이 최적화는 일반 loop-invariant code motion과 유사하지만, 중요한 차이가 있다. 원래 store 자체는 side effect 때문에 루프 밖으로 뺄 수 없더라도, &amp;#039;&amp;#039;check&amp;#039;&amp;#039;는 뺄 수 있다는 점이다.&lt;br /&gt;
&lt;br /&gt;
적용 조건은 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* 루프 반복 동안 대상 주소가 변하지 않음&lt;br /&gt;
* 루프 안에서 free/unmap/reallocation 같은 상태 변화가 없음&lt;br /&gt;
* signal-like 비정상 흐름으로 memory validity가 바뀌지 않음&lt;br /&gt;
* hoisted check가 루프 내 모든 access를 sound하게 대표함&lt;br /&gt;
&lt;br /&gt;
이 최적화는 특히 작은 loop body에서 효과가 크다. 원래 check가 차지하던 비중이 커서, hoisting만으로도 branch와 shadow access 수가 크게 줄어든다.&lt;br /&gt;
&lt;br /&gt;
=== Grouped Checks in Loops ===&lt;br /&gt;
loop가 연속된 주소를 차례로 접근한다면, 각 iteration마다 check하는 대신 몇 개 iteration을 묶어서 검사할 수 있다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=c&amp;gt;&lt;br /&gt;
for (int i = 0; i &amp;lt; N; i++) {&lt;br /&gt;
    ASan(ptr + i);&lt;br /&gt;
    ptr[i] = i;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
이 경우 &amp;lt;code&amp;gt;ptr + i&amp;lt;/code&amp;gt;는 연속 증가 주소다. ASan shadow mapping의 granularity를 생각하면, 여러 iteration이 같은 shadow chunk를 공유할 수 있다. 따라서 매번 check하는 대신 다음처럼 바꿀 수 있다.&lt;br /&gt;
&lt;br /&gt;
* 현재 iteration이 속한 shadow chunk를 확인&lt;br /&gt;
* 그 chunk 범위 안에서는 추가 check 생략&lt;br /&gt;
* chunk 경계를 넘을 때만 다시 검사&lt;br /&gt;
&lt;br /&gt;
즉, &amp;#039;&amp;#039;per-access check&amp;#039;&amp;#039;를 &amp;#039;&amp;#039;per-chunk check&amp;#039;&amp;#039;로 바꾸는 것이다.&lt;br /&gt;
&lt;br /&gt;
이 방식이 성립하려면 보통 다음이 필요하다.&lt;br /&gt;
&lt;br /&gt;
* contiguous access 또는 고정 stride access&lt;br /&gt;
* induction variable이 명확함&lt;br /&gt;
* access width가 일정하거나 상한이 추론 가능함&lt;br /&gt;
* redzone boundary를 정확히 고려할 수 있음&lt;br /&gt;
&lt;br /&gt;
예를 들어 &amp;lt;math&amp;gt;8:1&amp;lt;/math&amp;gt; shadow mapping에서 1-byte store가 연속해서 8번 일어나면, 이 8개의 access는 같은 shadow byte 상태와 연관될 수 있다. 이때 매번 shadow를 읽지 않고 한 번만 읽어도 충분한 경우가 많다.&lt;br /&gt;
&lt;br /&gt;
실제 구현 시 고려해야 할 문제는 다음과 같다.&lt;br /&gt;
&lt;br /&gt;
* 마지막 iteration에서 chunk를 부분적으로만 쓰는 경우&lt;br /&gt;
* loop peeling/unrolling 후 원래 induction 관계가 바뀌는 경우&lt;br /&gt;
* vectorized loop와 scalar remainder loop를 별도로 처리해야 하는 경우&lt;br /&gt;
* stride가 1이 아니라 2, 4, 8인 경우 coverage 계산이 달라지는 경우&lt;br /&gt;
&lt;br /&gt;
이 범주의 최적화는 대규모 array processing, codec, parser, numeric kernel처럼 loop가 긴 코드에서 특히 효과적이다.&amp;lt;ref&amp;gt;Debloating Address Sanitizer. USENIX Security 2022.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Redesigning ASAN Checks ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
</feed>