ASan determines the stack layout from alloca instructions. Since
arguments marked as "byval" do not have an explicit alloca instruction, ASan
does not produce red zones for them. This commit produces an explicit alloca
instruction and copies the byval argument into the allocated memory so that red
zones are produced.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2543 ↗ | (On Diff #104548) | Not sure if it matters here, but this is usually done with BasicBlock::getFirstInsertionPt() |
2545 ↗ | (On Diff #104548) | Local variables start with a capital letter. |
2553 ↗ | (On Diff #104548) | Better call it something like arg.getName() + ".byval", or whatever looks good in ASan error report. Please also add compiler-rt test for ASan detecting overflow of a byval arg. |
2557 ↗ | (On Diff #104548) | F.getParent() |
test/Instrumentation/AddressSanitizer/stack-poisoning-byval-args.ll | ||
16 ↗ | (On Diff #104548) | Please make this test a little stronger: check that bar() gets a pointer in the combined alloca, not the original %a. Check that memcpy is from %a. Also the size of alloca (96) is irrelevant and checking it can only make the test more brittle. |
Can I add compiler-rt tests to this revision or do I need to open a separate one for that?
You can if you use git-monorepo or plain svn. AFAIK it can not be done with multirepo-git. Anyway, could be easier to start a separate revision.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2544 ↗ | (On Diff #104666) | You can avoid the cast by using this constructor: http://llvm-cs.pcc.me.uk/include/llvm/IR/IRBuilder.h#703 IRBuilder(BB, BB.getFirstInsertionPt()); |
2551 ↗ | (On Diff #104666) | Check what happens if the arg has no name. AFAIK it can be referenced as %0 (%1, etc) in the function body in that case, but getName() would return nullptr. |
2557 ↗ | (On Diff #104666) | Check what happens when byval argument has not explicit align attribute. unsigned ArgAlign = FArg.getParamAlignment(); if (ArgAlign == 0) { Type *EltType = A->getType()->getPointerElementType(); ArgAlign = DL.getABITypeAlignment(EltType); } |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2541 ↗ | (On Diff #104666) | Should we poison original location? |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2541 ↗ | (On Diff #104666) | I'm thinking not, because it is not adjacent to any alloca - it's just a random location on the stack at this point. |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2541 ↗ | (On Diff #104666) | But access to that location is a sign of a bug |
Right, but then why don't we add 5 new allocas in each function, poison them and never use them. Access to those would also be a bug.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2550 ↗ | (On Diff #104732) | It looks like single-line if() usually do not use braces, at least in this source file. |
2554 ↗ | (On Diff #104732) | Arg.hasName |
2555 ↗ | (On Diff #104732) | Use Arg.getArgNo() |
test/Instrumentation/AddressSanitizer/stack-poisoning-byval-args.ll | ||
8 ↗ | (On Diff #104732) | Please add tests for unnamed arg and for arg w/o align attribute. |
16 ↗ | (On Diff #104732) | Check alignment here and in the alloca instruction |
This is not the same. We already have original space allocate on the stack, and we know that this should not be accessed.
We can investigate usefulness of this later.
You are right. Still, this is unlikely to ever catch anything, and it increases code size and adds some complexity to the instrumentation pass. I don't mind either way.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
194 ↗ | (On Diff #104732) | Probably we need compile time flag disabled by default |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
194 ↗ | (On Diff #104732) | A flag would not hurt, but I think it should be on by default. |
Remove ArgNum counter. Add compile-time flag to disable redzones for byval arguments. Check memcpy alignment in test case. Add test case for unnamed argument with no explicit alignment.
@eugenis You mentioned the test case should also check alignment in the alloca, but it looks like the alignment there is specified by the default "-asan-realign-stack" option independent of the argument alignment.
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
2557 ↗ | (On Diff #105470) | This looks suspicious. You construct a temporary StringRef to a temporary std::string. The const reference extends the lifetime of StringRef, but I don't think it does anything to the std::string it points to, and StringRef does not own the buffer. It's better to build the alloca name in a local std::string variable. |
llvm/test/Instrumentation/AddressSanitizer/stack-poisoning-byval-args.ll | ||
28 ↗ | (On Diff #105470) | I think you need "target datalayout" and "target triple" statements in the test, because type alignment is target-dependent. |
Replace StringRef usage with std::string. Add target datalayout and target triple lines to test. Add alignment check in alloca.
I've reverted this and the other change in r307345, see the commit message for the (incomplete) list of failing bots.
@vitalybuka If this looks good, could you land this today since I don't yet have commit access?
I usually reopen reviews for reverted patches.
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
14 ↗ | (On Diff #106530) | I suspect not all new headers are rely needed |