How It Works: SQL Server Stack Trace – COMDAT Elimination

Published Feb 05 2022 08:59 AM 762 Views
Microsoft
Moved from: bobsql.com

 

Starting with​​ SQL Server ​​ 2019, SQL Server is​​ built with the​​ COMDAT, ICF linker option​​ enabled, reducing size/space usage. ​​ For example: binn\sqllang.dll is ~12MB smaller when COMDAT is enabled.

 

Use ICF[=iterations] to perform identical COMDAT folding. ​​ /OPT:ICF can merge identical data or functions, it can change the function names that appear in stack traces.​​ 

 

I was looking​​ at a​​ strange​​ stack trace,​​ the caller​​ was not coded to invoke the displayed​​ destination​​ function. ​​ Here is an example:

class​​ C1

{

public:

GetValue()

{

return​​ m_value;

}

 

private:

ULONGLONG m_timeStamp;

ULONGLONG​​ m_value;

};

 

class​​ C2

{

public:

GetId()

{

return​​ m_Id;

}

 

private:

char​​ m_name[8];

ULONGLONG​​ m_Id;

};

 

main()

{

C1​​ localVar;

 printf("%lld\n", c1.GetValue());

}

 

You expect the stack to look like the following when calling​​ C1::GetValue.

C1::GetValue
main

The stack was​​ instead:

C2::GetId()
main

  • My first thought was there​​ must be​​ an​​ override​​ involved

  • My second thought was, is there a memory corruption​​ to a vtable

Neither​​ of these issues​​ are the case.​​ The C1::GetValue and the C2:GetId result in the same assembly.

mov​​ rax, [rcx+8];

 

The linker​​ correctly​​ identified the functions as identical and kept a single​​ copy (C2::GetId) making it look like​​ the call to​​ C1::GetValue was​​ a call​​ to C2:GetId.

 

The assembly tells the full story as both functions are reading 8 bytes from the base offset of the class and returning 8 bytes. ​​ It does not matter that the first 8 bytes of C1 are​​ from the​​ ULONGLONG and the first 8 bytes of C2​​ are from​​ an array of 8 characters. ​​ The memory layout from the base​​ pointer of the object​​ (this, stored in rcx) to the m_value or m_id is identical, allowing the linker​​ to eliminate the duplicate function in the final binary.

 

Caution: When symbolizing SQL server stack traces keep COMDAT elimination in mind when evaluating the validity of the stack.

%3CLINGO-SUB%20id%3D%22lingo-sub-3120975%22%20slang%3D%22en-US%22%3EHow%20It%20Works%3A%20SQL%20Server%20Stack%20Trace%20%E2%80%93%20COMDAT%20Elimination%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-3120975%22%20slang%3D%22en-US%22%3E%3CH6%20id%3D%22toc-hId-1762526047%22%20id%3D%22toc-hId-1762526079%22%3EMoved%20from%3A%20bobsql.com%3C%2FH6%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3EStarting%20with%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3ESQL%20Server%26nbsp%3B%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3E2019%2C%20SQL%20Server%20is%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ebuilt%20with%20the%3C%2FSPAN%3E%20%26nbsp%3B%3CA%20title%3D%22%22%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fcpp%2Fbuild%2Freference%2F%3A~%3Atext%3DUse%2520ICF%2520%255B%2520%253Diterations%255D%2520to%2520perform%2520identical%2520COMDAT%2Cduplicates.%2520The%2520default%2520number%2520of%2520iter%22%20target%3D%22_top%22%20rel%3D%22noopener%20noreferrer%22%3E%3CSPAN%20class%3D%22Hyperlink%22%3ECOMDAT%2C%20ICF%20linker%20option%3C%2FSPAN%3E%3C%2FA%3E%20%26nbsp%3B%3CSPAN%3Eenabled%2C%20reducing%20size%2Fspace%20usage.%26nbsp%3B%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EFor%20example%3A%20binn%5Csqllang.dll%20is%20~12MB%20smaller%20when%20COMDAT%20is%20enabled.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20style%3D%22%20padding-left%20%3A%2030px%3B%20%22%3E%3CSPAN%20class%3D%22T3%22%3EUse%26nbsp%3B%3C%2FSPAN%3E%3CSTRONG%3E%3CSPAN%20class%3D%22T4%22%3EICF%3C%2FSPAN%3E%3C%2FSTRONG%3E%3CSPAN%20class%3D%22T5%22%3E%5B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T6%22%3E%3D%3C%2FSPAN%3E%3CSPAN%20class%3D%22T7%22%3Eiterations%3C%2FSPAN%3E%3CSPAN%20class%3D%22T8%22%3E%5D%20to%20perform%20identical%20COMDAT%20folding.%20%26nbsp%3B%3C%2FSPAN%3E%3CSTRONG%3E%3CSPAN%20class%3D%22T9%22%3E%2FOPT%3AICF%3C%2FSPAN%3E%3CSPAN%20class%3D%22T10%22%3E%26nbsp%3B%3C%2FSPAN%3E%3C%2FSTRONG%3E%3CSPAN%20class%3D%22T11%22%3Ecan%20merge%20identical%20data%20or%20functions%2C%20it%20can%20change%20the%20function%20names%20that%20appear%20in%20stack%20traces%3C%2FSPAN%3E%3CSPAN%20class%3D%22T12%22%3E.%20%26nbsp%3B%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22P2%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3EI%20was%20looking%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eat%20a%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Estrange%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Estack%20trace%2C%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ethe%20caller%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ewas%20not%20coded%20to%20invoke%20the%20displayed%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Edestination%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Efunction.%26nbsp%3B%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EHere%20is%20an%20example%3A%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22P13%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T14%22%3Eclass%3C%2FSPAN%3E%3CSPAN%20class%3D%22T15%22%3E%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T16%22%3EC1%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P17%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3E%7B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P18%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T19%22%3Epublic%3C%2FSPAN%3E%3CSPAN%20class%3D%22T20%22%3E%3A%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P21%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3EGetValue()%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P22%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3E%7B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P23%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T24%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T25%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T26%22%3Ereturn%3C%2FSPAN%3E%3CSPAN%20class%3D%22T27%22%3E%20%26nbsp%3Bm_value%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P28%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3E%7D%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P29%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22P30%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T31%22%3Eprivate%3C%2FSPAN%3E%3CSPAN%20class%3D%22T32%22%3E%3A%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P33%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3EULONGLONG%20m_timeStamp%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P34%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3EULONGLONG%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Em_value%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P35%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3E%7D%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P36%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22P37%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T38%22%3Eclass%3C%2FSPAN%3E%3CSPAN%20class%3D%22T39%22%3E%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T40%22%3EC2%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P41%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3E%7B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P42%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T43%22%3Epublic%3C%2FSPAN%3E%3CSPAN%20class%3D%22T44%22%3E%3A%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P45%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3EGetId()%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P46%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3E%7B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P47%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T48%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T49%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T50%22%3Ereturn%3C%2FSPAN%3E%3CSPAN%20class%3D%22T51%22%3E%20%26nbsp%3Bm_Id%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P52%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3E%7D%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P53%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22P54%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T55%22%3Eprivate%3C%2FSPAN%3E%3CSPAN%20class%3D%22T56%22%3E%3A%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P57%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T58%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T59%22%3Echar%3C%2FSPAN%3E%3CSPAN%20class%3D%22T60%22%3E%20%26nbsp%3Bm_name%5B8%5D%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P61%22%3E%3CFONT%20size%3D%222%22%3E%E2%80%83%3CSPAN%3EULONGLONG%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Em_Id%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P62%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3E%7D%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P63%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22P64%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3Emain()%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P65%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%3E%7B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P66%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T67%22%3E%E2%80%83%3C%2FSPAN%3E%3CSPAN%20class%3D%22T68%22%3EC1%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T69%22%3ElocalVar%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22P71%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T72%22%3E%E2%80%83printf(%3C%2FSPAN%3E%3CSPAN%20class%3D%22T73%22%3E%22%25%3C%2FSPAN%3E%3CSPAN%20class%3D%22T74%22%3Ell%3C%2FSPAN%3E%3CSPAN%20class%3D%22T75%22%3Ed%5Cn%22%3C%2FSPAN%3E%3CSPAN%20class%3D%22T76%22%3E%2C%20c1.GetValue())%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CFONT%20size%3D%222%22%3E%3CSPAN%20class%3D%22T77%22%3E%7D%3C%2FSPAN%3E%3C%2FFONT%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3EYou%20expect%20the%20stack%20to%20look%20like%20the%20following%20when%20calling%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EC1%3A%3AGetValue.%3C%2FSPAN%3E%3CBR%20%2F%3E%3CBR%20%2F%3E%3CSTRONG%3EC1%3A%3AGetValue%3C%2FSTRONG%3E%3CBR%20%2F%3E%3CSPAN%3E%3CSTRONG%3Emain%3C%2FSTRONG%3E%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3EThe%20stack%20was%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Einstead%3A%3C%2FSPAN%3E%3CBR%20%2F%3E%3CBR%20%2F%3E%3CSTRONG%3E%3CSPAN%20class%3D%22T78%22%3EC2%3A%3AGetId()%3C%2FSPAN%3E%3C%2FSTRONG%3E%3CBR%20%2F%3E%3CSPAN%3E%3CSTRONG%3Emain%3C%2FSTRONG%3E%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CUL%20class%3D%22LFO3%22%3E%0A%3CLI%3E%3CP%20class%3D%22P79%22%3E%3CSPAN%3EMy%20first%20thought%20was%20there%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Emust%20be%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ean%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eoverride%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Einvolved%3C%2FSPAN%3E%3C%2FP%3E%0A%3C%2FLI%3E%0A%3CLI%3E%3CP%20class%3D%22P80%22%3E%3CSPAN%3EMy%20second%20thought%20was%2C%20is%20there%20a%20memory%20corruption%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eto%20a%20vtable%3C%2FSPAN%3E%3C%2FP%3E%0A%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3ENeither%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eof%20these%20issues%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eare%20the%20case.%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EThe%20C1%3A%3AGetValue%20and%20the%20C2%3AGetId%20result%20in%20the%20same%20assembly.%3C%2FSPAN%3E%3CBR%20%2F%3E%3CBR%20%2F%3E%3CSPAN%20class%3D%22T81%22%3Emov%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T82%22%3Er%3C%2FSPAN%3E%3CSPAN%20class%3D%22T83%22%3Eax%2C%20%5Brcx%3C%2FSPAN%3E%3CSPAN%20class%3D%22T84%22%3E%2B8%5D%3B%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CFONT%20color%3D%22%23008000%22%3E%3CSPAN%20class%3D%22T85%22%3EThe%20linker%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T86%22%3Ecorrectly%20%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%20class%3D%22T87%22%3Eidentified%20the%20functions%20as%20identical%20and%20kept%20a%20single%20%26nbsp%3B%3C%2FSPAN%3E%3C%2FFONT%3E%3CSPAN%3E%3CFONT%20color%3D%22%23008000%22%3Ecopy%3C%2FFONT%3E%20(C2%3A%3AGetId)%20making%20it%20look%20like%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ethe%20call%20to%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EC1%3A%3AGetValue%20was%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ea%20call%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eto%20C2%3AGetId.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3EThe%20assembly%20tells%20the%20full%20story%20as%20both%20functions%20are%20reading%208%20bytes%20from%20the%20base%20offset%20of%20the%20class%20and%20returning%208%20bytes.%26nbsp%3B%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EIt%20does%20not%20matter%20that%20the%20first%208%20bytes%20of%20C1%20are%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Efrom%20the%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EULONGLONG%20and%20the%20first%208%20bytes%20of%20C2%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eare%20from%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Ean%20array%20of%208%20characters.%26nbsp%3B%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3EThe%20memory%20layout%20from%20the%20base%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Epointer%20of%20the%20object%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3E(this%2C%20stored%20in%20rcx)%20to%20the%20m_value%20or%20m_id%20is%20identical%2C%20allowing%20the%20linker%3C%2FSPAN%3E%20%26nbsp%3B%3CSPAN%3Eto%20eliminate%20the%20duplicate%20function%20in%20the%20final%20binary.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22Normal%22%3E%3CSPAN%3E%3CSTRONG%3ECaution%3C%2FSTRONG%3E%3A%20When%20symbolizing%20SQL%20server%20stack%20traces%20keep%20COMDAT%20elimination%20in%20mind%20when%20evaluating%20the%20validity%20of%20the%20stack.%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-3120975%22%20slang%3D%22en-US%22%3E%3CP%3EHow%20compiling%20with%20COMDAT%20shrinks%20the%20SQL%20footprint.%3C%2FP%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-3120975%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EBobSQL%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E
Co-Authors
Version history
Last update:
‎Feb 05 2022 08:59 AM
Updated by: