<commit_before>//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MipsTargetHandler.h"
#include "MipsLinkingContext.h"
#include "MipsRelocationHandler.h"

#include "lld/ReaderWriter/RelocationHelperFunctions.h"

using namespace lld;
using namespace elf;
using namespace llvm::ELF;

namespace {

inline
void applyReloc(uint8_t *loc, uint32_t result, uint32_t mask) {
  auto target = reinterpret_cast<llvm::support::ulittle32_t *>(loc);
  *target = (uint32_t(*target) & ~mask) | (result & mask);
}

/// \brief Calculate AHL value combines addends from 'hi' and 'lo' relocations.
inline int64_t calcAHL(int64_t AHI, int64_t ALO) {
  AHI &= 0xffff;
  ALO &= 0xffff;
  return (AHI << 16) + (int16_t)ALO;
}

template <size_t BITS, class T> inline T signExtend(T val) {
  if (val & (T(1) << (BITS - 1)))
    val |= T(-1) << BITS;
  return val;
}

/// \brief R_MIPS_32
/// local/external: word32 S + A (truncate)
void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
  applyReloc(location, S + A, 0xffffffff);
}

/// \brief R_MIPS_26
/// local   : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
/// external: (sign–extend(A) + S) >> 2
void reloc26(uint8_t *location, uint64_t P, uint64_t S, bool isLocal) {
  int32_t A = (*(uint32_t*)location & 0x03FFFFFFU) << 2;
  uint32_t result = isLocal ? (A | ((P + 4) & 0x3F000000)) : signExtend<28>(A);
  result = (result + S) >> 2;
  applyReloc(location, result, 0x03ffffff);
}

/// \brief R_MIPS_HI16
/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
/// _gp_disp      : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
void relocHi16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
               uint64_t GP, bool isGPDisp) {
  int32_t result = 0;

  if (isGPDisp)
    result = (AHL + GP - P) - (int16_t)(AHL + GP - P);
  else
    result = (AHL + S) - (int16_t)(AHL + S);

  applyReloc(location, result >> 16, 0xffff);
}

/// \brief R_MIPS_LO16
/// local/external: lo16 AHL + S (truncate)
/// _gp_disp      : lo16 AHL + GP - P + 4 (verify)
void relocLo16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
               uint64_t GP, bool isGPDisp) {
  int32_t result = 0;

  if (isGPDisp)
    result = AHL + GP - P + 4;
  else
    result = AHL + S;

  applyReloc(location, result, 0xffff);
}

/// \brief R_MIPS_GOT16
/// local/external: rel16 G (verify)
void relocGOT16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
                uint64_t GP) {
  // FIXME (simon): for local sym put high 16 bit of AHL to the GOT
  int32_t G = (int32_t)(S - GP);
  applyReloc(location, G, 0xffff);
}

/// \brief R_MIPS_CALL16
/// external: rel16 G (verify)
void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
                 uint64_t GP) {
  int32_t G = (int32_t)(S - GP);
  applyReloc(location, G, 0xffff);
}

/// \brief LLD_R_MIPS_HI16
void relocLldHi16(uint8_t *location, uint64_t S) {
  applyReloc(location, (S + 0x8000) >> 16, 0xffff);
}

/// \brief LLD_R_MIPS_LO16
void relocLldLo16(uint8_t *location, uint64_t S) {
  applyReloc(location, S, 0xffff);
}

} // end anon namespace

MipsTargetRelocationHandler::~MipsTargetRelocationHandler() {
  assert(_pairedRelocations.empty());
}

void
MipsTargetRelocationHandler::savePairedRelocation(const lld::AtomLayout &atom,
                                                  const Reference &ref) const {
  auto pi = _pairedRelocations.find(&atom);
  if (pi == _pairedRelocations.end())
    pi = _pairedRelocations.emplace(&atom, PairedRelocationsT()).first;

  pi->second.push_back(&ref);
}

void MipsTargetRelocationHandler::applyPairedRelocations(
    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
    int64_t gpAddr, int64_t loAddend) const {
  auto pi = _pairedRelocations.find(&atom);
  if (pi == _pairedRelocations.end())
    return;

  for (auto ri : pi->second) {
    uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
    uint8_t *location = atomContent + ri->offsetInAtom();
    uint64_t targetVAddress = writer.addressOfAtom(ri->target());
    uint64_t relocVAddress = atom._virtualAddr + ri->offsetInAtom();

    int64_t ahl = calcAHL(ri->addend(), loAddend);

    if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF)
      continue;
    assert(ri->kindArch() == Reference::KindArch::Mips);
    switch (ri->kindValue()) {
    case R_MIPS_HI16:
      relocHi16(location, relocVAddress, targetVAddress, ahl, gpAddr,
                ri->target()->name() == "_gp_disp");
      break;
    case R_MIPS_GOT16:
      relocGOT16(location, relocVAddress, targetVAddress, ahl, gpAddr);
      break;
    default:
      llvm_unreachable("Unknown type of paired relocation.");
    }
  }

  _pairedRelocations.erase(pi);
}

error_code MipsTargetRelocationHandler::applyRelocation(
    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
    const Reference &ref) const {
  if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
    return error_code::success();
  assert(ref.kindArch() == Reference::KindArch::Mips);

  AtomLayout *gpAtom = _mipsTargetLayout.getGP();
  uint64_t gpAddr = gpAtom ? gpAtom->_virtualAddr : 0;

  uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
  uint8_t *location = atomContent + ref.offsetInAtom();
  uint64_t targetVAddress = writer.addressOfAtom(ref.target());
  uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();

  switch (ref.kindValue()) {
  case R_MIPS_NONE:
    break;
  case R_MIPS_32:
    reloc32(location, relocVAddress, targetVAddress, ref.addend());
    break;
  case R_MIPS_26:
    reloc26(location, relocVAddress, targetVAddress, true);
    break;
  case R_MIPS_HI16:
    savePairedRelocation(atom, ref);
    break;
  case R_MIPS_LO16:
    relocLo16(location, relocVAddress, targetVAddress, calcAHL(0, ref.addend()),
              gpAddr, ref.target()->name() == "_gp_disp");
    applyPairedRelocations(writer, buf, atom, gpAddr, ref.addend());
    break;
  case R_MIPS_GOT16:
    savePairedRelocation(atom, ref);
    break;
  case R_MIPS_CALL16:
    relocCall16(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
    break;
  case R_MIPS_JALR:
    // We do not do JALR optimization now.
    break;
  case R_MIPS_JUMP_SLOT:
    // Ignore runtime relocations.
    break;
  case LLD_R_MIPS_GLOBAL_GOT:
    // Do nothing.
    break;
  case LLD_R_MIPS_GLOBAL_GOT16:
    relocGOT16(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
    break;
  case LLD_R_MIPS_GLOBAL_26:
    reloc26(location, relocVAddress, targetVAddress, false);
    break;
  case LLD_R_MIPS_HI16:
    relocLldHi16(location, targetVAddress);
    break;
  case LLD_R_MIPS_LO16:
    relocLldLo16(location, targetVAddress);
    break;
  default: {
    std::string str;
    llvm::raw_string_ostream s(str);
    s << "Unhandled Mips relocation: " << ref.kindValue();
    llvm_unreachable(s.str().c_str());
  }
  }

  return error_code::success();
}
<commit_msg>[Mips] Split reloc26 function into two parts - for processing local and external relocations.<commit_after>//===- lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp ----------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MipsTargetHandler.h"
#include "MipsLinkingContext.h"
#include "MipsRelocationHandler.h"

#include "lld/ReaderWriter/RelocationHelperFunctions.h"

using namespace lld;
using namespace elf;
using namespace llvm::ELF;

namespace {

inline
void applyReloc(uint8_t *loc, uint32_t result, uint32_t mask) {
  auto target = reinterpret_cast<llvm::support::ulittle32_t *>(loc);
  *target = (uint32_t(*target) & ~mask) | (result & mask);
}

/// \brief Calculate AHL value combines addends from 'hi' and 'lo' relocations.
inline int64_t calcAHL(int64_t AHI, int64_t ALO) {
  AHI &= 0xffff;
  ALO &= 0xffff;
  return (AHI << 16) + (int16_t)ALO;
}

template <size_t BITS, class T> inline T signExtend(T val) {
  if (val & (T(1) << (BITS - 1)))
    val |= T(-1) << BITS;
  return val;
}

/// \brief R_MIPS_32
/// local/external: word32 S + A (truncate)
void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
  applyReloc(location, S + A, 0xffffffff);
}

/// \brief R_MIPS_26
/// local   : ((A | ((P + 4) & 0x3F000000)) + S) >> 2
void reloc26loc(uint8_t *location, uint64_t P, uint64_t S, int32_t A) {
  uint32_t result = ((A << 2) | ((P + 4) & 0x3f000000)) + S;
  applyReloc(location, result >> 2, 0x03ffffff);
}

/// \brief LLD_R_MIPS_GLOBAL_26
/// external: (sign–extend(A) + S) >> 2
void reloc26ext(uint8_t *location, uint64_t S, int32_t A) {
  uint32_t result = signExtend<28>(A << 2) + S;
  applyReloc(location, result >> 2, 0x03ffffff);
}

/// \brief R_MIPS_HI16
/// local/external: hi16 (AHL + S) - (short)(AHL + S) (truncate)
/// _gp_disp      : hi16 (AHL + GP - P) - (short)(AHL + GP - P) (verify)
void relocHi16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
               uint64_t GP, bool isGPDisp) {
  int32_t result = 0;

  if (isGPDisp)
    result = (AHL + GP - P) - (int16_t)(AHL + GP - P);
  else
    result = (AHL + S) - (int16_t)(AHL + S);

  applyReloc(location, result >> 16, 0xffff);
}

/// \brief R_MIPS_LO16
/// local/external: lo16 AHL + S (truncate)
/// _gp_disp      : lo16 AHL + GP - P + 4 (verify)
void relocLo16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
               uint64_t GP, bool isGPDisp) {
  int32_t result = 0;

  if (isGPDisp)
    result = AHL + GP - P + 4;
  else
    result = AHL + S;

  applyReloc(location, result, 0xffff);
}

/// \brief R_MIPS_GOT16
/// local/external: rel16 G (verify)
void relocGOT16(uint8_t *location, uint64_t P, uint64_t S, int64_t AHL,
                uint64_t GP) {
  // FIXME (simon): for local sym put high 16 bit of AHL to the GOT
  int32_t G = (int32_t)(S - GP);
  applyReloc(location, G, 0xffff);
}

/// \brief R_MIPS_CALL16
/// external: rel16 G (verify)
void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
                 uint64_t GP) {
  int32_t G = (int32_t)(S - GP);
  applyReloc(location, G, 0xffff);
}

/// \brief LLD_R_MIPS_HI16
void relocLldHi16(uint8_t *location, uint64_t S) {
  applyReloc(location, (S + 0x8000) >> 16, 0xffff);
}

/// \brief LLD_R_MIPS_LO16
void relocLldLo16(uint8_t *location, uint64_t S) {
  applyReloc(location, S, 0xffff);
}

} // end anon namespace

MipsTargetRelocationHandler::~MipsTargetRelocationHandler() {
  assert(_pairedRelocations.empty());
}

void
MipsTargetRelocationHandler::savePairedRelocation(const lld::AtomLayout &atom,
                                                  const Reference &ref) const {
  auto pi = _pairedRelocations.find(&atom);
  if (pi == _pairedRelocations.end())
    pi = _pairedRelocations.emplace(&atom, PairedRelocationsT()).first;

  pi->second.push_back(&ref);
}

void MipsTargetRelocationHandler::applyPairedRelocations(
    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
    int64_t gpAddr, int64_t loAddend) const {
  auto pi = _pairedRelocations.find(&atom);
  if (pi == _pairedRelocations.end())
    return;

  for (auto ri : pi->second) {
    uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
    uint8_t *location = atomContent + ri->offsetInAtom();
    uint64_t targetVAddress = writer.addressOfAtom(ri->target());
    uint64_t relocVAddress = atom._virtualAddr + ri->offsetInAtom();

    int64_t ahl = calcAHL(ri->addend(), loAddend);

    if (ri->kindNamespace() != lld::Reference::KindNamespace::ELF)
      continue;
    assert(ri->kindArch() == Reference::KindArch::Mips);
    switch (ri->kindValue()) {
    case R_MIPS_HI16:
      relocHi16(location, relocVAddress, targetVAddress, ahl, gpAddr,
                ri->target()->name() == "_gp_disp");
      break;
    case R_MIPS_GOT16:
      relocGOT16(location, relocVAddress, targetVAddress, ahl, gpAddr);
      break;
    default:
      llvm_unreachable("Unknown type of paired relocation.");
    }
  }

  _pairedRelocations.erase(pi);
}

error_code MipsTargetRelocationHandler::applyRelocation(
    ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
    const Reference &ref) const {
  if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
    return error_code::success();
  assert(ref.kindArch() == Reference::KindArch::Mips);

  AtomLayout *gpAtom = _mipsTargetLayout.getGP();
  uint64_t gpAddr = gpAtom ? gpAtom->_virtualAddr : 0;

  uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
  uint8_t *location = atomContent + ref.offsetInAtom();
  uint64_t targetVAddress = writer.addressOfAtom(ref.target());
  uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();

  switch (ref.kindValue()) {
  case R_MIPS_NONE:
    break;
  case R_MIPS_32:
    reloc32(location, relocVAddress, targetVAddress, ref.addend());
    break;
  case R_MIPS_26:
    reloc26loc(location, relocVAddress, targetVAddress, ref.addend());
    break;
  case R_MIPS_HI16:
    savePairedRelocation(atom, ref);
    break;
  case R_MIPS_LO16:
    relocLo16(location, relocVAddress, targetVAddress, calcAHL(0, ref.addend()),
              gpAddr, ref.target()->name() == "_gp_disp");
    applyPairedRelocations(writer, buf, atom, gpAddr, ref.addend());
    break;
  case R_MIPS_GOT16:
    savePairedRelocation(atom, ref);
    break;
  case R_MIPS_CALL16:
    relocCall16(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
    break;
  case R_MIPS_JALR:
    // We do not do JALR optimization now.
    break;
  case R_MIPS_JUMP_SLOT:
    // Ignore runtime relocations.
    break;
  case LLD_R_MIPS_GLOBAL_GOT:
    // Do nothing.
    break;
  case LLD_R_MIPS_GLOBAL_GOT16:
    relocGOT16(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
    break;
  case LLD_R_MIPS_GLOBAL_26:
    reloc26ext(location, targetVAddress, ref.addend());
    break;
  case LLD_R_MIPS_HI16:
    relocLldHi16(location, targetVAddress);
    break;
  case LLD_R_MIPS_LO16:
    relocLldLo16(location, targetVAddress);
    break;
  default: {
    std::string str;
    llvm::raw_string_ostream s(str);
    s << "Unhandled Mips relocation: " << ref.kindValue();
    llvm_unreachable(s.str().c_str());
  }
  }

  return error_code::success();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <unordered_map>
#include <future>

#include <curl/curl.h>

#include "client.hpp"

namespace azha {
	Client::Client()
	  : _oauth(new OAuth()) {
		curl_global_init(CURL_GLOBAL_ALL);
	}

	Client::~Client() {
		curl_global_cleanup();
	}

	void Client::consumer_key(const std::string &_consumer_key, const std::string &_consumer_secret) {
		_oauth->oauth_consumer_key(_consumer_key);
		_oauth->oauth_consumer_secret(_consumer_secret);
	}

	void Client::access_token(const std::string &_access_token, const std::string &_access_token_secret) {
		_oauth->oauth_token(_access_token);
		_oauth->oauth_token_secret(_access_token_secret);
	}

	std::future<Client::ResultType> Client::request(const parameters::ITwitterParameters &parameters) {
		return request(parameters.request_method(), parameters.url(), parameters.parameters);
	}

	std::future<Client::ResultType> Client::request(const parameters::RequestMethod &method, const std::string &url, const parameters::RequestParams &parameters) {
		return std::async(std::launch::async, &Client::request_internal, this, method, url, parameters);
	}

	Client::ResultType Client::request_internal(const parameters::RequestMethod &method, const std::string &url, const parameters::RequestParams &parameters) const
	{
		CURL* curl;
		CURLcode res;

		struct MemoryStruct data;

		data.memory = reinterpret_cast<char*>(malloc(1));
		data.size = 0;

		curl = curl_easy_init();

		if (curl == nullptr) {
			throw RequestFailedException("curl init failed");
		}

		std::stringstream ss;

		ss << "Authorization: " << _oauth->header_string(method, url, parameters);

		struct curl_slist *chunk = nullptr;
		chunk = curl_slist_append(chunk, ss.str().c_str());

		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		std::string parameter_string;
		if(method == parameters::RequestMethod::POST) {
			parameter_string = Client::parameter_string(parameters);
			std::cout << parameter_string << "\n";
			curl_easy_setopt(curl, CURLOPT_POSTFIELDS, parameter_string.c_str());
		}

		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(&data));

		res = curl_easy_perform(curl);

		if(res != CURLE_OK) {
			ss.str("curl_easy_perform() failed: ");
			ss << curl_easy_strerror(res);
			throw RequestFailedException(ss.str());
		}

		std::string response(data.memory);
		std::cout << response << "\n";

		char *content_type;
		curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
		bool contents_is_html = strncmp(content_type, "text/html;charset=utf-8", sizeof(content_type)) == 0;

		curl_easy_cleanup(curl);
		curl_slist_free_all(chunk);

		free(data.memory);

		if(contents_is_html) {
			return parse_query_string(response);
		}

		return parameters::RequestParams();
	}

	std::unordered_map<std::string, std::string> &&Client::parse_query_string(const std::string &query_string) {
		std::string key, value;
		std::stringstream ss;
		ss << query_string;
		std::unordered_map<std::string, std::string> result;

		while(getline(ss, key, '=') && getline(ss, value, '&')) {
			result[key] = value;
		}

		return std::move(result);
	}

	std::string Client::parameter_string(const parameters::RequestParams &parameters) {
		auto curl = curl_easy_init();

		std::unordered_map<std::string, std::string> p;

		for(const auto& iter : parameters) {
			p[iter.first] = iter.second;
		}

		std::stringstream ss;

		for(const auto& iter : p) {
			ss << iter.first << "=" << curl_easy_escape(curl, iter.second.c_str(), static_cast<int>(iter.second.size())) << "&";
		}

		auto parameter_string = ss.str();
		parameter_string.pop_back();

		return parameter_string;
	}

	size_t Client::write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
		auto realsize = size * nmemb;
		auto mem = static_cast<struct MemoryStruct *>(userp);

		mem->memory = reinterpret_cast<char *>(realloc(mem->memory, mem->size + realsize + 1));
		if(mem->memory == nullptr) {
			printf("not enough memory (realloc returned NULL)\n");
			return 0;
		}

		memcpy(&(mem->memory[mem->size]), contents, realsize);
		mem->size += realsize;
		mem->memory[mem->size] = 0;

		return realsize;
	}
}
<commit_msg>fix indentation & remove blank line<commit_after>#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <unordered_map>
#include <future>

#include <curl/curl.h>

#include "client.hpp"

namespace azha {
	Client::Client()
		: _oauth(new OAuth()) {
		curl_global_init(CURL_GLOBAL_ALL);
	}

	Client::~Client() {
		curl_global_cleanup();
	}

	void Client::consumer_key(const std::string &_consumer_key, const std::string &_consumer_secret) {
		_oauth->oauth_consumer_key(_consumer_key);
		_oauth->oauth_consumer_secret(_consumer_secret);
	}

	void Client::access_token(const std::string &_access_token, const std::string &_access_token_secret) {
		_oauth->oauth_token(_access_token);
		_oauth->oauth_token_secret(_access_token_secret);
	}

	std::future<Client::ResultType> Client::request(const parameters::ITwitterParameters &parameters) {
		return request(parameters.request_method(), parameters.url(), parameters.parameters);
	}

	std::future<Client::ResultType> Client::request(const parameters::RequestMethod &method, const std::string &url, const parameters::RequestParams &parameters) {
		return std::async(std::launch::async, &Client::request_internal, this, method, url, parameters);
	}

	Client::ResultType Client::request_internal(const parameters::RequestMethod &method, const std::string &url, const parameters::RequestParams &parameters) const
	{
		CURL* curl;
		CURLcode res;

		struct MemoryStruct data;

		data.memory = reinterpret_cast<char*>(malloc(1));
		data.size = 0;

		curl = curl_easy_init();

		if (curl == nullptr) {
			throw RequestFailedException("curl init failed");
		}

		std::stringstream ss;

		ss << "Authorization: " << _oauth->header_string(method, url, parameters);

		struct curl_slist *chunk = nullptr;
		chunk = curl_slist_append(chunk, ss.str().c_str());

		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		std::string parameter_string;
		if(method == parameters::RequestMethod::POST) {
			parameter_string = Client::parameter_string(parameters);
			std::cout << parameter_string << "\n";
			curl_easy_setopt(curl, CURLOPT_POSTFIELDS, parameter_string.c_str());
		}

		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(&data));

		res = curl_easy_perform(curl);

		if(res != CURLE_OK) {
			ss.str("curl_easy_perform() failed: ");
			ss << curl_easy_strerror(res);
			throw RequestFailedException(ss.str());
		}

		std::string response(data.memory);
		std::cout << response << "\n";

		char *content_type;
		curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
		bool contents_is_html = strncmp(content_type, "text/html;charset=utf-8", sizeof(content_type)) == 0;

		curl_easy_cleanup(curl);
		curl_slist_free_all(chunk);

		free(data.memory);

		if(contents_is_html) {
			return parse_query_string(response);
		}

		return parameters::RequestParams();
	}

	std::unordered_map<std::string, std::string> &&Client::parse_query_string(const std::string &query_string) {
		std::string key, value;
		std::stringstream ss;
		ss << query_string;
		std::unordered_map<std::string, std::string> result;

		while(getline(ss, key, '=') && getline(ss, value, '&')) {
			result[key] = value;
		}

		return std::move(result);
	}

	std::string Client::parameter_string(const parameters::RequestParams &parameters) {
		auto curl = curl_easy_init();

		std::unordered_map<std::string, std::string> p;

		for(const auto& iter : parameters) {
			p[iter.first] = iter.second;
		}

		std::stringstream ss;

		for(const auto& iter : p) {
			ss << iter.first << "=" << curl_easy_escape(curl, iter.second.c_str(), static_cast<int>(iter.second.size())) << "&";
		}

		auto parameter_string = ss.str();
		parameter_string.pop_back();

		return parameter_string;
	}

	size_t Client::write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
		auto realsize = size * nmemb;
		auto mem = static_cast<struct MemoryStruct *>(userp);

		mem->memory = reinterpret_cast<char *>(realloc(mem->memory, mem->size + realsize + 1));
		if(mem->memory == nullptr) {
			printf("not enough memory (realloc returned NULL)\n");
			return 0;
		}

		memcpy(&(mem->memory[mem->size]), contents, realsize);
		mem->size += realsize;
		mem->memory[mem->size] = 0;

		return realsize;
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "statechecker.h"
#include "distributor_bucket_space.h"
#include "distributor_stripe_component.h"
#include <vespa/vdslib/distribution/distribution.h>
#include <vespa/vdslib/state/clusterstate.h>

#include <vespa/log/log.h>
LOG_SETUP(".distributor.statechecker");

namespace storage::distributor {

namespace {

class StoredResultImpl
    : public StateChecker::ResultImpl
{
    mutable IdealStateOperation::UP _operation;
    MaintenancePriority _priority;
public:
    StoredResultImpl(const StoredResultImpl &) = delete;
    StoredResultImpl & operator = (const StoredResultImpl &) = delete;
    StoredResultImpl()
        : _operation(),
          _priority(MaintenancePriority::NO_MAINTENANCE_NEEDED)
    {}

    StoredResultImpl(IdealStateOperation::UP operation,
                     MaintenancePriority priority)
        : _operation(std::move(operation)),
          _priority(priority)
    {}

    IdealStateOperation::UP createOperation() override {
        return std::move(_operation);
    }

    MaintenancePriority getPriority() const override {
        return _priority;
    }

    MaintenanceOperation::Type getType() const override {
        assert(_operation.get());
        return _operation->getType();
    }
};

}

StateChecker::Result
StateChecker::Result::noMaintenanceNeeded()
{
    return Result(std::unique_ptr<ResultImpl>());
}

StateChecker::Result
StateChecker::Result::createStoredResult(
        IdealStateOperation::UP operation,
        MaintenancePriority::Priority priority)
{
    return Result(std::unique_ptr<ResultImpl>(new StoredResultImpl(std::move(operation), MaintenancePriority(priority))));
}

StateChecker::Context::Context(const DistributorNodeContext& node_ctx_in,
                               const DistributorStripeOperationContext& op_ctx_in,
                               const DistributorBucketSpace &distributorBucketSpace,
                               NodeMaintenanceStatsTracker& statsTracker,
                               const document::Bucket &bucket_)
    : bucket(bucket_),
      siblingBucket(op_ctx_in.get_sibling(bucket.getBucketId())),
      systemState(distributorBucketSpace.getClusterState()),
      pending_cluster_state(op_ctx_in.pending_cluster_state_or_null(bucket_.getBucketSpace())),
      distributorConfig(op_ctx_in.distributor_config()),
      distribution(distributorBucketSpace.getDistribution()),
      gcTimeCalculator(op_ctx_in.bucket_id_hasher(),
                       std::chrono::duration_cast<std::chrono::seconds>(distributorConfig.getGarbageCollectionInterval())),
      node_ctx(node_ctx_in),
      op_ctx(op_ctx_in),
      db(distributorBucketSpace.getBucketDatabase()),
      stats(statsTracker)
{
    // TODO STRIPE use existing cache for computing ideal storage nodes for bucket
    idealState = distribution.getIdealStorageNodes(systemState, bucket.getBucketId());
    unorderedIdealState.insert(idealState.begin(), idealState.end());
}

StateChecker::Context::~Context() = default;

std::string
StateChecker::Context::toString() const
{
    std::ostringstream ss;
    ss << "entries: {";

    for (uint32_t i = 0; i < entries.size(); ++i) {
        if (i != 0) {
            ss << ", ";
        }
        ss << entries[i].getBucketId() << ": [" << entries[i]->toString() << "]";
    }

    ss << "}, state: " << systemState;
    return ss.str();
}

StateChecker::StateChecker()  = default;
StateChecker::~StateChecker() = default;

}
<commit_msg>Use ideal state cache when populating StateChecker context<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "statechecker.h"
#include "distributor_bucket_space.h"
#include "distributor_stripe_component.h"
#include <vespa/vdslib/distribution/distribution.h>
#include <vespa/vdslib/state/clusterstate.h>

#include <vespa/log/log.h>
LOG_SETUP(".distributor.statechecker");

namespace storage::distributor {

namespace {

class StoredResultImpl
    : public StateChecker::ResultImpl
{
    mutable IdealStateOperation::UP _operation;
    MaintenancePriority _priority;
public:
    StoredResultImpl(const StoredResultImpl &) = delete;
    StoredResultImpl & operator = (const StoredResultImpl &) = delete;
    StoredResultImpl()
        : _operation(),
          _priority(MaintenancePriority::NO_MAINTENANCE_NEEDED)
    {}

    StoredResultImpl(IdealStateOperation::UP operation,
                     MaintenancePriority priority)
        : _operation(std::move(operation)),
          _priority(priority)
    {}

    IdealStateOperation::UP createOperation() override {
        return std::move(_operation);
    }

    MaintenancePriority getPriority() const override {
        return _priority;
    }

    MaintenanceOperation::Type getType() const override {
        assert(_operation.get());
        return _operation->getType();
    }
};

}

StateChecker::Result
StateChecker::Result::noMaintenanceNeeded()
{
    return Result(std::unique_ptr<ResultImpl>());
}

StateChecker::Result
StateChecker::Result::createStoredResult(
        IdealStateOperation::UP operation,
        MaintenancePriority::Priority priority)
{
    return Result(std::make_unique<StoredResultImpl>(std::move(operation), MaintenancePriority(priority)));
}

StateChecker::Context::Context(const DistributorNodeContext& node_ctx_in,
                               const DistributorStripeOperationContext& op_ctx_in,
                               const DistributorBucketSpace &distributorBucketSpace,
                               NodeMaintenanceStatsTracker& statsTracker,
                               const document::Bucket &bucket_)
    : bucket(bucket_),
      siblingBucket(op_ctx_in.get_sibling(bucket.getBucketId())),
      systemState(distributorBucketSpace.getClusterState()),
      pending_cluster_state(op_ctx_in.pending_cluster_state_or_null(bucket_.getBucketSpace())),
      distributorConfig(op_ctx_in.distributor_config()),
      distribution(distributorBucketSpace.getDistribution()),
      gcTimeCalculator(op_ctx_in.bucket_id_hasher(),
                       std::chrono::duration_cast<std::chrono::seconds>(distributorConfig.getGarbageCollectionInterval())),
      node_ctx(node_ctx_in),
      op_ctx(op_ctx_in),
      db(distributorBucketSpace.getBucketDatabase()),
      stats(statsTracker)
{
    idealState = distributorBucketSpace.get_ideal_service_layer_nodes_bundle(bucket.getBucketId()).get_available_nonretired_or_maintenance_nodes();
    unorderedIdealState.insert(idealState.begin(), idealState.end());
}

StateChecker::Context::~Context() = default;

std::string
StateChecker::Context::toString() const
{
    std::ostringstream ss;
    ss << "entries: {";

    for (uint32_t i = 0; i < entries.size(); ++i) {
        if (i != 0) {
            ss << ", ";
        }
        ss << entries[i].getBucketId() << ": [" << entries[i]->toString() << "]";
    }

    ss << "}, state: " << systemState;
    return ss.str();
}

StateChecker::StateChecker()  = default;
StateChecker::~StateChecker() = default;

}
<|endoftext|>


<commit_before>//=== InnerPointerChecker.cpp -------------------------------------*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a check that marks a raw pointer to a C++ container's
// inner buffer released when the object is destroyed. This information can
// be used by MallocChecker to detect use-after-free problems.
//
//===----------------------------------------------------------------------===//

#include "AllocationState.h"
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

// Associate container objects with a set of raw pointer symbols.
REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(PtrSet, SymbolRef);
REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)

namespace {

class InnerPointerChecker
    : public Checker<check::DeadSymbols, check::PostCall> {

  CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
      InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
      ShrinkToFitFn, SwapFn;

public:
  class InnerPointerBRVisitor : public BugReporterVisitor {
    SymbolRef PtrToBuf;

  public:
    InnerPointerBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}

    static void *getTag() {
      static int Tag = 0;
      return &Tag;
    }

    void Profile(llvm::FoldingSetNodeID &ID) const override {
      ID.AddPointer(getTag());
    }

    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                   const ExplodedNode *PrevN,
                                                   BugReporterContext &BRC,
                                                   BugReport &BR) override;

    // FIXME: Scan the map once in the visitor's constructor and do a direct
    // lookup by region.
    bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
      RawPtrMapTy Map = State->get<RawPtrMap>();
      for (const auto Entry : Map) {
        if (Entry.second.contains(Sym))
          return true;
      }
      return false;
    }
  };

  InnerPointerChecker()
      : AppendFn({"std", "basic_string", "append"}),
        AssignFn({"std", "basic_string", "assign"}),
        ClearFn({"std", "basic_string", "clear"}),
        CStrFn({"std", "basic_string", "c_str"}),
        DataFn({"std", "basic_string", "data"}),
        EraseFn({"std", "basic_string", "erase"}),
        InsertFn({"std", "basic_string", "insert"}),
        PopBackFn({"std", "basic_string", "pop_back"}),
        PushBackFn({"std", "basic_string", "push_back"}),
        ReplaceFn({"std", "basic_string", "replace"}),
        ReserveFn({"std", "basic_string", "reserve"}),
        ResizeFn({"std", "basic_string", "resize"}),
        ShrinkToFitFn({"std", "basic_string", "shrink_to_fit"}),
        SwapFn({"std", "basic_string", "swap"}) {}

  /// Check whether the called member function potentially invalidates
  /// pointers referring to the container object's inner buffer.
  bool isInvalidatingMemberFunction(const CallEvent &Call) const;

  /// Mark pointer symbols associated with the given memory region released
  /// in the program state.
  void markPtrSymbolsReleased(const CallEvent &Call, ProgramStateRef State,
                              const MemRegion *ObjRegion,
                              CheckerContext &C) const;

  /// Standard library functions that take a non-const `basic_string` argument by
  /// reference may invalidate its inner pointers. Check for these cases and
  /// mark the pointers released.
  void checkFunctionArguments(const CallEvent &Call, ProgramStateRef State,
                              CheckerContext &C) const;

  /// Record the connection between raw pointers referring to a container
  /// object's inner buffer and the object's memory region in the program state.
  /// Mark potentially invalidated pointers released.
  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;

  /// Clean up the program state map.
  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
};

} // end anonymous namespace

bool InnerPointerChecker::isInvalidatingMemberFunction(
        const CallEvent &Call) const {
  if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
    OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator();
    if (Opc == OO_Equal || Opc == OO_PlusEqual)
      return true;
    return false;
  }
  return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
          Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
          Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
          Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
          Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
          Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
          Call.isCalled(SwapFn));
}

void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,
                                                 ProgramStateRef State,
                                                 const MemRegion *MR,
                                                 CheckerContext &C) const {
  if (const PtrSet *PS = State->get<RawPtrMap>(MR)) {
    const Expr *Origin = Call.getOriginExpr();
    for (const auto Symbol : *PS) {
      // NOTE: `Origin` may be null, and will be stored so in the symbol's
      // `RefState` in MallocChecker's `RegionState` program state map.
      State = allocation_state::markReleased(State, Symbol, Origin);
    }
    State = State->remove<RawPtrMap>(MR);
    C.addTransition(State);
    return;
  }
}

void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
                                                 ProgramStateRef State,
                                                 CheckerContext &C) const {
  if (const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
    const FunctionDecl *FD = FC->getDecl();
    if (!FD || !FD->isInStdNamespace())
      return;

    for (unsigned I = 0, E = FD->getNumParams(); I != E; ++I) {
      QualType ParamTy = FD->getParamDecl(I)->getType();
      if (!ParamTy->isReferenceType() ||
          ParamTy->getPointeeType().isConstQualified())
        continue;

      // In case of member operator calls, `this` is counted as an
      // argument but not as a parameter.
      bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
      unsigned ArgI = isaMemberOpCall ? I+1 : I;

      SVal Arg = FC->getArgSVal(ArgI);
      const auto *ArgRegion =
          dyn_cast_or_null<TypedValueRegion>(Arg.getAsRegion());
      if (!ArgRegion)
        continue;

      markPtrSymbolsReleased(Call, State, ArgRegion, C);
    }
  }
}

// [string.require]
//
// "References, pointers, and iterators referring to the elements of a
// basic_string sequence may be invalidated by the following uses of that
// basic_string object:
//
// -- As an argument to any standard library function taking a reference
// to non-const basic_string as an argument. For example, as an argument to
// non-member functions swap(), operator>>(), and getline(), or as an argument
// to basic_string::swap().
//
// -- Calling non-const member functions, except operator[], at, front, back,
// begin, rbegin, end, and rend."

void InnerPointerChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
    // TODO: Do we need these to be typed?
    const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
        ICall->getCXXThisVal().getAsRegion());
    if (!ObjRegion)
      return;

    if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
      SVal RawPtr = Call.getReturnValue();
      if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
        // Start tracking this raw pointer by adding it to the set of symbols
        // associated with this container object in the program state map.

        PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
        const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
        PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
        assert(C.wasInlined || !Set.contains(Sym));
        Set = F.add(Set, Sym);

        State = State->set<RawPtrMap>(ObjRegion, Set);
        C.addTransition(State);
      }
      return;
    }

    // Check [string.require] / second point.
    if (isInvalidatingMemberFunction(Call)) {
      markPtrSymbolsReleased(Call, State, ObjRegion, C);
      return;
    }
  }

  // Check [string.require] / first point.
  checkFunctionArguments(Call, State, C);
}

void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                           CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
  RawPtrMapTy RPM = State->get<RawPtrMap>();
  for (const auto Entry : RPM) {
    if (!SymReaper.isLiveRegion(Entry.first)) {
      // Due to incomplete destructor support, some dead regions might
      // remain in the program state map. Clean them up.
      State = State->remove<RawPtrMap>(Entry.first);
    }
    if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
      PtrSet CleanedUpSet = *OldSet;
      for (const auto Symbol : Entry.second) {
        if (!SymReaper.isLive(Symbol))
          CleanedUpSet = F.remove(CleanedUpSet, Symbol);
      }
      State = CleanedUpSet.isEmpty()
                  ? State->remove<RawPtrMap>(Entry.first)
                  : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
    }
  }
  C.addTransition(State);
}

namespace clang {
namespace ento {
namespace allocation_state {

std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
  return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
}

const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
  RawPtrMapTy Map = State->get<RawPtrMap>();
  for (const auto Entry : Map) {
    if (Entry.second.contains(Sym)) {
      return Entry.first;
    }
  }
  return nullptr;
}

} // end namespace allocation_state
} // end namespace ento
} // end namespace clang

std::shared_ptr<PathDiagnosticPiece>
InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
                                                      const ExplodedNode *PrevN,
                                                      BugReporterContext &BRC,
                                                      BugReport &BR) {
  if (!isSymbolTracked(N->getState(), PtrToBuf) ||
      isSymbolTracked(PrevN->getState(), PtrToBuf))
    return nullptr;

  const Stmt *S = PathDiagnosticLocation::getStmt(N);
  if (!S)
    return nullptr;

  const MemRegion *ObjRegion =
      allocation_state::getContainerObjRegion(N->getState(), PtrToBuf);
  const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
  QualType ObjTy = TypedRegion->getValueType();

  SmallString<256> Buf;
  llvm::raw_svector_ostream OS(Buf);
  OS << "Pointer to inner buffer of '" << ObjTy.getAsString()
     << "' obtained here";
  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
                             N->getLocationContext());
  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
                                                    nullptr);
}

void ento::registerInnerPointerChecker(CheckerManager &Mgr) {
  registerInnerPointerCheckerAux(Mgr);
  Mgr.registerChecker<InnerPointerChecker>();
}
<commit_msg>Removed extra semicolon to fix Wpedantic. (NFCI).<commit_after>//=== InnerPointerChecker.cpp -------------------------------------*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a check that marks a raw pointer to a C++ container's
// inner buffer released when the object is destroyed. This information can
// be used by MallocChecker to detect use-after-free problems.
//
//===----------------------------------------------------------------------===//

#include "AllocationState.h"
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

// Associate container objects with a set of raw pointer symbols.
REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(PtrSet, SymbolRef)
REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)

namespace {

class InnerPointerChecker
    : public Checker<check::DeadSymbols, check::PostCall> {

  CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
      InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
      ShrinkToFitFn, SwapFn;

public:
  class InnerPointerBRVisitor : public BugReporterVisitor {
    SymbolRef PtrToBuf;

  public:
    InnerPointerBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}

    static void *getTag() {
      static int Tag = 0;
      return &Tag;
    }

    void Profile(llvm::FoldingSetNodeID &ID) const override {
      ID.AddPointer(getTag());
    }

    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                   const ExplodedNode *PrevN,
                                                   BugReporterContext &BRC,
                                                   BugReport &BR) override;

    // FIXME: Scan the map once in the visitor's constructor and do a direct
    // lookup by region.
    bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
      RawPtrMapTy Map = State->get<RawPtrMap>();
      for (const auto Entry : Map) {
        if (Entry.second.contains(Sym))
          return true;
      }
      return false;
    }
  };

  InnerPointerChecker()
      : AppendFn({"std", "basic_string", "append"}),
        AssignFn({"std", "basic_string", "assign"}),
        ClearFn({"std", "basic_string", "clear"}),
        CStrFn({"std", "basic_string", "c_str"}),
        DataFn({"std", "basic_string", "data"}),
        EraseFn({"std", "basic_string", "erase"}),
        InsertFn({"std", "basic_string", "insert"}),
        PopBackFn({"std", "basic_string", "pop_back"}),
        PushBackFn({"std", "basic_string", "push_back"}),
        ReplaceFn({"std", "basic_string", "replace"}),
        ReserveFn({"std", "basic_string", "reserve"}),
        ResizeFn({"std", "basic_string", "resize"}),
        ShrinkToFitFn({"std", "basic_string", "shrink_to_fit"}),
        SwapFn({"std", "basic_string", "swap"}) {}

  /// Check whether the called member function potentially invalidates
  /// pointers referring to the container object's inner buffer.
  bool isInvalidatingMemberFunction(const CallEvent &Call) const;

  /// Mark pointer symbols associated with the given memory region released
  /// in the program state.
  void markPtrSymbolsReleased(const CallEvent &Call, ProgramStateRef State,
                              const MemRegion *ObjRegion,
                              CheckerContext &C) const;

  /// Standard library functions that take a non-const `basic_string` argument by
  /// reference may invalidate its inner pointers. Check for these cases and
  /// mark the pointers released.
  void checkFunctionArguments(const CallEvent &Call, ProgramStateRef State,
                              CheckerContext &C) const;

  /// Record the connection between raw pointers referring to a container
  /// object's inner buffer and the object's memory region in the program state.
  /// Mark potentially invalidated pointers released.
  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;

  /// Clean up the program state map.
  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
};

} // end anonymous namespace

bool InnerPointerChecker::isInvalidatingMemberFunction(
        const CallEvent &Call) const {
  if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
    OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator();
    if (Opc == OO_Equal || Opc == OO_PlusEqual)
      return true;
    return false;
  }
  return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
          Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
          Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
          Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
          Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
          Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
          Call.isCalled(SwapFn));
}

void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,
                                                 ProgramStateRef State,
                                                 const MemRegion *MR,
                                                 CheckerContext &C) const {
  if (const PtrSet *PS = State->get<RawPtrMap>(MR)) {
    const Expr *Origin = Call.getOriginExpr();
    for (const auto Symbol : *PS) {
      // NOTE: `Origin` may be null, and will be stored so in the symbol's
      // `RefState` in MallocChecker's `RegionState` program state map.
      State = allocation_state::markReleased(State, Symbol, Origin);
    }
    State = State->remove<RawPtrMap>(MR);
    C.addTransition(State);
    return;
  }
}

void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
                                                 ProgramStateRef State,
                                                 CheckerContext &C) const {
  if (const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
    const FunctionDecl *FD = FC->getDecl();
    if (!FD || !FD->isInStdNamespace())
      return;

    for (unsigned I = 0, E = FD->getNumParams(); I != E; ++I) {
      QualType ParamTy = FD->getParamDecl(I)->getType();
      if (!ParamTy->isReferenceType() ||
          ParamTy->getPointeeType().isConstQualified())
        continue;

      // In case of member operator calls, `this` is counted as an
      // argument but not as a parameter.
      bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
      unsigned ArgI = isaMemberOpCall ? I+1 : I;

      SVal Arg = FC->getArgSVal(ArgI);
      const auto *ArgRegion =
          dyn_cast_or_null<TypedValueRegion>(Arg.getAsRegion());
      if (!ArgRegion)
        continue;

      markPtrSymbolsReleased(Call, State, ArgRegion, C);
    }
  }
}

// [string.require]
//
// "References, pointers, and iterators referring to the elements of a
// basic_string sequence may be invalidated by the following uses of that
// basic_string object:
//
// -- As an argument to any standard library function taking a reference
// to non-const basic_string as an argument. For example, as an argument to
// non-member functions swap(), operator>>(), and getline(), or as an argument
// to basic_string::swap().
//
// -- Calling non-const member functions, except operator[], at, front, back,
// begin, rbegin, end, and rend."

void InnerPointerChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const {
  ProgramStateRef State = C.getState();

  if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
    // TODO: Do we need these to be typed?
    const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
        ICall->getCXXThisVal().getAsRegion());
    if (!ObjRegion)
      return;

    if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
      SVal RawPtr = Call.getReturnValue();
      if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
        // Start tracking this raw pointer by adding it to the set of symbols
        // associated with this container object in the program state map.

        PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
        const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
        PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
        assert(C.wasInlined || !Set.contains(Sym));
        Set = F.add(Set, Sym);

        State = State->set<RawPtrMap>(ObjRegion, Set);
        C.addTransition(State);
      }
      return;
    }

    // Check [string.require] / second point.
    if (isInvalidatingMemberFunction(Call)) {
      markPtrSymbolsReleased(Call, State, ObjRegion, C);
      return;
    }
  }

  // Check [string.require] / first point.
  checkFunctionArguments(Call, State, C);
}

void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                           CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
  RawPtrMapTy RPM = State->get<RawPtrMap>();
  for (const auto Entry : RPM) {
    if (!SymReaper.isLiveRegion(Entry.first)) {
      // Due to incomplete destructor support, some dead regions might
      // remain in the program state map. Clean them up.
      State = State->remove<RawPtrMap>(Entry.first);
    }
    if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
      PtrSet CleanedUpSet = *OldSet;
      for (const auto Symbol : Entry.second) {
        if (!SymReaper.isLive(Symbol))
          CleanedUpSet = F.remove(CleanedUpSet, Symbol);
      }
      State = CleanedUpSet.isEmpty()
                  ? State->remove<RawPtrMap>(Entry.first)
                  : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
    }
  }
  C.addTransition(State);
}

namespace clang {
namespace ento {
namespace allocation_state {

std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
  return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
}

const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
  RawPtrMapTy Map = State->get<RawPtrMap>();
  for (const auto Entry : Map) {
    if (Entry.second.contains(Sym)) {
      return Entry.first;
    }
  }
  return nullptr;
}

} // end namespace allocation_state
} // end namespace ento
} // end namespace clang

std::shared_ptr<PathDiagnosticPiece>
InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
                                                      const ExplodedNode *PrevN,
                                                      BugReporterContext &BRC,
                                                      BugReport &BR) {
  if (!isSymbolTracked(N->getState(), PtrToBuf) ||
      isSymbolTracked(PrevN->getState(), PtrToBuf))
    return nullptr;

  const Stmt *S = PathDiagnosticLocation::getStmt(N);
  if (!S)
    return nullptr;

  const MemRegion *ObjRegion =
      allocation_state::getContainerObjRegion(N->getState(), PtrToBuf);
  const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
  QualType ObjTy = TypedRegion->getValueType();

  SmallString<256> Buf;
  llvm::raw_svector_ostream OS(Buf);
  OS << "Pointer to inner buffer of '" << ObjTy.getAsString()
     << "' obtained here";
  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
                             N->getLocationContext());
  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
                                                    nullptr);
}

void ento::registerInnerPointerChecker(CheckerManager &Mgr) {
  registerInnerPointerCheckerAux(Mgr);
  Mgr.registerChecker<InnerPointerChecker>();
}
<|endoftext|>


<commit_before>//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines NonNullParamChecker, which checks for arguments expected not to
// be null due to:
//   - the corresponding parameters being declared to have nonnull attribute
//   - the corresponding parameters being references; since the call would form
//     a reference to a null pointer
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class NonNullParamChecker
  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
  mutable std::unique_ptr<BugType> BTAttrNonNull;
  mutable std::unique_ptr<BugType> BTNullRefArg;

public:

  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

  std::unique_ptr<BugReport>
  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
  std::unique_ptr<BugReport>
  genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
                                  const Expr *ArgE) const;
};
} // end anonymous namespace

void NonNullParamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  const Decl *FD = Call.getDecl();
  if (!FD)
    return;

  // Merge all non-null attributes
  unsigned NumArgs = Call.getNumArgs();
  llvm::SmallBitVector AttrNonNull(NumArgs);
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
    if (!NonNull->args_size()) {
      AttrNonNull.set(0, NumArgs);
      break;
    }
    for (unsigned Val : NonNull->args()) {
      if (Val >= NumArgs)
        continue;
      AttrNonNull.set(Val);
    }
  }

  ProgramStateRef state = C.getState();

  CallEvent::param_type_iterator TyI = Call.param_type_begin(),
                                 TyE = Call.param_type_end();

  for (unsigned idx = 0; idx < NumArgs; ++idx) {

    // Check if the parameter is a reference. We want to report when reference
    // to a null pointer is passed as a parameter.
    bool haveRefTypeParam = false;
    if (TyI != TyE) {
      haveRefTypeParam = (*TyI)->isReferenceType();
      TyI++;
    }

    bool haveAttrNonNull = AttrNonNull[idx];
    if (!haveAttrNonNull) {
      // Check if the parameter is also marked 'nonnull'.
      ArrayRef<ParmVarDecl*> parms = Call.parameters();
      if (idx < parms.size())
        haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
    }

    if (!haveRefTypeParam && !haveAttrNonNull)
      continue;

    // If the value is unknown or undefined, we can't perform this check.
    const Expr *ArgE = Call.getArgExpr(idx);
    SVal V = Call.getArgSVal(idx);
    Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
    if (!DV)
      continue;

    // Process the case when the argument is not a location.
    assert(!haveRefTypeParam || DV->getAs<Loc>());

    if (haveAttrNonNull && !DV->getAs<Loc>()) {
      // If the argument is a union type, we want to handle a potential
      // transparent_union GCC extension.
      if (!ArgE)
        continue;

      QualType T = ArgE->getType();
      const RecordType *UT = T->getAsUnionType();
      if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
        continue;

      if (Optional<nonloc::CompoundVal> CSV =
              DV->getAs<nonloc::CompoundVal>()) {
        nonloc::CompoundVal::iterator CSV_I = CSV->begin();
        assert(CSV_I != CSV->end());
        V = *CSV_I;
        DV = V.getAs<DefinedSVal>();
        assert(++CSV_I == CSV->end());
        // FIXME: Handle (some_union){ some_other_union_val }, which turns into
        // a LazyCompoundVal inside a CompoundVal.
        if (!V.getAs<Loc>())
          continue;
        // Retrieve the corresponding expression.
        if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
          if (const InitListExpr *IE =
                dyn_cast<InitListExpr>(CE->getInitializer()))
             ArgE = dyn_cast<Expr>(*(IE->begin()));

      } else {
        // FIXME: Handle LazyCompoundVals?
        continue;
      }
    }

    ConstraintManager &CM = C.getConstraintManager();
    ProgramStateRef stateNotNull, stateNull;
    std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);

    if (stateNull) {
      if (!stateNotNull) {
        // Generate an error node.  Check for a null node in case
        // we cache out.
        if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {

          std::unique_ptr<BugReport> R;
          if (haveAttrNonNull)
            R = genReportNullAttrNonNull(errorNode, ArgE);
          else if (haveRefTypeParam)
            R = genReportReferenceToNullPointer(errorNode, ArgE);

          // Highlight the range of the argument that was null.
          R->addRange(Call.getArgSourceRange(idx));

          // Emit the bug report.
          C.emitReport(std::move(R));
        }

        // Always return.  Either we cached out or we just emitted an error.
        return;
      }
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
        ImplicitNullDerefEvent event = {
            V, false, N, &C.getBugReporter(),
            /*IsDirectDereference=*/haveRefTypeParam};
        dispatchEvent(event);
      }
    }

    // If a pointer value passed the check we should assume that it is
    // indeed not null from this point forward.
    assert(stateNotNull);
    state = stateNotNull;
  }

  // If we reach here all of the arguments passed the nonnull check.
  // If 'state' has been updated generated a new node.
  C.addTransition(state);
}

std::unique_ptr<BugReport>
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
                                              const Expr *ArgE) const {
  // Lazily allocate the BugType object if it hasn't already been
  // created. Ownership is transferred to the BugReporter object once
  // the BugReport is passed to 'EmitWarning'.
  if (!BTAttrNonNull)
    BTAttrNonNull.reset(new BugType(
        this, "Argument with 'nonnull' attribute passed null", "API"));

  auto R = llvm::make_unique<BugReport>(
      *BTAttrNonNull,
      "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
  if (ArgE)
    bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);

  return R;
}

std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
    const ExplodedNode *ErrorNode, const Expr *ArgE) const {
  if (!BTNullRefArg)
    BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));

  auto R = llvm::make_unique<BugReport>(
      *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
  if (ArgE) {
    const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
    if (!ArgEDeref)
      ArgEDeref = ArgE;
    bugreporter::trackNullOrUndefValue(ErrorNode,
                                       ArgEDeref,
                                       *R);
  }
  return R;

}

void ento::registerNonNullParamChecker(CheckerManager &mgr) {
  mgr.registerChecker<NonNullParamChecker>();
}
<commit_msg>[analyzer] [NFC] Minor refactoring of NonNullParamChecker<commit_after>//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines NonNullParamChecker, which checks for arguments expected not to
// be null due to:
//   - the corresponding parameters being declared to have nonnull attribute
//   - the corresponding parameters being references; since the call would form
//     a reference to a null pointer
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckers.h"
#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class NonNullParamChecker
  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
  mutable std::unique_ptr<BugType> BTAttrNonNull;
  mutable std::unique_ptr<BugType> BTNullRefArg;

public:

  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

  std::unique_ptr<BugReport>
  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
  std::unique_ptr<BugReport>
  genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
                                  const Expr *ArgE) const;
};
} // end anonymous namespace

/// \return Bitvector marking non-null attributes.
static llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
  const Decl *FD = Call.getDecl();
  unsigned NumArgs = Call.getNumArgs();
  llvm::SmallBitVector AttrNonNull(NumArgs);
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
    if (!NonNull->args_size()) {
      AttrNonNull.set(0, NumArgs);
      break;
    }
    for (unsigned Val : NonNull->args()) {
      if (Val >= NumArgs)
        continue;
      AttrNonNull.set(Val);
    }
  }
  return AttrNonNull;
}

void NonNullParamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  if (!Call.getDecl())
    return;

  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
  unsigned NumArgs = Call.getNumArgs();

  ProgramStateRef state = C.getState();
  ArrayRef<ParmVarDecl*> parms = Call.parameters();

  for (unsigned idx = 0; idx < NumArgs; ++idx) {
    // For vararg functions, a corresponding parameter decl may not exist.
    bool HasParam = idx < parms.size();

    // Check if the parameter is a reference. We want to report when reference
    // to a null pointer is passed as a parameter.
    bool haveRefTypeParam =
        HasParam ? parms[idx]->getType()->isReferenceType() : false;
    bool haveAttrNonNull = AttrNonNull[idx];

    // Check if the parameter is also marked 'nonnull'.
    if (!haveAttrNonNull && HasParam)
      haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();

    if (!haveAttrNonNull && !haveRefTypeParam)
      continue;

    // If the value is unknown or undefined, we can't perform this check.
    const Expr *ArgE = Call.getArgExpr(idx);
    SVal V = Call.getArgSVal(idx);
    auto DV = V.getAs<DefinedSVal>();
    if (!DV)
      continue;

    assert(!haveRefTypeParam || DV->getAs<Loc>());

    // Process the case when the argument is not a location.
    if (haveAttrNonNull && !DV->getAs<Loc>()) {
      // If the argument is a union type, we want to handle a potential
      // transparent_union GCC extension.
      if (!ArgE)
        continue;

      QualType T = ArgE->getType();
      const RecordType *UT = T->getAsUnionType();
      if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
        continue;

      auto CSV = DV->getAs<nonloc::CompoundVal>();

      // FIXME: Handle LazyCompoundVals?
      if (!CSV)
        continue;

      V = *(CSV->begin());
      DV = V.getAs<DefinedSVal>();
      assert(++CSV->begin() == CSV->end());
      // FIXME: Handle (some_union){ some_other_union_val }, which turns into
      // a LazyCompoundVal inside a CompoundVal.
      if (!V.getAs<Loc>())
        continue;

      // Retrieve the corresponding expression.
      if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
        if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
          ArgE = dyn_cast<Expr>(*(IE->begin()));
    }

    ConstraintManager &CM = C.getConstraintManager();
    ProgramStateRef stateNotNull, stateNull;
    std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);

    // Generate an error node.  Check for a null node in case
    // we cache out.
    if (stateNull && !stateNotNull) {
      if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {

        std::unique_ptr<BugReport> R;
        if (haveAttrNonNull)
          R = genReportNullAttrNonNull(errorNode, ArgE);
        else if (haveRefTypeParam)
          R = genReportReferenceToNullPointer(errorNode, ArgE);

        // Highlight the range of the argument that was null.
        R->addRange(Call.getArgSourceRange(idx));

        // Emit the bug report.
        C.emitReport(std::move(R));
      }

      // Always return.  Either we cached out or we just emitted an error.
      return;
    }

    if (stateNull) {
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
        ImplicitNullDerefEvent event = {
          V, false, N, &C.getBugReporter(),
          /*IsDirectDereference=*/haveRefTypeParam};
        dispatchEvent(event);
      }
    }

    // If a pointer value passed the check we should assume that it is
    // indeed not null from this point forward.
    state = stateNotNull;
  }

  // If we reach here all of the arguments passed the nonnull check.
  // If 'state' has been updated generated a new node.
  C.addTransition(state);
}

std::unique_ptr<BugReport>
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
                                              const Expr *ArgE) const {
  // Lazily allocate the BugType object if it hasn't already been
  // created. Ownership is transferred to the BugReporter object once
  // the BugReport is passed to 'EmitWarning'.
  if (!BTAttrNonNull)
    BTAttrNonNull.reset(new BugType(
        this, "Argument with 'nonnull' attribute passed null", "API"));

  auto R = llvm::make_unique<BugReport>(
      *BTAttrNonNull,
      "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
  if (ArgE)
    bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);

  return R;
}

std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
    const ExplodedNode *ErrorNode, const Expr *ArgE) const {
  if (!BTNullRefArg)
    BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));

  auto R = llvm::make_unique<BugReport>(
      *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
  if (ArgE) {
    const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
    if (!ArgEDeref)
      ArgEDeref = ArgE;
    bugreporter::trackNullOrUndefValue(ErrorNode,
                                       ArgEDeref,
                                       *R);
  }
  return R;

}

void ento::registerNonNullParamChecker(CheckerManager &mgr) {
  mgr.registerChecker<NonNullParamChecker>();
}
<|endoftext|>


<commit_before>#include "gm.h"

GameStateManager::GameStateManager()
{
	playerShipMap = Map(10, 10);
	enemyShipMap  = Map(10, 10);
	playerShotMap = Map(10, 10);

	// Set up the ships
	playerShips[SHIP_CARRIER]   = enemyShips[SHIP_CARRIER]   = Ship();
	playerShips[SHIP_BATTLE]    = enemyShips[SHIP_BATTLE]    = Ship();
	playerShips[SHIP_CRUISER]   = enemyShips[SHIP_CRUISER]   = Ship();
	playerShips[SHIP_SUBMARINE] = enemyShips[SHIP_SUBMARINE] = Ship();
	playerShips[SHIP_DESTROYER] = enemyShips[SHIP_DESTROYER] = Ship();
}

GameStateManager::~GameStateManager()
{
}

void GameStateManager::main()
{
	while (!gameOver)
	{
		update();
		ui::draw(playerShipMap, playerShotMap, statusMsg);
		getInput();
	}
	if (enemyShipsLeft <= 0)
	{
		ui::clear();
		puts("!!You Win!!");
	}

	if (playerShipsLeft <= 0)
	{
		ui::clear();
		puts("!!You Lose!!");
	}

}

void GameStateManager::update()
{
	if (turn == -2)
	{
		switch (playerShipsLeft)
		{
			case SHIP_CARRIER:
				print("Place your carrier!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_CARRIER);
					if (ship.isValid())
					{
						playerShips[SHIP_CARRIER] = ship;
						playerShipsLeft++; // We placed the ship, go ahead and inc
						print("Place your battleship!");
					}

				}
				break;
			case SHIP_BATTLE:
				print("Place your battleship!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_BATTLE);
					if (ship.isValid())
					{
						playerShips[SHIP_BATTLE] = ship;
						playerShipsLeft++;
						print("Place your cruiser!");
					}
				}
				break;
			case SHIP_CRUISER:
				print("Place your cruiser!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_CRUISER);
					if (ship.isValid())
					{
						playerShips[SHIP_CRUISER] = ship;
						playerShipsLeft++;
						print("Place your submarine!");
					}
				}
				break;
			case SHIP_SUBMARINE:
				print("Place your submarine!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_SUBMARINE);
					if (ship.isValid())
					{
						playerShips[SHIP_SUBMARINE] = ship;
						playerShipsLeft++;
						print("Place your destroyer!");
					}
				}
				break;
			case SHIP_DESTROYER:
				print("Place your destroyer!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_DESTROYER);
					if (ship.isValid())
						turn = -1;
					// Reset targSpot
					playerTargetPos = Vec2(-1, -1);
				}
				break;
		}
	}

	if (turn == -1)
	{
		print("Computer placing ships, please wait...");
		printf("Enemyships: %d\n", enemyShipsLeft);
		for (int i = 0; i <= 5; i++)
		{
		switch (enemyShipsLeft)
		{
			case SHIP_CARRIER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 9), DIR_WEST, SHIP_CARRIER);
				if (ship.isValid())
				{
					enemyShips[SHIP_CARRIER] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_BATTLE:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 8), DIR_WEST, SHIP_BATTLE);
				if (ship.isValid())
				{
					enemyShips[SHIP_BATTLE] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_CRUISER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 7), DIR_WEST, SHIP_CRUISER);
				if (ship.isValid())
				{
					enemyShips[SHIP_CRUISER] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_SUBMARINE:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 6), DIR_WEST, SHIP_SUBMARINE);
				if (ship.isValid())
				{
					enemyShips[SHIP_SUBMARINE] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_DESTROYER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 5), DIR_WEST, SHIP_DESTROYER);
				if (ship.isValid())
				{
					enemyShips[SHIP_DESTROYER] = ship;
					enemyShipsLeft++;
					turn = 0;
				}
				break;
			}
		}
		}
	}

	if (turn == 0)
	{
		print("Player's turn! Enter coords for attack or a command!");
		if (playerTargetPos.inBounds())
		{
			// See if we already tried here
			switch (playerShotMap.getNode(playerTargetPos))
			{
				case STATE_HIT:
				case STATE_MISS:
					print("Already attacked coords, try another!");
					return;
				default: break;
			}

			switch (enemyShipMap.getNode(playerTargetPos))
			{
				case STATE_EMPTY:
					playerShotMap.setNode(playerTargetPos, STATE_MISS);
					error("Missed!");
					break;
				case STATE_SHIP:
					playerShotMap.setNode(playerTargetPos, STATE_HIT);
					switch (getHitShip(ENEMY))
					{
						case SHIP_CARRIER:
							enemyShips[SHIP_CARRIER].hit();
							if (!enemyShips[SHIP_CARRIER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's carrier!");
							}
							break;
						case SHIP_BATTLE:
							enemyShips[SHIP_BATTLE].hit();
							if (!enemyShips[SHIP_BATTLE].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's battleship!");
							}
							break;
						case SHIP_CRUISER:
							enemyShips[SHIP_CRUISER].hit();
							if (!enemyShips[SHIP_CRUISER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's cruiser!");
							}
							break;
						case SHIP_SUBMARINE:
							enemyShips[SHIP_SUBMARINE].hit();
							if (!enemyShips[SHIP_SUBMARINE].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's submarine!");
							}
							break;
						case SHIP_DESTROYER:
							enemyShips[SHIP_DESTROYER].hit();
							if (!enemyShips[SHIP_DESTROYER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's destroyer!");
							}
							break;
						default: error("Something went terribly wrong in the enemy ship hit code!"); break;
					}
					break;
				default:
					error("Something just went terribly wrong! gm.cpp:192");
					break;
			}
		}
	}

	if (turn >= 0)
	{
		if (playerShipsLeft <= 0 || enemyShipsLeft <= 0)
			gameOver = true;
	}

	/* Reset state variables */
	playerShipDirection = DIR_NONE;
	playerTargetPos = Vec2(-1, -1);
	if (statusMsgRedrawOverride)
	{
		statusMsgRedrawOverride = false;
	}
}

void GameStateManager::handleCommand(strVec commandList)
{
	if (commandList.empty())
		return;

	if (commandList.size() == 1)
	{ // Handle 0 arg commands
		if (commandList[0] == "quit" || commandList[0] == "q" || commandList[0] == "sd")
		{
			gameOver = true;
		}
		else
		{
			playerTargetPos = util::parseCoords(commandList[0]);
			if (playerTargetPos.x == -1 || playerTargetPos.y == -1)
			{
				error("Invalid coordinates!");
				return;
			}
		}
	} else
	if (commandList.size() == 2)
	{ // Handle single argument commands
		if (commandList[1] == "north" || commandList[1] == "south" || commandList[1] == "east" || commandList[1] == "west")
		{
			playerTargetPos = util::parseCoords(commandList[0]);
			if (playerTargetPos.x == -1 || playerTargetPos.y == -1)
			{
				error("Invalid coordinates!");
				return;
			}

			if (commandList[1] == "north") playerShipDirection = DIR_NORTH; else
			if (commandList[1] == "south") playerShipDirection = DIR_SOUTH; else
			if (commandList[1] == "west")  playerShipDirection = DIR_WEST; else
			if (commandList[1] == "east")  playerShipDirection = DIR_EAST;

			return;
		}
		else
			goto invalidCommand;
	}
	else
	invalidCommand:
		error("Invalid command!");
}

void GameStateManager::getInput()
{
	if (!gameOver)
	{
		std::string rawCommand;
		std::getline(std::cin, rawCommand);

		strVec commandList;
		commandList = util::parse(rawCommand);

		handleCommand(commandList);
	}
}

void GameStateManager::print(std::string msg)
{ // Helper to print info to the status bar
	statusMsg = msg;
}

void GameStateManager::error(std::string msg)
{
	statusMsgRedrawOverride = true;
	statusMsg = msg;
}

ShipType GameStateManager::getHitShip(Team team)
{
	if (team == ENEMY)
	{
		for (int i = 0; i <= 5; i++)
		{
			if (enemyShips[i].contains(playerTargetPos))
			{
				return enemyShips[i].type;
			}
		}
	} else
	if (team == PLAYER)
	{
		for (int i = 0; i <= 5; i++)
		{
			if (playerShips[i].contains(enemyTargetPos))
			{
				return playerShips[i].type;
			}
		}
	}
	return SHIP_NULL;
}

void GameStateManager::test()
{ // Sets 5,5 to be different states on all 3 maps, then confirms it is indeed that
	playerShipMap.setNode(5,5, STATE_MISS);
	enemyShipMap.setNode(5,5, STATE_HIT);
	playerShotMap.setNode(5,5, STATE_SHIP);

	if (playerShipMap.getNode(5,5) == STATE_MISS)
		puts("Successfully set playerShipMap!");
	if (enemyShipMap.getNode(5,5) == STATE_HIT)
		puts("Successfully set enemyShipMap!");
	if (playerShotMap.getNode(5,5) == STATE_SHIP)
		puts("Successfully set playerShotMap!");
	ui::draw(playerShipMap, playerShotMap, "AUGH!");
}
<commit_msg>implemented nswe along-side full direction names<commit_after>#include "gm.h"

GameStateManager::GameStateManager()
{
	playerShipMap = Map(10, 10);
	enemyShipMap  = Map(10, 10);
	playerShotMap = Map(10, 10);

	// Set up the ships
	playerShips[SHIP_CARRIER]   = enemyShips[SHIP_CARRIER]   = Ship();
	playerShips[SHIP_BATTLE]    = enemyShips[SHIP_BATTLE]    = Ship();
	playerShips[SHIP_CRUISER]   = enemyShips[SHIP_CRUISER]   = Ship();
	playerShips[SHIP_SUBMARINE] = enemyShips[SHIP_SUBMARINE] = Ship();
	playerShips[SHIP_DESTROYER] = enemyShips[SHIP_DESTROYER] = Ship();
}

GameStateManager::~GameStateManager()
{
}

void GameStateManager::main()
{
	while (!gameOver)
	{
		update();
		ui::draw(playerShipMap, playerShotMap, statusMsg);
		getInput();
	}
	if (enemyShipsLeft <= 0)
	{
		ui::clear();
		puts("!!You Win!!");
	}

	if (playerShipsLeft <= 0)
	{
		ui::clear();
		puts("!!You Lose!!");
	}

}

void GameStateManager::update()
{
	if (turn == -2)
	{
		switch (playerShipsLeft)
		{
			case SHIP_CARRIER:
				print("Place your carrier!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_CARRIER);
					if (ship.isValid())
					{
						playerShips[SHIP_CARRIER] = ship;
						playerShipsLeft++; // We placed the ship, go ahead and inc
						print("Place your battleship!");
					}

				}
				break;
			case SHIP_BATTLE:
				print("Place your battleship!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_BATTLE);
					if (ship.isValid())
					{
						playerShips[SHIP_BATTLE] = ship;
						playerShipsLeft++;
						print("Place your cruiser!");
					}
				}
				break;
			case SHIP_CRUISER:
				print("Place your cruiser!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_CRUISER);
					if (ship.isValid())
					{
						playerShips[SHIP_CRUISER] = ship;
						playerShipsLeft++;
						print("Place your submarine!");
					}
				}
				break;
			case SHIP_SUBMARINE:
				print("Place your submarine!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_SUBMARINE);
					if (ship.isValid())
					{
						playerShips[SHIP_SUBMARINE] = ship;
						playerShipsLeft++;
						print("Place your destroyer!");
					}
				}
				break;
			case SHIP_DESTROYER:
				print("Place your destroyer!");
				if (playerShipDirection != DIR_NONE)
				{
					Ship ship = playerShipMap.addShip(playerTargetPos, playerShipDirection, SHIP_DESTROYER);
					if (ship.isValid())
						turn = -1;
					// Reset targSpot
					playerTargetPos = Vec2(-1, -1);
				}
				break;
		}
	}

	if (turn == -1)
	{
		print("Computer placing ships, please wait...");
		printf("Enemyships: %d\n", enemyShipsLeft);
		for (int i = 0; i <= 5; i++)
		{
		switch (enemyShipsLeft)
		{
			case SHIP_CARRIER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 9), DIR_WEST, SHIP_CARRIER);
				if (ship.isValid())
				{
					enemyShips[SHIP_CARRIER] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_BATTLE:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 8), DIR_WEST, SHIP_BATTLE);
				if (ship.isValid())
				{
					enemyShips[SHIP_BATTLE] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_CRUISER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 7), DIR_WEST, SHIP_CRUISER);
				if (ship.isValid())
				{
					enemyShips[SHIP_CRUISER] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_SUBMARINE:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 6), DIR_WEST, SHIP_SUBMARINE);
				if (ship.isValid())
				{
					enemyShips[SHIP_SUBMARINE] = ship;
					enemyShipsLeft++;
				}
				break;
			}
			case SHIP_DESTROYER:
			{
				Ship ship = enemyShipMap.addShip(Vec2(9, 5), DIR_WEST, SHIP_DESTROYER);
				if (ship.isValid())
				{
					enemyShips[SHIP_DESTROYER] = ship;
					enemyShipsLeft++;
					turn = 0;
				}
				break;
			}
		}
		}
	}

	if (turn == 0)
	{
		print("Player's turn! Enter coords for attack or a command!");
		if (playerTargetPos.inBounds())
		{
			// See if we already tried here
			switch (playerShotMap.getNode(playerTargetPos))
			{
				case STATE_HIT:
				case STATE_MISS:
					print("Already attacked coords, try another!");
					return;
				default: break;
			}

			switch (enemyShipMap.getNode(playerTargetPos))
			{
				case STATE_EMPTY:
					playerShotMap.setNode(playerTargetPos, STATE_MISS);
					error("Missed!");
					break;
				case STATE_SHIP:
					playerShotMap.setNode(playerTargetPos, STATE_HIT);
					switch (getHitShip(ENEMY))
					{
						case SHIP_CARRIER:
							enemyShips[SHIP_CARRIER].hit();
							if (!enemyShips[SHIP_CARRIER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's carrier!");
							}
							break;
						case SHIP_BATTLE:
							enemyShips[SHIP_BATTLE].hit();
							if (!enemyShips[SHIP_BATTLE].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's battleship!");
							}
							break;
						case SHIP_CRUISER:
							enemyShips[SHIP_CRUISER].hit();
							if (!enemyShips[SHIP_CRUISER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's cruiser!");
							}
							break;
						case SHIP_SUBMARINE:
							enemyShips[SHIP_SUBMARINE].hit();
							if (!enemyShips[SHIP_SUBMARINE].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's submarine!");
							}
							break;
						case SHIP_DESTROYER:
							enemyShips[SHIP_DESTROYER].hit();
							if (!enemyShips[SHIP_DESTROYER].isAlive())
							{
								enemyShipsLeft--;
								error("You sank the computer's destroyer!");
							}
							break;
						default: error("Something went terribly wrong in the enemy ship hit code!"); break;
					}
					break;
				default:
					error("Something just went terribly wrong! gm.cpp:192");
					break;
			}
		}
	}

	if (turn >= 0)
	{
		if (playerShipsLeft <= 0 || enemyShipsLeft <= 0)
			gameOver = true;
	}

	/* Reset state variables */
	playerShipDirection = DIR_NONE;
	playerTargetPos = Vec2(-1, -1);
	if (statusMsgRedrawOverride)
	{
		statusMsgRedrawOverride = false;
	}
}

void GameStateManager::handleCommand(strVec commandList)
{
	if (commandList.empty())
		return;

	if (commandList.size() == 1)
	{ // Handle 0 arg commands
		if (commandList[0] == "quit" || commandList[0] == "q" || commandList[0] == "sd")
		{
			gameOver = true;
		}
		else
		{
			playerTargetPos = util::parseCoords(commandList[0]);
			if (playerTargetPos.x == -1 || playerTargetPos.y == -1)
			{
				error("Invalid coordinates!");
				return;
			}
		}
	} else
	if (commandList.size() == 2)
	{ // Handle single argument commands
		if (commandList[1] == "north" || commandList[1] == "south" || commandList[1] == "east" || commandList[1] == "west" ||
				commandList[1] == "n" || commandList[1] == "s" || commandList[1] == "e" || commandList[1] == "w")
		{
			playerTargetPos = util::parseCoords(commandList[0]);
			if (playerTargetPos.x == -1 || playerTargetPos.y == -1)
			{
				error("Invalid coordinates!");
				return;
			}

			if (commandList[1] == "north" || commandList[1] == "n") playerShipDirection = DIR_NORTH; else
			if (commandList[1] == "south" || commandList[1] == "s") playerShipDirection = DIR_SOUTH; else
			if (commandList[1] == "west"  || commandList[1] == "w")  playerShipDirection = DIR_WEST; else
			if (commandList[1] == "east"  || commandList[1] == "e")  playerShipDirection = DIR_EAST;

			return;
		}
		else
			goto invalidCommand;
	}
	else
	invalidCommand:
		error("Invalid command!");
}

void GameStateManager::getInput()
{
	if (!gameOver)
	{
		std::string rawCommand;
		std::getline(std::cin, rawCommand);

		strVec commandList;
		commandList = util::parse(rawCommand);

		handleCommand(commandList);
	}
}

void GameStateManager::print(std::string msg)
{ // Helper to print info to the status bar
	statusMsg = msg;
}

void GameStateManager::error(std::string msg)
{
	statusMsgRedrawOverride = true;
	statusMsg = msg;
}

ShipType GameStateManager::getHitShip(Team team)
{
	if (team == ENEMY)
	{
		for (int i = 0; i <= 5; i++)
		{
			if (enemyShips[i].contains(playerTargetPos))
			{
				return enemyShips[i].type;
			}
		}
	} else
	if (team == PLAYER)
	{
		for (int i = 0; i <= 5; i++)
		{
			if (playerShips[i].contains(enemyTargetPos))
			{
				return playerShips[i].type;
			}
		}
	}
	return SHIP_NULL;
}

void GameStateManager::test()
{ // Sets 5,5 to be different states on all 3 maps, then confirms it is indeed that
	playerShipMap.setNode(5,5, STATE_MISS);
	enemyShipMap.setNode(5,5, STATE_HIT);
	playerShotMap.setNode(5,5, STATE_SHIP);

	if (playerShipMap.getNode(5,5) == STATE_MISS)
		puts("Successfully set playerShipMap!");
	if (enemyShipMap.getNode(5,5) == STATE_HIT)
		puts("Successfully set enemyShipMap!");
	if (playerShotMap.getNode(5,5) == STATE_SHIP)
		puts("Successfully set playerShotMap!");
	ui::draw(playerShipMap, playerShotMap, "AUGH!");
}
<|endoftext|>