Canaryの大きさを指定できるようにする

	clang 7.0, LLVM 7.0を拡張
	とりあえずgcc attributeみたいな感じで指定できるようにしたい
		イメージ `char __attribute__((multicanary_size=(256))) hoge[256];`
	もしくは、行列もしくは多次元配列の大きさだけ指定して推定させる
		`int __attribute__((multicanary_sizefor=(2, 3))) huga[2][3];`
	完全にコンパイラにやらせる

	そもそも__attribute__ってC系言語限定なのでは, rustにも似たような機能があった気がするが、[- そもそも関数に対して適用するものだし](variable attributesなるものを発見した)、LLVMに変数宣言ごとの属性を伝えるにはどうすればいいのだろう
	LLVM IRの後ろの方に`attributes #0`が存在している
	方法
		clang=front-endがMultiCanaryのAllocaInstを作ってサイズを設定して、LLVMがそれに従う
			なんか微妙
			実証は楽?そうでもない?
		clangからはCanaryのサイズだけ伝わるようにして、LLVMで完結させる→こっちを利用
			parameter attributes
			LLVM IRの構文を拡張して、その拡張をclangから使えるようにする必要がある
	[How to add an attribute https://clang.llvm.org/docs/InternalsManual.html#how-to-add-an-attribute] ドンピシャなガイドがある
		IgnoredAttrは他のコンパイラでは実装されてるけどclangでは無視したい、といったときに使う
			>An attribute that inherits from IgnoredAttr is parsed, but will generate an ignored attribute diagnostic when used, which may be useful when an attribute is supported by another vendor but not supported by clang.
			code:Attr.rd
			 /// An ignored attribute, which we parse but discard with no checking.
   	class IgnoredAttr : Attr {
			another vendor = CUDA とか
	LLVMの拡張
		[- Attributes→parameter attributes, function attributes, global attributes]
		IRのlexer/parserにkw_multicanry_sizeを追加
		allocainstの構文を拡張
		MultiCanary Passからそれを利用してIRを書き換える
	clangの拡張
		__attribute__構文に追加
		hasAttrを使ってDecl?に落とし込む
		CGDecl.cpp:EmitAutoVarAllocaでgetAttrしてからAllocaInstにセット
		あとはLLVMにおまかせ
	なぜかMultiCanarySizeに値がセットできていない、`clang -emit-llvm`で`multicanary_size`を含んだIRが表示されない
		[https://gyazo.com/d215c67c11c06ee6105d1083c34e7966]
		CreateTempAllocaWithoutCastにMultiCanarySizeを渡し忘れていた…
	バッファの型が`[256 x i32]`であるのに対してCanaryは`i8*`(=`i32`, `i64`)なのでそのまま比較できない
	`alloca i8*, i32 32` vs `alloca [32 x i8*]`
	GEPは`i8*`などのPointer Typeを要素にもつ配列には使えない…?
		Instructions.cpp:1433
	代わりに`ptrtoint`で

	entryブロック内に(multicanary_size指定のある)allocaInstが2つあると、片方がsplitされて別のBasicBlockに移る→isKnownSentinelで落ちる
	新しいブロックに移される=後からまたループで参照されることが保証されているので、はじめのallocaInstの処理が終わればcontinueしてしまえばよい

	IRBuilderにはBBをまたいで後ろに挿入する癖がある?かと思ったら前にも入れるっぽいしよくわからん
code:MultiCanary.cpp
  // ↓のようになるのでIRBuilder<> B(AI)は使えない
  //   %MultiCanaryLoad5 = load i8*, i8* addrspace(257)* inttoptr (i32 40 to i8* addrspace(257)*)
  //   %MultiCanaryAlloca6 = alloca i8*, i32 32
  //
  // ; <label>:0:                                      ; preds = %MultiCanaryStoreLoopHead
  //   br label %MultiCanaryStore
  //
  // IRBuilder<> BBB(BB.getContext());
  // BBB.CreateBr(StoreBB);

	CreateBrは動いたり動かなかったりする
		BranchInst::Createを使う

	でも落ちる
	code:SelectionDAGBuilder.cpp
      AllocaInst *CanarySlot = cast<AllocaInst>(I.getArgOperand(1));
      AllocaInst *BufferSlot = cast<AllocaInst>(I.getArgOperand(2));
  
      int CanaryFI = FuncInfo.StaticAllocaMap[CanarySlot];
      int BufferFI = FuncInfo.StaticAllocaMap[BufferSlot];
      errs() << CanaryFI << " for " << BufferFI << "\n";
      MFI.setMultiCanaryIndex(BufferFI, CanaryFI);
  
      SDValue CanaryFIN = DAG.getFrameIndex(CanaryFI, PtrTy);
  
      // Store the canary onto the stack.
      Res = DAG.getStore(
          Chain, sdl, Src, CanaryFIN,
          MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), CanaryFI),
          /* Alignment = */ 0, MachineMemOperand::MOVolatile);
      CanarySlot->dump();
      BufferSlot->dump();
      errs() << FuncInfo.StaticAllocaMap.count(CanarySlot) << "\n";
      errs() << FuncInfo.StaticAllocaMap.count(BufferSlot) << "\n";
      if (FuncInfo.StaticAllocaMap.find(CanarySlot) == FuncInfo.StaticAllocaMap.end()) {
        errs() << "CanarySlot not found in StaticAllocaMap\n";
      }
      if (FuncInfo.StaticAllocaMap.find(BufferSlot) == FuncInfo.StaticAllocaMap.end()) {
        errs() << "BufferSlot not found in StaticAllocaMap\n";
      }
      Res->dump();
      setValue(&I, Res);
	code:attr.c
	 #include <stdio.h>
  
  int main(int argc, char **argv) {
    __attribute__((multicanary_size(16))) int hoge[256];
    __attribute__((multicanary_size(128))) char huga[16];
    __attribute__((multicanary_size(256))) char fuga[24];
 	  return 0;
  }
	code:attr_opt_llc.txt
  0 for 0 ; [MultiCanaryAllocaのStaticAllocaMap] for [BufferのStaticAllocaMap], Idx=0のCanaryをIdx=0のBufferに割り当てている???
    %MultiCanaryAlloca15 = alloca i8*, i32 32 ; CanaryAI
    %fuga = alloca [24 x i8], align 16, multicanary_size 256 ; BufferAI
  1
  1
  t5: ch = store<(volatile store 8 into %fixed-stack.0)> t0, t2, FrameIndex:i64<0>, undef:i64
  # *** IR Dump After X86 DAG->DAG Instruction Selection ***:
  # Machine code for function main: IsSSA, TracksLiveness
  Frame Objects:
    fi#0: size=8, align=8, at location [SP+8]
    fi#1: size=4, align=4, at location [SP+8]
    fi#2: size=8, align=8, at location [SP+8]
    fi#3: size=4, align=4, at location [SP+8]
    fi#4: size=8, align=8, at location [SP+8]
    fi#5: size=8, align=8, at location [SP+8]
    fi#6: size=16, align=8, at location [SP+8]
    fi#7: size=1024, align=16, at location [SP+8] ; %hugaのみ確保されている
    fi#8: variable sized, align=1, at location [SP+8]
    fi#9: variable sized, align=1, at location [SP+8]
  ...
    ; MI->dump()させた↓
    %44:gr64 = MOV64rm %2:gr64, 1, $noreg, 0, $noreg :: (volatile load 8 from %ir.MultiCanaryAlloca8)
  llc: /home/sei0o/Devs/llvm/lib/CodeGen/LiveVariables.cpp:134: void llvm::LiveVariables::HandleVirtRegUse(unsigned int, llvm::MachineBasicBlock*, llvm::MachineInstr&): Assertion `MRI->getVRegDef(reg) && "Register use before def!"' failed.
  Stack dump:
	`MultiCanaryAlloca8`を宣言する前にロードしている
	直前のMIRにそもそもMulCanaryAlloca / `%ir.MultiCanaryAlloca8`が存在せず、SelectionDAGBuilderの後で消滅している
	はて??
	`attr.c`をいろいろ変化させてみるも同じ
	StaticAllocaMapに同じ値(`0`)がセットさせているのがよくなさそう
	代入しているところを見てみる
	code:FunctionLoweringInfo.cpp
	           if (Iter != CatchObjects.end() && TLI->needsFixedCatchObjects()) { ; Windows + EH???
              FrameIndex = MF->getFrameInfo().CreateFixedObject(
                  TySize, 0, /*Immutable=*/false, /*isAliased=*/true);
              MF->getFrameInfo().setObjectAlignment(FrameIndex, Align);
            } else { ; こちら側を通る
              FrameIndex =
                  MF->getFrameInfo().CreateStackObject(TySize, Align, false, AI);
            }
  
            StaticAllocaMap[AI] = FrameIndex;
	`CreateFixedObject`ではNumFixedObjectsが更新されている
	`CreateStackObject`では更新されている感じはない
	`MachineFrameInfo::setMultiCanaryIndex`あたりは`NumFixedObjects`に依存している
	しかし他のメンバ変数・関数もそうなので関係なさそう
	というかMultiCanaryはそこを通っていない?→そんなことなかった
	いろいろ探してみると、FunctionLoweringInfo.cpp:132で`MultiCanaryAlloca8`だけStatic扱いされてない(???)
		code:gdb
		 gdb-peda$ p AI->isStaticAlloca()
   $41 = 0x0
   gdb-peda$ p AI->getName()
   $42 = {
     static npos = 0xffffffffffffffff, 
     Data = 0x55555c425550 "MultiCanaryAlloca8", 
     Length = 0x12
   }
 code:Instructions.cpp
  /// isStaticAlloca - Return true if this alloca is in the entry block of the
  /// function and is a constant size.  If so, the code generator will fold it
  /// into the prolog/epilog code, so it is basically free.
  bool AllocaInst::isStaticAlloca() const {
	ここの`free`は計算量がO(1)って意味?
	if this alloca is in the entry block
	<span title='There is no note that matches this link.' class='invalid-link'>  <span class='invalid-link-brackets'>[[</span>  if this alloca is in the entry block  <span class='invalid-link-brackets'>]]</span></span>
	[** if this alloca is in the entry block]
	[**** if this alloca is in the entry block] マジかよ〜
	BasicBlock分けてCanary設置済みかそうでないかを識別するアプローチはダメってことか
		でもcallはOKなんだよな
	Before: alloca Buffer→alloca Canary→CanaryStoreBB→llvm.multicanary→別のbuffer→...
	After: alloca all Buffer + all Canary→llvm.multicanary→lots of CanaryStoreBB
		entry basicblockにすべてを収められる
	が、よくよく考えたらentry basicblockにはalloca以降の処理も置かれているので、entryの後ろに処理を挿入するとプログラムが終わってからcanaryを挿入することになってしまう(それはダメでしょう)
	よく見るとAllocaInstはentryの前半に連続して置かれているので、allocaの連続が終わったらそこからは実際の処理だとみなして切ってしまう
		その仮定大丈夫?

	FailBBがなぜか消えている
		単純なミスだった

Backlinks