summaryrefslogtreecommitdiff
path: root/lib/Analysis/MallocHelper.cpp
blob: 567268c6797cba36b5053259dd4f18293a0e77db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//===-- MallocHelper.cpp - Functions to identify malloc calls -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This family of functions identifies calls to malloc, bitcasts of malloc
// calls, and the types and array sizes associated with them.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MallocHelper.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
//  malloc Call Utility Functions.
//

/// isMalloc - Returns true if the the value is either a malloc call or a
/// bitcast of the result of a malloc call.
bool llvm::isMalloc(Value* I) {
  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
}

bool llvm::isMalloc(const Value* I) {
  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
}

static bool isMallocCall(const CallInst *CI) {
  if (!CI)
    return false;

  const Module* M = CI->getParent()->getParent()->getParent();
  Constant *MallocFunc = M->getFunction("malloc");

  if (CI->getOperand(0) != MallocFunc)
    return false;

  return true;
}

/// extractMallocCall - Returns the corresponding CallInst if the instruction
/// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
/// ignore InvokeInst here.
const CallInst* llvm::extractMallocCall(const Value* I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

CallInst* llvm::extractMallocCall(Value* I) {
  CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

static bool isBitCastOfMallocCall(const BitCastInst* BCI) {
  if (!BCI)
    return false;
    
  return isMallocCall(dyn_cast<CallInst>(BCI->getOperand(0)));
}

/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the
/// instruction is a bitcast of the result of a malloc call.
CallInst* llvm::extractMallocCallFromBitCast(Value* I) {
  BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0)) : NULL;
}

const CallInst* llvm::extractMallocCallFromBitCast(const Value* I) {
  const BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0)) : NULL;
}

static bool isArrayMallocHelper(const CallInst *CI) {
  if (!CI)
    return false;

  // Only identify array mallocs for mallocs with 1 bitcast use.  The unique 
  // bitcast is needed to determine the type/size of the array allocation.
  if (!CI->hasOneUse()) return false;

  for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
       UI != E; )
    if (!isa<BitCastInst>(cast<Instruction>(*UI++)))
      return false;

  // malloc arg
  Value* MallocArg = CI->getOperand(1);
  // element size
  const Type* T = getMallocAllocatedType(CI);
  if (!T) return false;
  Constant *ElementSize = ConstantExpr::getSizeOf(T);
  
  if (isa<ConstantExpr>(MallocArg))
    return (MallocArg == ElementSize) ? false : true;

  BinaryOperator *BI = dyn_cast<BinaryOperator>(MallocArg);
  if (!BI)
    return false;

  if (BI->getOpcode() != Instruction::Mul)
    return false;
      
  if (BI->getOperand(1) != ElementSize)
    return false;
        
  return true;
}

/// isArrayMalloc - Returns the corresponding CallInst if the instruction 
/// matches the malloc call IR generated by CallInst::CreateMalloc().  This 
/// means that it is a malloc call with one bitcast use AND the malloc call's 
/// size argument is:
///  1. a constant not equal to the malloc's allocated type
/// or
///  2. the result of a multiplication by the malloc's allocated type
/// Otherwise it returns NULL.
/// The unique bitcast is needed to determine the type/size of the array
/// allocation.
CallInst* llvm::isArrayMalloc(Value* I) {
  CallInst *CI = extractMallocCall(I);
  return (isArrayMallocHelper(CI)) ? CI : NULL;
}

const CallInst* llvm::isArrayMalloc(const Value* I) {
  const CallInst *CI = extractMallocCall(I);
  return (isArrayMallocHelper(CI)) ? CI : NULL;
}

/// getMallocType - Returns the PointerType resulting from the malloc call.
/// This PointerType is the result type of the call's only bitcast use.
/// If there is no unique bitcast use, then return NULL.
const PointerType* llvm::getMallocType(const CallInst* CI) {
  assert(isMalloc(CI) && "GetMallocType and not malloc call");
  
  const BitCastInst* BCI = NULL;

  // Determine type only if there is only 1 bitcast use of CI.
  if (CI->hasOneUse())
    for (Value::use_const_iterator UI = CI->use_begin(), E = CI->use_end();
         UI != E; )
      BCI = dyn_cast<BitCastInst>(cast<Instruction>(*UI++));

  return BCI ? reinterpret_cast<const PointerType*>(BCI->getDestTy()) : NULL;
}

/// getMallocAllocatedType - Returns the Type allocated by malloc call. This
/// Type is the result type of the call's only bitcast use. If there is no
/// unique bitcast use, then return NULL.
const Type* llvm::getMallocAllocatedType(const CallInst* CI) {
  const PointerType* PT = getMallocType(CI);
  return PT ? PT->getElementType() : NULL;
}

/// isConstantOne - Return true only if val is constant int 1.
static bool isConstantOne(Value *val) {
  return isa<ConstantInt>(val) && cast<ConstantInt>(val)->isOne();
}

/// getMallocArraySize - Returns the array size of a malloc call.  The array
/// size is computated in 1 of 3 ways:
///  1. If the element type if of size 1, then array size is the argument to 
///     malloc.
///  2. Else if the malloc's argument is a constant, the array size is that
///     argument divided by the element type's size.
///  3. Else the malloc argument must be a multiplication and the array size is
///     the first operand of the multiplication.
/// This function returns constant 1 if:
///  1. The malloc call's allocated type cannot be determined.
///  2. IR wasn't created by a call to CallInst::CreateMalloc() with a non-NULL
///     ArraySize.
Value* llvm::getMallocArraySize(CallInst* CI) {
  // Match CreateMalloc's use of constant 1 array-size for non-array mallocs.
  if (!isArrayMalloc(CI))
    return ConstantInt::get(CI->getOperand(1)->getType(), 1);

  Value* MallocArg = CI->getOperand(1);
  assert(getMallocAllocatedType(CI) && "getMallocArraySize and no type");
  Constant *ElementSize = ConstantExpr::getSizeOf(getMallocAllocatedType(CI));
  ElementSize = ConstantExpr::getTruncOrBitCast(cast<Constant>(ElementSize), 
                                                MallocArg->getType());

  Constant* CO = dyn_cast<Constant>(MallocArg);
  BinaryOperator* BO = dyn_cast<BinaryOperator>(MallocArg);
  assert((isConstantOne(ElementSize) || CO || BO) &&
         "getMallocArraySize and malformed malloc IR");
      
  if (isConstantOne(ElementSize))
    return MallocArg;

  if (CO) 
    return ConstantExpr::getUDiv(CO, ElementSize);
  
  assert(BO && "getMallocArraySize not constant but not multiplication either");
  return BO->getOperand(0);
}