Bug Summary

File:lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
Warning:line 166, column 9
2nd function call argument is an uninitialized value

Annotated Source Code

1//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements MCELFStreamer for Mips NaCl. It emits .o object files
11// as required by NaCl's SFI sandbox. It inserts address-masking instructions
12// before dangerous control-flow and memory access instructions. It inserts
13// address-masking instructions after instructions that change the stack
14// pointer. It ensures that the mask and the dangerous instruction are always
15// emitted in the same bundle. It aligns call + branch delay to the bundle end,
16// so that return address is always aligned to the start of next bundle.
17//
18//===----------------------------------------------------------------------===//
19
20#include "Mips.h"
21#include "MipsELFStreamer.h"
22#include "MipsMCNaCl.h"
23#include "llvm/MC/MCAssembler.h"
24#include "llvm/MC/MCELFStreamer.h"
25#include "llvm/MC/MCInst.h"
26#include "llvm/Support/ErrorHandling.h"
27#include <cassert>
28
29using namespace llvm;
30
31#define DEBUG_TYPE"mips-mc-nacl" "mips-mc-nacl"
32
33namespace {
34
35const unsigned IndirectBranchMaskReg = Mips::T6;
36const unsigned LoadStoreStackMaskReg = Mips::T7;
37
38/// Extend the generic MCELFStreamer class so that it can mask dangerous
39/// instructions.
40
41class MipsNaClELFStreamer : public MipsELFStreamer {
42public:
43 MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
44 raw_pwrite_stream &OS, MCCodeEmitter *Emitter)
45 : MipsELFStreamer(Context, TAB, OS, Emitter) {}
46
47 ~MipsNaClELFStreamer() override = default;
48
49private:
50 // Whether we started the sandboxing sequence for calls. Calls are bundled
51 // with branch delays and aligned to the bundle end.
52 bool PendingCall = false;
53
54 bool isIndirectJump(const MCInst &MI) {
55 if (MI.getOpcode() == Mips::JALR) {
56 // MIPS32r6/MIPS64r6 doesn't have a JR instruction and uses JALR instead.
57 // JALR is an indirect branch if the link register is $0.
58 assert(MI.getOperand(0).isReg())((MI.getOperand(0).isReg()) ? static_cast<void> (0) : __assert_fail
("MI.getOperand(0).isReg()", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn301135/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp"
, 58, __PRETTY_FUNCTION__))
;
59 return MI.getOperand(0).getReg() == Mips::ZERO;
60 }
61 return MI.getOpcode() == Mips::JR;
62 }
63
64 bool isStackPointerFirstOperand(const MCInst &MI) {
65 return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
66 && MI.getOperand(0).getReg() == Mips::SP);
67 }
68
69 bool isCall(const MCInst &MI, bool *IsIndirectCall) {
70 unsigned Opcode = MI.getOpcode();
71
72 *IsIndirectCall = false;
73
74 switch (Opcode) {
75 default:
76 return false;
77
78 case Mips::JAL:
79 case Mips::BAL:
80 case Mips::BAL_BR:
81 case Mips::BLTZAL:
82 case Mips::BGEZAL:
83 return true;
84
85 case Mips::JALR:
86 // JALR is only a call if the link register is not $0. Otherwise it's an
87 // indirect branch.
88 assert(MI.getOperand(0).isReg())((MI.getOperand(0).isReg()) ? static_cast<void> (0) : __assert_fail
("MI.getOperand(0).isReg()", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn301135/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp"
, 88, __PRETTY_FUNCTION__))
;
89 if (MI.getOperand(0).getReg() == Mips::ZERO)
90 return false;
91
92 *IsIndirectCall = true;
93 return true;
94 }
95 }
96
97 void emitMask(unsigned AddrReg, unsigned MaskReg,
98 const MCSubtargetInfo &STI) {
99 MCInst MaskInst;
100 MaskInst.setOpcode(Mips::AND);
101 MaskInst.addOperand(MCOperand::createReg(AddrReg));
102 MaskInst.addOperand(MCOperand::createReg(AddrReg));
103 MaskInst.addOperand(MCOperand::createReg(MaskReg));
104 MipsELFStreamer::EmitInstruction(MaskInst, STI);
105 }
106
107 // Sandbox indirect branch or return instruction by inserting mask operation
108 // before it.
109 void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
110 unsigned AddrReg = MI.getOperand(0).getReg();
111
112 EmitBundleLock(false);
113 emitMask(AddrReg, IndirectBranchMaskReg, STI);
114 MipsELFStreamer::EmitInstruction(MI, STI);
115 EmitBundleUnlock();
116 }
117
118 // Sandbox memory access or SP change. Insert mask operation before and/or
119 // after the instruction.
120 void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
121 const MCSubtargetInfo &STI, bool MaskBefore,
122 bool MaskAfter) {
123 EmitBundleLock(false);
124 if (MaskBefore) {
125 // Sandbox memory access.
126 unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
127 emitMask(BaseReg, LoadStoreStackMaskReg, STI);
128 }
129 MipsELFStreamer::EmitInstruction(MI, STI);
130 if (MaskAfter) {
131 // Sandbox SP change.
132 unsigned SPReg = MI.getOperand(0).getReg();
133 assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.")(((Mips::SP == SPReg) && "Unexpected stack-pointer register."
) ? static_cast<void> (0) : __assert_fail ("(Mips::SP == SPReg) && \"Unexpected stack-pointer register.\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn301135/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp"
, 133, __PRETTY_FUNCTION__))
;
134 emitMask(SPReg, LoadStoreStackMaskReg, STI);
135 }
136 EmitBundleUnlock();
137 }
138
139public:
140 /// This function is the one used to emit instruction data into the ELF
141 /// streamer. We override it to mask dangerous instructions.
142 void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
143 bool) override {
144 // Sandbox indirect jumps.
145 if (isIndirectJump(Inst)) {
1
Taking false branch
146 if (PendingCall)
147 report_fatal_error("Dangerous instruction in branch delay slot!");
148 sandboxIndirectJump(Inst, STI);
149 return;
150 }
151
152 // Sandbox loads, stores and SP changes.
153 unsigned AddrIdx;
2
'AddrIdx' declared without an initial value
154 bool IsStore;
155 bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
3
Calling 'isBasePlusOffsetMemoryAccess'
6
Returning from 'isBasePlusOffsetMemoryAccess'
156 &IsStore);
157 bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
158 if (IsMemAccess || IsSPFirstOperand) {
7
Assuming 'IsSPFirstOperand' is not equal to 0
8
Taking true branch
159 bool MaskBefore = (IsMemAccess
160 && baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
161 .getReg()));
162 bool MaskAfter = IsSPFirstOperand && !IsStore;
163 if (MaskBefore || MaskAfter) {
9
Taking true branch
164 if (PendingCall)
10
Assuming the condition is false
11
Taking false branch
165 report_fatal_error("Dangerous instruction in branch delay slot!");
166 sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
12
2nd function call argument is an uninitialized value
167 return;
168 }
169 // fallthrough
170 }
171
172 // Sandbox calls by aligning call and branch delay to the bundle end.
173 // For indirect calls, emit the mask before the call.
174 bool IsIndirectCall;
175 if (isCall(Inst, &IsIndirectCall)) {
176 if (PendingCall)
177 report_fatal_error("Dangerous instruction in branch delay slot!");
178
179 // Start the sandboxing sequence by emitting call.
180 EmitBundleLock(true);
181 if (IsIndirectCall) {
182 unsigned TargetReg = Inst.getOperand(1).getReg();
183 emitMask(TargetReg, IndirectBranchMaskReg, STI);
184 }
185 MipsELFStreamer::EmitInstruction(Inst, STI);
186 PendingCall = true;
187 return;
188 }
189 if (PendingCall) {
190 // Finish the sandboxing sequence by emitting branch delay.
191 MipsELFStreamer::EmitInstruction(Inst, STI);
192 EmitBundleUnlock();
193 PendingCall = false;
194 return;
195 }
196
197 // None of the sandboxing applies, just emit the instruction.
198 MipsELFStreamer::EmitInstruction(Inst, STI);
199 }
200};
201
202} // end anonymous namespace
203
204namespace llvm {
205
206bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
207 bool *IsStore) {
208 if (IsStore)
4
Taking true branch
209 *IsStore = false;
210
211 switch (Opcode) {
5
Control jumps to the 'default' case at line 212
212 default:
213 return false;
214
215 // Load instructions with base address register in position 1.
216 case Mips::LB:
217 case Mips::LBu:
218 case Mips::LH:
219 case Mips::LHu:
220 case Mips::LW:
221 case Mips::LWC1:
222 case Mips::LDC1:
223 case Mips::LL:
224 case Mips::LL_R6:
225 case Mips::LWL:
226 case Mips::LWR:
227 *AddrIdx = 1;
228 return true;
229
230 // Store instructions with base address register in position 1.
231 case Mips::SB:
232 case Mips::SH:
233 case Mips::SW:
234 case Mips::SWC1:
235 case Mips::SDC1:
236 case Mips::SWL:
237 case Mips::SWR:
238 *AddrIdx = 1;
239 if (IsStore)
240 *IsStore = true;
241 return true;
242
243 // Store instructions with base address register in position 2.
244 case Mips::SC:
245 case Mips::SC_R6:
246 *AddrIdx = 2;
247 if (IsStore)
248 *IsStore = true;
249 return true;
250 }
251}
252
253bool baseRegNeedsLoadStoreMask(unsigned Reg) {
254 // The contents of SP and thread pointer register do not require masking.
255 return Reg != Mips::SP && Reg != Mips::T8;
256}
257
258MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
259 raw_pwrite_stream &OS,
260 MCCodeEmitter *Emitter,
261 bool RelaxAll) {
262 MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
263 if (RelaxAll)
264 S->getAssembler().setRelaxAll(true);
265
266 // Set bundle-alignment as required by the NaCl ABI for the target.
267 S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
268
269 return S;
270}
271
272} // end namespace llvm