| //===-------- String.cpp - Secure C standard string library calls ---------===// |
| // |
| // The SAFECode Compiler |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This pass finds all calls to functions in the C standard string library and |
| // transforms them to a more secure form. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "safecode/CStdLib.h" |
| |
| NAMESPACE_SC_BEGIN |
| |
| // Identifier variable for the pass |
| char StringTransform::ID = 0; |
| |
| // Statistics counters |
| STATISTIC(stat_transform_memcpy, "Total memcpy() calls transformed"); |
| STATISTIC(stat_transform_memmove, "Total memmove() calls transformed"); |
| STATISTIC(stat_transform_mempcpy, "Total mempcpy() calls transformed"); |
| STATISTIC(stat_transform_memset, "Total memset() calls transformed"); |
| #if 0 |
| STATISTIC(stat_transform_strcat, "Total strcat() calls transformed"); |
| #endif |
| STATISTIC(stat_transform_strcpy, "Total strcpy() calls transformed"); |
| #if 0 |
| STATISTIC(stat_transform_strlcat, "Total strlcat() calls transformed"); |
| STATISTIC(stat_transform_strlcpy, "Total strlcpy() calls transformed"); |
| #endif |
| STATISTIC(stat_transform_strlen, "Total strlen() calls transformed"); |
| #if 0 |
| STATISTIC(stat_transform_strncat, "Total strncat() calls transformed"); |
| #endif |
| STATISTIC(stat_transform_strncpy, "Total strncpy() calls transformed"); |
| #if 0 |
| STATISTIC(stat_transform_strnlen, "Total strnlen() calls transformed"); |
| STATISTIC(stat_transform_wcscpy, "Total wcscpy() calls transformed"); |
| STATISTIC(stat_transform_wmemcpy, "Total wmemcpy() calls transformed"); |
| STATISTIC(stat_transform_wmemmove, "Total wmemmove() calls transformed"); |
| #endif |
| |
| static RegisterPass<StringTransform> |
| ST("string_transform", "Secure C standard string library calls"); |
| |
| /** |
| * Entry point for the LLVM pass that transforms C standard string library calls |
| * |
| * @param M Module to scan |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::runOnModule(Module &M) { |
| // Flags whether we modified the module. |
| bool modified = false; |
| |
| dsnPass = &getAnalysis<DSNodePass>(); |
| assert(dsnPass && "Must run DSNode Pass first!"); |
| |
| paPass = &getAnalysis<PoolAllocateGroup>(); |
| assert(paPass && "Must run Pool Allocation Transform first!"); |
| |
| modified |= memcpyTransform(M); |
| modified |= memmoveTransform(M); |
| modified |= mempcpyTransform(M); |
| modified |= memsetTransform(M); |
| modified |= strcpyTransform(M); |
| modified |= strlenTransform(M); |
| modified |= strncpyTransform(M); |
| |
| return modified; |
| } |
| |
| /** |
| * Secures memcpy() by transforming it into pool_memcpy() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for memcpy() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::memcpyTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_memcpy = M.getFunction("memcpy"); |
| if (!F_memcpy) |
| return modified; |
| |
| // Scan through the module and replace memcpy() with pool_memcpy(). |
| for (Value::use_iterator UI = F_memcpy->use_begin(), UE = F_memcpy->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_memcpy != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 3) { |
| I->dump(); |
| assert(CS.arg_size() == 3 && "memcpy() takes 3 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (void * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get the exact type for size_t. |
| const Type *SizeTy = I->getOperand(3)->getType(); |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| Value *srcPH = dsnPass->getPoolHandle(I->getOperand(2), F, *FI); |
| |
| if (!dstPH || !srcPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| assert(srcPH && "No pool handle for source pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| Value *Casted_srcPH = castTo(srcPH, VoidPtrTy, srcPH->getName() + ".casted", I); |
| |
| // Construct pool_memcpy(). |
| std::vector<const Type *> ParamTy(4, VoidPtrTy); |
| ParamTy.push_back(SizeTy); |
| Value *Params[] = {Casted_dstPH, Casted_srcPH, I->getOperand(1), I->getOperand(2), I->getOperand(3)}; |
| FunctionType *FT_pool_memcpy = FunctionType::get(F_memcpy->getReturnType(), ParamTy, false); |
| Constant *F_pool_memcpy = M.getOrInsertFunction("pool_memcpy", FT_pool_memcpy); |
| |
| // Create the call instruction for pool_memcpy() and insert it before the current instruction. |
| CallInst *CI_pool_memcpy = CallInst::Create(F_pool_memcpy, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of memcpy() with pool_memcpy(). |
| I->replaceAllUsesWith(CI_pool_memcpy); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_memcpy; |
| |
| // Mark the module as modified and continue to the next memcpy() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures memmove() by transforming it into pool_memmove() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for memmove() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::memmoveTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_memmove = M.getFunction("memmove"); |
| if (!F_memmove) |
| return modified; |
| |
| // Scan through the module and replace memmove() with pool_memmove(). |
| for (Value::use_iterator UI = F_memmove->use_begin(), UE = F_memmove->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_memmove != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 3) { |
| I->dump(); |
| assert(CS.arg_size() == 3 && "memmove() takes 3 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (void * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get the exact type for size_t. |
| const Type *SizeTy = I->getOperand(3)->getType(); |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| Value *srcPH = dsnPass->getPoolHandle(I->getOperand(2), F, *FI); |
| |
| if (!dstPH || !srcPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| assert(srcPH && "No pool handle for source pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| Value *Casted_srcPH = castTo(srcPH, VoidPtrTy, srcPH->getName() + ".casted", I); |
| |
| // Construct pool_memmove(). |
| std::vector<const Type *> ParamTy(4, VoidPtrTy); |
| ParamTy.push_back(SizeTy); |
| Value *Params[] = {Casted_dstPH, Casted_srcPH, I->getOperand(1), I->getOperand(2), I->getOperand(3)}; |
| FunctionType *FT_pool_memmove = FunctionType::get(F_memmove->getReturnType(), ParamTy, false); |
| Constant *F_pool_memmove = M.getOrInsertFunction("pool_memmove", FT_pool_memmove); |
| |
| // Create the call instruction for pool_memmove() and insert it before the current instruction. |
| CallInst *CI_pool_memmove = CallInst::Create(F_pool_memmove, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of memmove() with pool_memmove(). |
| I->replaceAllUsesWith(CI_pool_memmove); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_memmove; |
| |
| // Mark the module as modified and continue to the next memmove() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures mempcpy() by transforming it into pool_mempcpy() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for mempcpy() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::mempcpyTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_mempcpy = M.getFunction("mempcpy"); |
| if (!F_mempcpy) |
| return modified; |
| |
| // Scan through the module and replace mempcpy() with pool_mempcpy(). |
| for (Value::use_iterator UI = F_mempcpy->use_begin(), UE = F_mempcpy->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_mempcpy != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 3) { |
| I->dump(); |
| assert(CS.arg_size() == 3 && "mempcpy() takes 3 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (void * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get the exact type for size_t. |
| const Type *SizeTy = I->getOperand(3)->getType(); |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| Value *srcPH = dsnPass->getPoolHandle(I->getOperand(2), F, *FI); |
| |
| if (!dstPH || !srcPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| assert(srcPH && "No pool handle for source pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| Value *Casted_srcPH = castTo(srcPH, VoidPtrTy, srcPH->getName() + ".casted", I); |
| |
| // Construct pool_mempcpy(). |
| std::vector<const Type *> ParamTy(4, VoidPtrTy); |
| ParamTy.push_back(SizeTy); |
| Value *Params[] = {Casted_dstPH, Casted_srcPH, I->getOperand(1), I->getOperand(2), I->getOperand(3)}; |
| FunctionType *FT_pool_mempcpy = FunctionType::get(F_mempcpy->getReturnType(), ParamTy, false); |
| Constant *F_pool_mempcpy = M.getOrInsertFunction("pool_mempcpy", FT_pool_mempcpy); |
| |
| // Create the call instruction for pool_mempcpy() and insert it before the current instruction. |
| CallInst *CI_pool_mempcpy = CallInst::Create(F_pool_mempcpy, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of mempcpy() with pool_mempcpy(). |
| I->replaceAllUsesWith(CI_pool_mempcpy); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_mempcpy; |
| |
| // Mark the module as modified and continue to the next mempcpy() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures memset() by transforming it into pool_memset() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for memset() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::memsetTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_memset = M.getFunction("memset"); |
| if (!F_memset) |
| return modified; |
| |
| // Scan through the module and replace memset() with pool_memset(). |
| for (Value::use_iterator UI = F_memset->use_begin(), UE = F_memset->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_memset != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 3) { |
| I->dump(); |
| assert(CS.arg_size() == 3 && "memset() takes 3 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (void * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get the exact type for size_t. |
| const Type *IntTy = I->getOperand(2)->getType(); |
| const Type *SizeTy = I->getOperand(3)->getType(); |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| |
| if (!dstPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| |
| // Construct pool_memset(). |
| std::vector<const Type *> ParamTy(2, VoidPtrTy); |
| ParamTy.push_back(IntTy); |
| ParamTy.push_back(SizeTy); |
| Value *Params[] = {Casted_dstPH, I->getOperand(1), I->getOperand(2), I->getOperand(3)}; |
| FunctionType *FT_pool_memset = FunctionType::get(F_memset->getReturnType(), ParamTy, false); |
| Constant *F_pool_memset = M.getOrInsertFunction("pool_memset", FT_pool_memset); |
| |
| // Create the call instruction for pool_memset() and insert it before the current instruction. |
| CallInst *CI_pool_memset = CallInst::Create(F_pool_memset, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of memset() with pool_memset(). |
| I->replaceAllUsesWith(CI_pool_memset); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_memset; |
| |
| // Mark the module as modified and continue to the next memset() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures strcpy() by transforming it into pool_strcpy() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for strcpy() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::strcpyTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_strcpy = M.getFunction("strcpy"); |
| if (!F_strcpy) |
| return modified; |
| |
| // Scan through the module and replace strcpy() with pool_strcpy(). |
| for (Value::use_iterator UI = F_strcpy->use_begin(), UE = F_strcpy->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_strcpy != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 2) { |
| I->dump(); |
| assert(CS.arg_size() == 2 && "strcpy() takes 2 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (char * == i8 * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| Value *srcPH = dsnPass->getPoolHandle(I->getOperand(2), F, *FI); |
| |
| if (!dstPH || !srcPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| assert(srcPH && "No pool handle for source pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| Value *Casted_srcPH = castTo(srcPH, VoidPtrTy, srcPH->getName() + ".casted", I); |
| |
| // Construct pool_strcpy(). |
| std::vector<const Type *> ParamTy(4, VoidPtrTy); // SmallVector<const Type *, 4> |
| Value *Params[] = {Casted_dstPH, Casted_srcPH, I->getOperand(1), I->getOperand(2)}; |
| FunctionType *FT_pool_strcpy = FunctionType::get(F_strcpy->getReturnType(), ParamTy, false); |
| Constant *F_pool_strcpy = M.getOrInsertFunction("pool_strcpy", FT_pool_strcpy); |
| |
| // Create the call instruction for pool_strcpy() and insert it before the current instruction. |
| CallInst *CI_pool_strcpy = CallInst::Create(F_pool_strcpy, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of strcpy() with pool_strcpy(). |
| I->replaceAllUsesWith(CI_pool_strcpy); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_strcpy; |
| |
| // Mark the module as modified and continue to the next strcpy() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures strlen() by transforming it into pool_strlen() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for strlen() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::strlenTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| const Type *Int32Ty = IntegerType::getInt32Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_strlen = M.getFunction("strlen"); |
| if (!F_strlen) |
| return modified; |
| |
| // Scan through the module and replace strlen() with pool_strlen(). |
| for (Value::use_iterator UI = F_strlen->use_begin(), UE = F_strlen->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_strlen != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 1) { |
| I->dump(); |
| assert(CS.arg_size() == 1 && "strlen() takes 1 argument!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (i32). |
| if (CalledF->getReturnType() != Int32Ty) |
| continue; |
| |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *stringPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| |
| if (!stringPH) |
| I->dump(); |
| assert(stringPH && "No pool handle for string!\n"); |
| Value *Casted_stringPH = castTo(stringPH, VoidPtrTy, stringPH->getName() + ".casted", I); |
| |
| // Construct pool_strlen(). |
| std::vector<const Type *> ParamTy(2, VoidPtrTy); // SmallVector<const Type *, 4> |
| Value *Params[] = {Casted_stringPH, I->getOperand(1)}; |
| FunctionType *FT_pool_strlen = FunctionType::get(F_strlen->getReturnType(), ParamTy, false); |
| Constant *F_pool_strlen = M.getOrInsertFunction("pool_strlen", FT_pool_strlen); |
| |
| // Create the call instruction for pool_strlen() and insert it before the current instruction. |
| CallInst *CI_pool_strlen = CallInst::Create(F_pool_strlen, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of strlen() with pool_strlen(). |
| I->replaceAllUsesWith(CI_pool_strlen); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_strlen; |
| |
| // Mark the module as modified and continue to the next strlen() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| /** |
| * Secures strncpy() by transforming it into pool_strncpy() with correct bounds |
| * |
| * @param M Module from runOnModule() to scan for strncpy() |
| * @return Whether we modified the module |
| */ |
| bool StringTransform::strncpyTransform(Module &M) { |
| // Flag whether we modified the module. |
| bool modified = false; |
| |
| // Create needed pointer types. |
| const Type *Int8Ty = IntegerType::getInt8Ty(getGlobalContext()); |
| PointerType *VoidPtrTy = PointerType::getUnqual(Int8Ty); |
| |
| Function *F_strncpy = M.getFunction("strncpy"); |
| if (!F_strncpy) |
| return modified; |
| |
| // Scan through the module and replace strncpy() with pool_strncpy(). |
| for (Value::use_iterator UI = F_strncpy->use_begin(), UE = F_strncpy->use_end(); UI != UE;) { |
| Instruction *I = dyn_cast<Instruction>(UI); |
| ++UI; // Replacement invalidates the user, so must increment the iterator beforehand. |
| |
| if (I) { |
| CallSite CS(I); |
| Function *CalledF = CS.getCalledFunction(); |
| |
| // Indirect call. |
| if (NULL == CalledF) |
| continue; |
| |
| if (F_strncpy != CalledF) |
| continue; |
| |
| // Check that the function uses the correct number of arguments. |
| if (CS.arg_size() != 3) { |
| I->dump(); |
| assert(CS.arg_size() == 3 && "strncpy() takes 3 arguments!\n"); |
| continue; |
| } |
| |
| // Check for correct return type (char * == i8 * == VoidPtrTy). |
| if (CalledF->getReturnType() != VoidPtrTy) |
| continue; |
| |
| // Get the exact type for size_t. |
| const Type *SizeTy = I->getOperand(3)->getType(); |
| |
| // Get pool handles for destination and source strings. |
| Function *F = I->getParent()->getParent(); |
| PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F); |
| Value *dstPH = dsnPass->getPoolHandle(I->getOperand(1), F, *FI); |
| Value *srcPH = dsnPass->getPoolHandle(I->getOperand(2), F, *FI); |
| |
| if (!dstPH || !srcPH) |
| I->dump(); |
| assert(dstPH && "No pool handle for destination pointer!\n"); |
| assert(srcPH && "No pool handle for source pointer!\n"); |
| |
| Value *Casted_dstPH = castTo(dstPH, VoidPtrTy, dstPH->getName() + ".casted", I); |
| Value *Casted_srcPH = castTo(srcPH, VoidPtrTy, srcPH->getName() + ".casted", I); |
| |
| // Construct pool_strncpy(). |
| std::vector<const Type *> ParamTy(4, VoidPtrTy); |
| ParamTy.push_back(SizeTy); |
| Value *Params[] = {Casted_dstPH, Casted_srcPH, I->getOperand(1), I->getOperand(2), I->getOperand(3)}; |
| FunctionType *FT_pool_strncpy = FunctionType::get(F_strncpy->getReturnType(), ParamTy, false); |
| Constant *F_pool_strncpy = M.getOrInsertFunction("pool_strncpy", FT_pool_strncpy); |
| |
| // Create the call instruction for pool_strncpy() and insert it before the current instruction. |
| CallInst *CI_pool_strncpy = CallInst::Create(F_pool_strncpy, Params, array_endof(Params), "", I); |
| |
| // Replace all of the uses of strncpy() with pool_strncpy(). |
| I->replaceAllUsesWith(CI_pool_strncpy); |
| I->eraseFromParent(); |
| |
| // Record the transform. |
| ++stat_transform_strncpy; |
| |
| // Mark the module as modified and continue to the next strncpy() call. |
| modified = true; |
| } |
| } |
| |
| return modified; |
| } |
| |
| |
| NAMESPACE_SC_END |