<commit_before>#include <gtest/gtest.h>
#include <SharedMemory.hpp>
#include <MMaper.hpp>

//////////////////////////////////////////////////////////////////
TEST(MMaper, test_001)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::OpenOptions f;
     posix::SharedMemory sm3(n, false, f);
     sm3.open().truncate(4096);
     posix::MMapOptions mo;
     ASSERT_EQ(posix::mmap::READ |
	       posix::mmap::WRITE,
	       mo.get_protection().get());
     ASSERT_EQ(posix::mmap::MSHARED, mo.get_flag().get());
}

TEST(MMaper, test_002)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::SharedMemory sm3(n, false);
     sm3.open().truncate(4096);
     posix::MMapOptions mo;
     posix::MMaper m1(sm3, true, mo);
     posix::MMaper m2(sm3, true);
     posix::MMaper m3(sm3);
     m3.unmap();
}

TEST(MMaper, test_003)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::SharedMemory sm3(n, false);
     sm3.open().truncate(4096);
     posix::MMaper m3(sm3);
     auto r = m3.map();
     ASSERT_EQ(4096, std::get<size_t>(r));
     ASSERT_NE(nullptr, std::get<void*>(r));
     m3.unmap();
}
//////////////////////////////////////////////////////////////////
<commit_msg>fix unit test for MMaper<commit_after>#include <gtest/gtest.h>
#include <SharedMemory.hpp>
#include <MMaper.hpp>
#include <Error.hpp>

//////////////////////////////////////////////////////////////////
TEST(MMaper, test_001)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::OpenOptions f;
     posix::SharedMemory sm3(n, false, f);
     sm3.open().truncate(4096);
     posix::MMapOptions mo;
     ASSERT_EQ(posix::mmap::READ |
	       posix::mmap::WRITE,
	       mo.get_protection().get());
     ASSERT_EQ(posix::mmap::MSHARED, mo.get_flag().get());
}

TEST(MMaper, test_002)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::SharedMemory sm3(n, false);
     sm3.open().truncate(4096);
     posix::MMapOptions mo;
     posix::MMaper m1(sm3, true, mo);
     posix::MMaper m2(sm3, true);
     posix::MMaper m3(sm3);
     try {
	  m3.unmap();
     } catch (linux::posix::NullPointer& d) {
	  ASSERT_TRUE(true);
	  return;
     }
     ASSERT_TRUE(false);
}

TEST(MMaper, test_003)
{
     using namespace linux;
     posix::Name n("/ARTA");
     posix::SharedMemory sm3(n, false);
     sm3.open().truncate(4096);
     posix::MMaper m3(sm3);
     auto r = m3.map();
     ASSERT_EQ(4096, std::get<size_t>(r));
     ASSERT_NE(nullptr, std::get<void*>(r));
     m3.unmap();
}
//////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>//=============================================================================
// ■ Assembler.cpp
//-----------------------------------------------------------------------------
//   ASM76汇编器。
//=============================================================================

#include "ASM76.hpp"

namespace ASM76 {
	#define SPACE " \t\v"
	//-------------------------------------------------------------------------
	// ● 构造
	//-------------------------------------------------------------------------
	Assembler::Assembler(const char* program) {
		prg = program;
	}
	//-------------------------------------------------------------------------
	// ● 汇编
	//-------------------------------------------------------------------------
	Program Assembler::assemble() {
		Program r;
		// 实际已用0字节
		r.size = 0;
		// 预留10个指令空位
		size_t buf_size = 10 * sizeof(Instruct);
		r.instruct = (Instruct*) malloc(buf_size);
		// 这个指针指向当前正要填充的指令
		Instruct* current_instruct = r.instruct;
		while (prg && *prg) switch (*prg) {
		case '#':
			prg = strchr(prg, '\n') + 1;
			break;
		case '\n':
			prg++;
			break;
		default: {
			// 需要添加指令但预留空间不足时，
			if (r.size > buf_size) {
				// 补充30个指令空位。
				buf_size += 30 * sizeof(Instruct);
				r.instruct = (Instruct*) realloc(r.instruct, r.size);
			}
			// 读取opcode
			char opcode[13];
			copy_opcode(opcode);
			current_instruct->opcode = parse_opcode(opcode);
			// 读取参数
			read_parameters(current_instruct);
			// 换行
			skip('\n');
			// 填充完毕，指针移位
			r.size += sizeof(Instruct);
			current_instruct++;
		}
		}
		return r;
	}
	//-------------------------------------------------------------------------
	// ● 报错！
	//-------------------------------------------------------------------------
	void Assembler::error(const char* message) {
		printf("Error: %s\nAssembly:\n%s\n", message, prg);
		abort();
	}
	//-------------------------------------------------------------------------
	// ● 是否为某些字符中的一个？
	//-------------------------------------------------------------------------
	bool Assembler::check(char c, const char* s) {
		return strchr(s, (unsigned char) c) != NULL;
	}
	//-------------------------------------------------------------------------
	// ● 跳过某一字符
	//-------------------------------------------------------------------------
	void Assembler::skip(char c) {
		if (*prg != c) {
			char msg[20];
			switch (c) {
			case '\n':
				strcpy(msg, "expected newline");
				break;
			case ' ':
				strcpy(msg, "expected space");
				break;
			default:
				strcpy(msg, "expected '\a'");
				*strchr(msg, '\a') = c;
			}
			error(msg);
		}
		prg++;
	}
	//-------------------------------------------------------------------------
	// ● 跳过某些字符组成的串
	//-------------------------------------------------------------------------
	void Assembler::skip(const char* s, const char* error_msg) {
		size_t len = strspn(prg, s);
		if (!len) error(error_msg);
		prg += len;
	}
	//-------------------------------------------------------------------------
	// ● 复制opcode
	//-------------------------------------------------------------------------
	void Assembler::copy_opcode(char* buf) {
		for (size_t i = 0; i < 12; i++) {
			if (check(prg[i], " \t\v\n") {
				memcpy(buf, prg, i);
				buf[i] = 0;
				prg += i;
				return;
			}
		}
		error("opcode too long");
	}
	//-------------------------------------------------------------------------
	// ● opcode: char[] → enum InstructionOpcode
	//-------------------------------------------------------------------------
	enum InstructionOpcode Assembler::parse_opcode(const char* str) {
		#define I(x, ta, tb) if (strcmp(str, #x) == 0) return x;
		#include "instructions.hpp"
		error("unidentified instruction");
		return NOOP;
	}
	//-------------------------------------------------------------------------
	// ● 读取参数
	//-------------------------------------------------------------------------
	void Assembler::read_parameters(Instruct* i) {
		switch (i->opcode) {
		#define TNUL 0
		#define TIMM read_immediate_u32()
		#define TADD read_address()
		#define TREG read_register()
		#define I(x, ta, tb) case x: i->a = ta; i->b = tb; break;
		#include "instructions.hpp"
		}
	}
	//-------------------------------------------------------------------------
	// ● 读取立即数参数
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_immediate_u32() {
		skip(" \t\v");
		if (!is_digit(*prg)) error("expected digit");
		long long n;
		if (prg[0] == '0' && prg[1] == 'x') {
			char* end;
			n = strtoll(prg + 2, &end, 16);
			prg = (const char*) end;
		} else {
			n = atoll(prg);
		}
		if (n > UINT32_MAX) error("immediate number too large");
		if (n < 0) error("immediate number can't be negative");
		while (is_digit(*prg)) prg++;
		return n;
	}
	//-------------------------------------------------------------------------
	// ● 读取地址参数
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_address() {
		return read_immediate_u32();
	}
	//-------------------------------------------------------------------------
	// ● 读取寄存器参数
	//   返回寄存器编号。
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_register() {
		skip(" \t\v");
		skip('$');
		if (!is_digit(*prg)) error("expected digit");
		int reg = atoi(prg);
		if (reg < 0) error("register no. can't be negative");
		if ((size_t) reg > VM::REGISTER_COUNT) error("register no. too large");
		while (is_digit(*prg)) prg++;
		return reg;
	}
}
<commit_msg>增强错误信息（未测试）<commit_after>//=============================================================================
// ■ Assembler.cpp
//-----------------------------------------------------------------------------
//   ASM76汇编器。
//=============================================================================

#include "ASM76.hpp"

namespace ASM76 {
	#define SPACE " \t\v"
	//-------------------------------------------------------------------------
	// ● 构造
	//-------------------------------------------------------------------------
	Assembler::Assembler(const char* program) {
		prg = original_prg = program;
	}
	//-------------------------------------------------------------------------
	// ● 汇编
	//-------------------------------------------------------------------------
	Program Assembler::assemble() {
		Program r;
		// 实际已用0字节
		r.size = 0;
		// 预留10个指令空位
		size_t buf_size = 10 * sizeof(Instruct);
		r.instruct = (Instruct*) malloc(buf_size);
		// 这个指针指向当前正要填充的指令
		Instruct* current_instruct = r.instruct;
		while (prg && *prg) switch (*prg) {
		case '#':
			prg = strchr(prg, '\n') + 1;
			break;
		case '\n':
			prg++;
			break;
		default: {
			// 需要添加指令但预留空间不足时，
			if (r.size > buf_size) {
				// 补充30个指令空位。
				buf_size += 30 * sizeof(Instruct);
				r.instruct = (Instruct*) realloc(r.instruct, r.size);
			}
			// 读取opcode
			char opcode[13];
			copy_opcode(opcode);
			current_instruct->opcode = parse_opcode(opcode);
			// 读取参数
			read_parameters(current_instruct);
			// 换行
			skip('\n');
			// 填充完毕，指针移位
			r.size += sizeof(Instruct);
			current_instruct++;
		}
		}
		return r;
	}
	//-------------------------------------------------------------------------
	// ● 报错！
	//-------------------------------------------------------------------------
	void Assembler::error(const char* message) {
		printf("Error: %s\nAssembly:\n", message);
		const char* p = prg;
		while (p > original_prg || p[-1] != '\n') p--;
		while (!check(*p, "\n")) putchar(*p++);
		putchar('\n');
		abort();
	}
	//-------------------------------------------------------------------------
	// ● 是否为某些字符中的一个？
	//-------------------------------------------------------------------------
	bool Assembler::check(char c, const char* s) {
		return strchr(s, (unsigned char) c) != NULL;
	}
	//-------------------------------------------------------------------------
	// ● 跳过某一字符
	//-------------------------------------------------------------------------
	void Assembler::skip(char c) {
		if (*prg != c) {
			char msg[20];
			switch (c) {
			case '\n':
				strcpy(msg, "expected newline");
				break;
			case ' ':
				strcpy(msg, "expected space");
				break;
			default:
				strcpy(msg, "expected '\a'");
				*strchr(msg, '\a') = c;
			}
			error(msg);
		}
		prg++;
	}
	//-------------------------------------------------------------------------
	// ● 跳过某些字符组成的串
	//-------------------------------------------------------------------------
	void Assembler::skip(const char* s, const char* error_msg) {
		size_t len = strspn(prg, s);
		if (!len) error(error_msg);
		prg += len;
	}
	//-------------------------------------------------------------------------
	// ● 复制opcode
	//-------------------------------------------------------------------------
	void Assembler::copy_opcode(char* buf) {
		for (size_t i = 0; i < 12; i++) {
			if (check(prg[i], " \t\v\n")) {
				memcpy(buf, prg, i);
				buf[i] = 0;
				prg += i;
				return;
			}
		}
		error("opcode too long");
	}
	//-------------------------------------------------------------------------
	// ● opcode: char[] → enum InstructionOpcode
	//-------------------------------------------------------------------------
	enum InstructionOpcode Assembler::parse_opcode(const char* str) {
		#define I(x, ta, tb) if (strcmp(str, #x) == 0) return x;
		#include "instructions.hpp"
		error("unidentified instruction");
		return NOOP;
	}
	//-------------------------------------------------------------------------
	// ● 读取参数
	//-------------------------------------------------------------------------
	void Assembler::read_parameters(Instruct* i) {
		switch (i->opcode) {
		#define TNUL 0
		#define TIMM read_immediate_u32()
		#define TADD read_address()
		#define TREG read_register()
		#define I(x, ta, tb) case x: i->a = ta; i->b = tb; break;
		#include "instructions.hpp"
		}
	}
	//-------------------------------------------------------------------------
	// ● 读取立即数参数
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_immediate_u32() {
		skip(" \t\v", "expected whitespace");
		if (!isdigit((unsigned char) *prg)) error("expected digit");
		long long n;
		char* end;
		if (prg[0] == '0' && prg[1] == 'x') {
			n = strtoll(prg + 2, &end, 16);
		} else {
			n = strtoll(prg, &end, 10);
		}
		if (n > UINT32_MAX) error("immediate number too large");
		if (n < 0) error("immediate number can't be negative");
		prg = (const char*) end;
		return n;
	}
	//-------------------------------------------------------------------------
	// ● 读取地址参数
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_address() {
		return read_immediate_u32();
	}
	//-------------------------------------------------------------------------
	// ● 读取寄存器参数
	//   返回寄存器编号。
	//-------------------------------------------------------------------------
	uint32_t Assembler::read_register() {
		skip(" \t\v", "expected whitespace");
		skip('$');
		if (!isdigit((unsigned char) *prg)) error("expected digit");
		int reg = atoi(prg);
		if (reg < 0) error("register no. can't be negative");
		if ((size_t) reg > VM::REGISTER_COUNT) error("register no. too large");
		while (isdigit((unsigned char) *prg)) prg++;
		return reg;
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/services/credentials.h"

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <sys/capability.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
#include "base/template_util.h"
#include "base/third_party/valgrind/valgrind.h"
#include "sandbox/linux/services/namespace_utils.h"
#include "sandbox/linux/services/syscall_wrappers.h"

namespace sandbox {

namespace {

bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }

struct CapFreeDeleter {
  inline void operator()(cap_t cap) const {
    int ret = cap_free(cap);
    CHECK_EQ(0, ret);
  }
};

// Wrapper to manage libcap2's cap_t type.
typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;

struct CapTextFreeDeleter {
  inline void operator()(char* cap_text) const {
    int ret = cap_free(cap_text);
    CHECK_EQ(0, ret);
  }
};

// Wrapper to manage the result from libcap2's cap_from_text().
typedef scoped_ptr<char, CapTextFreeDeleter> ScopedCapText;

// Checks that the set of RES-uids and the set of RES-gids have
// one element each and return that element in |resuid| and |resgid|
// respectively. It's ok to pass NULL as one or both of the ids.
bool GetRESIds(uid_t* resuid, gid_t* resgid) {
  uid_t ruid, euid, suid;
  gid_t rgid, egid, sgid;
  PCHECK(getresuid(&ruid, &euid, &suid) == 0);
  PCHECK(getresgid(&rgid, &egid, &sgid) == 0);
  const bool uids_are_equal = (ruid == euid) && (ruid == suid);
  const bool gids_are_equal = (rgid == egid) && (rgid == sgid);
  if (!uids_are_equal || !gids_are_equal) return false;
  if (resuid) *resuid = euid;
  if (resgid) *resgid = egid;
  return true;
}

const int kExitSuccess = 0;

int ChrootToSelfFdinfo(void*) {
  RAW_CHECK(chroot("/proc/self/fdinfo/") == 0);

  // CWD is essentially an implicit file descriptor, so be careful to not
  // leave it behind.
  RAW_CHECK(chdir("/") == 0);
  _exit(kExitSuccess);
}

// chroot() to an empty dir that is "safe". To be safe, it must not contain
// any subdirectory (chroot-ing there would allow a chroot escape) and it must
// be impossible to create an empty directory there.
// We achieve this by doing the following:
// 1. We create a new process sharing file system information.
// 2. In the child, we chroot to /proc/self/fdinfo/
// This is already "safe", since fdinfo/ does not contain another directory and
// one cannot create another directory there.
// 3. The process dies
// After (3) happens, the directory is not available anymore in /proc.
bool ChrootToSafeEmptyDir() {
  // We need to chroot to a fdinfo that is unique to a process and have that
  // process die.
  // 1. We don't want to simply fork() because duplicating the page tables is
  // slow with a big address space.
  // 2. We do not use a regular thread (that would unshare CLONE_FILES) because
  // when we are in a PID namespace, we cannot easily get a handle to the
  // /proc/tid directory for the thread (since /proc may not be aware of the
  // PID namespace). With a process, we can just use /proc/self.
  pid_t pid = -1;
  char stack_buf[PTHREAD_STACK_MIN];
#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
  // The stack grows downward.
  void* stack = stack_buf + sizeof(stack_buf);
#else
#error "Unsupported architecture"
#endif
  pid = clone(ChrootToSelfFdinfo, stack,
              CLONE_VM | CLONE_VFORK | CLONE_FS | SIGCHLD, nullptr, nullptr,
              nullptr, nullptr);
  PCHECK(pid != -1);

  int status = -1;
  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);

  return kExitSuccess == status;
}

// CHECK() that an attempt to move to a new user namespace raised an expected
// errno.
void CheckCloneNewUserErrno(int error) {
  // EPERM can happen if already in a chroot. EUSERS if too many nested
  // namespaces are used. EINVAL for kernels that don't support the feature.
  // Valgrind will ENOSYS unshare().
  PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
         error == ENOSYS);
}

}  // namespace.

bool Credentials::DropAllCapabilities() {
  ScopedCap cap(cap_init());
  CHECK(cap);
  PCHECK(0 == cap_set_proc(cap.get()));
  CHECK(!HasAnyCapability());
  // We never let this function fail.
  return true;
}

bool Credentials::HasAnyCapability() {
  ScopedCap current_cap(cap_get_proc());
  CHECK(current_cap);
  ScopedCap empty_cap(cap_init());
  CHECK(empty_cap);
  return cap_compare(current_cap.get(), empty_cap.get()) != 0;
}

scoped_ptr<std::string> Credentials::GetCurrentCapString() {
  ScopedCap current_cap(cap_get_proc());
  CHECK(current_cap);
  ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL));
  CHECK(cap_text);
  return scoped_ptr<std::string> (new std::string(cap_text.get()));
}

// static
bool Credentials::CanCreateProcessInNewUserNS() {
  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
  // so always consider UserNS unsupported there.
  if (IsRunningOnValgrind()) {
    return false;
  }

  // This is roughly a fork().
  const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0);

  if (pid == -1) {
    CheckCloneNewUserErrno(errno);
    return false;
  }

  // The parent process could have had threads. In the child, these threads
  // have disappeared. Make sure to not do anything in the child, as this is a
  // fragile execution environment.
  if (pid == 0) {
    _exit(0);
  }

  // Always reap the child.
  siginfo_t infop;
  PCHECK(0 == HANDLE_EINTR(waitid(P_PID, pid, &infop, WEXITED)));

  // clone(2) succeeded, we can use CLONE_NEWUSER.
  return true;
}

bool Credentials::MoveToNewUserNS() {
  uid_t uid;
  gid_t gid;
  if (!GetRESIds(&uid, &gid)) {
    // If all the uids (or gids) are not equal to each other, the security
    // model will most likely confuse the caller, abort.
    DVLOG(1) << "uids or gids differ!";
    return false;
  }
  int ret = unshare(CLONE_NEWUSER);
  if (ret) {
    const int unshare_errno = errno;
    VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
            << "on this kernel.";
    CheckCloneNewUserErrno(unshare_errno);
    return false;
  }

  if (NamespaceUtils::KernelSupportsDenySetgroups()) {
    PCHECK(NamespaceUtils::DenySetgroups());
  }

  // The current {r,e,s}{u,g}id is now an overflow id (c.f.
  // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
  DCHECK(GetRESIds(NULL, NULL));
  const char kGidMapFile[] = "/proc/self/gid_map";
  const char kUidMapFile[] = "/proc/self/uid_map";
  PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
  PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
  DCHECK(GetRESIds(NULL, NULL));
  return true;
}

bool Credentials::DropFileSystemAccess() {
  CHECK(ChrootToSafeEmptyDir());
  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
  // We never let this function fail.
  return true;
}

}  // namespace sandbox.
<commit_msg>sandbox: use waitpid consistently<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/services/credentials.h"

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <sys/capability.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
#include "base/template_util.h"
#include "base/third_party/valgrind/valgrind.h"
#include "sandbox/linux/services/namespace_utils.h"
#include "sandbox/linux/services/syscall_wrappers.h"

namespace sandbox {

namespace {

bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }

struct CapFreeDeleter {
  inline void operator()(cap_t cap) const {
    int ret = cap_free(cap);
    CHECK_EQ(0, ret);
  }
};

// Wrapper to manage libcap2's cap_t type.
typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;

struct CapTextFreeDeleter {
  inline void operator()(char* cap_text) const {
    int ret = cap_free(cap_text);
    CHECK_EQ(0, ret);
  }
};

// Wrapper to manage the result from libcap2's cap_from_text().
typedef scoped_ptr<char, CapTextFreeDeleter> ScopedCapText;

// Checks that the set of RES-uids and the set of RES-gids have
// one element each and return that element in |resuid| and |resgid|
// respectively. It's ok to pass NULL as one or both of the ids.
bool GetRESIds(uid_t* resuid, gid_t* resgid) {
  uid_t ruid, euid, suid;
  gid_t rgid, egid, sgid;
  PCHECK(getresuid(&ruid, &euid, &suid) == 0);
  PCHECK(getresgid(&rgid, &egid, &sgid) == 0);
  const bool uids_are_equal = (ruid == euid) && (ruid == suid);
  const bool gids_are_equal = (rgid == egid) && (rgid == sgid);
  if (!uids_are_equal || !gids_are_equal) return false;
  if (resuid) *resuid = euid;
  if (resgid) *resgid = egid;
  return true;
}

const int kExitSuccess = 0;

int ChrootToSelfFdinfo(void*) {
  RAW_CHECK(chroot("/proc/self/fdinfo/") == 0);

  // CWD is essentially an implicit file descriptor, so be careful to not
  // leave it behind.
  RAW_CHECK(chdir("/") == 0);
  _exit(kExitSuccess);
}

// chroot() to an empty dir that is "safe". To be safe, it must not contain
// any subdirectory (chroot-ing there would allow a chroot escape) and it must
// be impossible to create an empty directory there.
// We achieve this by doing the following:
// 1. We create a new process sharing file system information.
// 2. In the child, we chroot to /proc/self/fdinfo/
// This is already "safe", since fdinfo/ does not contain another directory and
// one cannot create another directory there.
// 3. The process dies
// After (3) happens, the directory is not available anymore in /proc.
bool ChrootToSafeEmptyDir() {
  // We need to chroot to a fdinfo that is unique to a process and have that
  // process die.
  // 1. We don't want to simply fork() because duplicating the page tables is
  // slow with a big address space.
  // 2. We do not use a regular thread (that would unshare CLONE_FILES) because
  // when we are in a PID namespace, we cannot easily get a handle to the
  // /proc/tid directory for the thread (since /proc may not be aware of the
  // PID namespace). With a process, we can just use /proc/self.
  pid_t pid = -1;
  char stack_buf[PTHREAD_STACK_MIN];
#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
  // The stack grows downward.
  void* stack = stack_buf + sizeof(stack_buf);
#else
#error "Unsupported architecture"
#endif
  pid = clone(ChrootToSelfFdinfo, stack,
              CLONE_VM | CLONE_VFORK | CLONE_FS | SIGCHLD, nullptr, nullptr,
              nullptr, nullptr);
  PCHECK(pid != -1);

  int status = -1;
  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);

  return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess;
}

// CHECK() that an attempt to move to a new user namespace raised an expected
// errno.
void CheckCloneNewUserErrno(int error) {
  // EPERM can happen if already in a chroot. EUSERS if too many nested
  // namespaces are used. EINVAL for kernels that don't support the feature.
  // Valgrind will ENOSYS unshare().
  PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
         error == ENOSYS);
}

}  // namespace.

bool Credentials::DropAllCapabilities() {
  ScopedCap cap(cap_init());
  CHECK(cap);
  PCHECK(0 == cap_set_proc(cap.get()));
  CHECK(!HasAnyCapability());
  // We never let this function fail.
  return true;
}

bool Credentials::HasAnyCapability() {
  ScopedCap current_cap(cap_get_proc());
  CHECK(current_cap);
  ScopedCap empty_cap(cap_init());
  CHECK(empty_cap);
  return cap_compare(current_cap.get(), empty_cap.get()) != 0;
}

scoped_ptr<std::string> Credentials::GetCurrentCapString() {
  ScopedCap current_cap(cap_get_proc());
  CHECK(current_cap);
  ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL));
  CHECK(cap_text);
  return scoped_ptr<std::string> (new std::string(cap_text.get()));
}

// static
bool Credentials::CanCreateProcessInNewUserNS() {
  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
  // so always consider UserNS unsupported there.
  if (IsRunningOnValgrind()) {
    return false;
  }

  // This is roughly a fork().
  const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0);

  if (pid == -1) {
    CheckCloneNewUserErrno(errno);
    return false;
  }

  // The parent process could have had threads. In the child, these threads
  // have disappeared. Make sure to not do anything in the child, as this is a
  // fragile execution environment.
  if (pid == 0) {
    _exit(kExitSuccess);
  }

  // Always reap the child.
  int status = -1;
  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
  CHECK(WIFEXITED(status));
  CHECK_EQ(kExitSuccess, WEXITSTATUS(status));

  // clone(2) succeeded, we can use CLONE_NEWUSER.
  return true;
}

bool Credentials::MoveToNewUserNS() {
  uid_t uid;
  gid_t gid;
  if (!GetRESIds(&uid, &gid)) {
    // If all the uids (or gids) are not equal to each other, the security
    // model will most likely confuse the caller, abort.
    DVLOG(1) << "uids or gids differ!";
    return false;
  }
  int ret = unshare(CLONE_NEWUSER);
  if (ret) {
    const int unshare_errno = errno;
    VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
            << "on this kernel.";
    CheckCloneNewUserErrno(unshare_errno);
    return false;
  }

  if (NamespaceUtils::KernelSupportsDenySetgroups()) {
    PCHECK(NamespaceUtils::DenySetgroups());
  }

  // The current {r,e,s}{u,g}id is now an overflow id (c.f.
  // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
  DCHECK(GetRESIds(NULL, NULL));
  const char kGidMapFile[] = "/proc/self/gid_map";
  const char kUidMapFile[] = "/proc/self/uid_map";
  PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
  PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
  DCHECK(GetRESIds(NULL, NULL));
  return true;
}

bool Credentials::DropFileSystemAccess() {
  CHECK(ChrootToSafeEmptyDir());
  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
  // We never let this function fail.
  return true;
}

}  // namespace sandbox.
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_MATRIX_EXP_HPP
#define STAN_MATH_PRIM_MAT_FUN_MATRIX_EXP_HPP

#include <stan/math/prim/mat/fun/matrix_exp_pade.hpp>
#include <stan/math/prim/mat/fun/matrix_exp_2x2.hpp>

namespace stan {
namespace math {

/**
 * Return the matrix exponential of the input
 * matrix.
 *
 * @tparam T type of scalar of the elements of
 * input matrix.
 * @param[in] A Matrix to exponentiate.
 * @return Matrix exponential.
 */
template <typename T>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> matrix_exp(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A) {
  check_nonzero_size("matrix_exp", "input matrix", A);
  check_square("matrix_exp", "input matrix", A);

  return (A.cols() == 2
          && square(value_of(A(0, 0)) - value_of(A(1, 1)))
                     + 4 * value_of(A(0, 1)) * value_of(A(1, 0))
                 > 0)
             ? matrix_exp_2x2(A)
             : matrix_exp_pade(A);
}

template <typename T, int N>
inline Eigen::Matrix<T, N, N> matrix_exp(const Eigen::Matrix<T, N, N>& A) {
  check_nonzero_size("matrix_exp", "input matrix", A);

  return (N == 2
          && square(value_of(A(0, 0)) - value_of(A(1, 1)))
                     + 4 * value_of(A(0, 1)) * value_of(A(1, 0))
                 > 0)
             ? matrix_exp_2x2(A)
             : matrix_exp_pade(A);
}

template <typename T>
inline Eigen::Matrix<T, 1, 1> matrix_exp(const Eigen::Matrix<T, 1, 1>& A) {
  Eigen::Matrix<T, 1, 1> res;
  res << exp(A(0));
  return res;
}
}  // namespace math
}  // namespace stan
#endif
<commit_msg>add comment<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_MATRIX_EXP_HPP
#define STAN_MATH_PRIM_MAT_FUN_MATRIX_EXP_HPP

#include <stan/math/prim/mat/fun/matrix_exp_pade.hpp>
#include <stan/math/prim/mat/fun/matrix_exp_2x2.hpp>

namespace stan {
namespace math {

/**
 * Return the matrix exponential of the input
 * matrix.
 *
 * @tparam T type of scalar of the elements of
 * input matrix.
 * @param[in] A Matrix to exponentiate.
 * @return Matrix exponential, dynacally-sized.
 */
template <typename T>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> matrix_exp(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A) {
  check_nonzero_size("matrix_exp", "input matrix", A);
  check_square("matrix_exp", "input matrix", A);

  return (A.cols() == 2
          && square(value_of(A(0, 0)) - value_of(A(1, 1)))
                     + 4 * value_of(A(0, 1)) * value_of(A(1, 0))
                 > 0)
             ? matrix_exp_2x2(A)
             : matrix_exp_pade(A);
}

/**
 * Return the matrix exponential of the input
 * statically-sized matrix.
 *
 * @tparam T type of scalar of the elements of
 * input matrix.
 * @tparam N size of the input square matrix.
 * @param[in] A Matrix to exponentiate.
 * @return Matrix exponential, statically-sized.
 */
template <typename T, int N>
inline Eigen::Matrix<T, N, N> matrix_exp(const Eigen::Matrix<T, N, N>& A) {
  check_nonzero_size("matrix_exp", "input matrix", A);

  return (N == 2
          && square(value_of(A(0, 0)) - value_of(A(1, 1)))
                     + 4 * value_of(A(0, 1)) * value_of(A(1, 0))
                 > 0)
             ? matrix_exp_2x2(A)
             : matrix_exp_pade(A);
}

/**
 * Return the exponential of the input scalar when it's in
 * the form of Eigen matrix.
 *
 * @tparam T type of scalar of the elements of
 * input matrix.
 * @return 1x1 Matrix exponential, statically-sized.
 */
template <typename T>
inline Eigen::Matrix<T, 1, 1> matrix_exp(const Eigen::Matrix<T, 1, 1>& A) {
  Eigen::Matrix<T, 1, 1> res;
  res << exp(A(0));
  return res;
}
}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_FUN_CONSTANTS_HPP
#define STAN_MATH_PRIM_SCAL_FUN_CONSTANTS_HPP

#include <stan/math/prim/scal/fun/inv.hpp>
#include <boost/math/constants/constants.hpp>
#include <limits>

namespace stan {
namespace math {

/**
 * The base of the natural logarithm,
 * \f$ e \f$.
 */
const double E = boost::math::constants::e<double>();

/**
 * The value of the square root of 2,
 * \f$ \sqrt{2} \f$.
 */
const double SQRT_2 = std::sqrt(2.0);

/**
 * The value of 1 over the square root of 2,
 * \f$ 1 / \sqrt{2} \f$.
 */
const double INV_SQRT_2 = inv(SQRT_2);

/**
 * The natural logarithm of 2,
 * \f$ \log 2 \f$.
 */
const double LOG_2 = std::log(2.0);

/**
 * The natural logarithm of 10,
 * \f$ \log 10 \f$.
 */
const double LOG_10 = std::log(10.0);

/**
 * Positive infinity.
 */
const double INFTY = std::numeric_limits<double>::infinity();

/**
 * Negative infinity.
 */
const double NEGATIVE_INFTY = -std::numeric_limits<double>::infinity();

/**
 * (Quiet) not-a-number value.
 */
const double NOT_A_NUMBER = std::numeric_limits<double>::quiet_NaN();

/**
 * Smallest positive value.
 */
const double EPSILON = std::numeric_limits<double>::epsilon();

/**
 * Largest negative value (i.e., smallest absolute value).
 */
const double NEGATIVE_EPSILON = -std::numeric_limits<double>::epsilon();

/**
 * Largest rate parameter allowed in Poisson RNG
 */
const double POISSON_MAX_RATE = std::pow(2.0, 30);

/**
 * Log pi divided by 4
 * \f$ \log \pi / 4 \f$
 */
const double LOG_PI_OVER_FOUR
    = std::log(boost::math::constants::pi<double>()) / 4.0;

/**
 * Return the value of pi.
 *
 * @return Pi.
 */
inline double pi() { return boost::math::constants::pi<double>(); }

/**
 * Return the base of the natural logarithm.
 *
 * @return Base of natural logarithm.
 */
inline double e() { return E; }

/**
 * Return the square root of two.
 *
 * @return Square root of two.
 */
inline double sqrt2() { return SQRT_2; }

/**
 * Return natural logarithm of ten.
 *
 * @return Natural logarithm of ten.
 */
inline double log10() { return LOG_10; }

/**
 * Return positive infinity.
 *
 * @return Positive infinity.
 */
inline double positive_infinity() { return INFTY; }

/**
 * Return negative infinity.
 *
 * @return Negative infinity.
 */
inline double negative_infinity() { return NEGATIVE_INFTY; }

/**
 * Return (quiet) not-a-number.
 *
 * @return Quiet not-a-number.
 */
inline double not_a_number() { return NOT_A_NUMBER; }

/**
 * Returns the difference between 1.0 and the next value
 * representable.
 *
 * @return Minimum positive number.
 */
inline double machine_precision() { return EPSILON; }

const double SQRT_PI = std::sqrt(boost::math::constants::pi<double>());

const double SQRT_2_TIMES_SQRT_PI = SQRT_2 * SQRT_PI;

const double SQRT_2_OVER_SQRT_PI = SQRT_2 / SQRT_PI;

const double TWO_OVER_SQRT_PI = 2.0 / SQRT_PI;

const double NEG_TWO_OVER_SQRT_PI = -TWO_OVER_SQRT_PI;

const double INV_SQRT_TWO_PI
    = inv(std::sqrt(2.0 * boost::math::constants::pi<double>()));

const double LOG_PI = std::log(boost::math::constants::pi<double>());

const double LOG_SQRT_PI = std::log(SQRT_PI);

const double LOG_ZERO = std::log(0.0);

const double LOG_TWO = std::log(2.0);

const double LOG_HALF = std::log(0.5);

const double NEG_LOG_TWO = -LOG_TWO;

const double NEG_LOG_SQRT_TWO_PI
    = -std::log(std::sqrt(2.0 * boost::math::constants::pi<double>()));

const double NEG_LOG_PI = -LOG_PI;

const double NEG_LOG_SQRT_PI
    = -std::log(std::sqrt(boost::math::constants::pi<double>()));

const double NEG_LOG_TWO_OVER_TWO = -LOG_TWO / 2.0;

const double LOG_TWO_PI = LOG_TWO + LOG_PI;

const double NEG_LOG_TWO_PI = -LOG_TWO_PI;

const double LOG_EPSILON = std::log(EPSILON);
}  // namespace math
}  // namespace stan

#endif
<commit_msg>Tidying<commit_after>#ifndef STAN_MATH_PRIM_SCAL_FUN_CONSTANTS_HPP
#define STAN_MATH_PRIM_SCAL_FUN_CONSTANTS_HPP

#include <stan/math/prim/scal/fun/inv.hpp>
#include <boost/math/constants/constants.hpp>
#include <limits>

namespace stan {
namespace math {

/**
 * The base of the natural logarithm,
 * \f$ e \f$.
 */
const double E = boost::math::constants::e<double>();

/**
 * The value of the square root of 2,
 * \f$ \sqrt{2} \f$.
 */
const double SQRT_2 = std::sqrt(2.0);

/**
 * The value of 1 over the square root of 2,
 * \f$ 1 / \sqrt{2} \f$.
 */
const double INV_SQRT_2 = inv(SQRT_2);

/**
 * The natural logarithm of 2,
 * \f$ \log 2 \f$.
 */
const double LOG_2 = std::log(2.0);

/**
 * The natural logarithm of 10,
 * \f$ \log 10 \f$.
 */
const double LOG_10 = std::log(10.0);

/**
 * Positive infinity.
 */
const double INFTY = std::numeric_limits<double>::infinity();

/**
 * Negative infinity.
 */
const double NEGATIVE_INFTY = -std::numeric_limits<double>::infinity();

/**
 * (Quiet) not-a-number value.
 */
const double NOT_A_NUMBER = std::numeric_limits<double>::quiet_NaN();

/**
 * Smallest positive value.
 */
const double EPSILON = std::numeric_limits<double>::epsilon();

/**
 * Largest negative value (i.e., smallest absolute value).
 */
const double NEGATIVE_EPSILON = -std::numeric_limits<double>::epsilon();

/**
 * Largest rate parameter allowed in Poisson RNG
 */
const double POISSON_MAX_RATE = std::pow(2.0, 30);

/**
 * Log pi divided by 4
 * \f$ \log \pi / 4 \f$
 */
const double LOG_PI_OVER_FOUR
    = std::log(boost::math::constants::pi<double>()) / 4.0;

/**
 * Return the value of pi.
 *
 * @return Pi.
 */
inline double pi() { return boost::math::constants::pi<double>(); }

/**
 * Return the base of the natural logarithm.
 *
 * @return Base of natural logarithm.
 */
inline double e() { return E; }

/**
 * Return the square root of two.
 *
 * @return Square root of two.
 */
inline double sqrt2() { return SQRT_2; }

/**
 * Return natural logarithm of ten.
 *
 * @return Natural logarithm of ten.
 */
inline double log10() { return LOG_10; }

/**
 * Return positive infinity.
 *
 * @return Positive infinity.
 */
inline double positive_infinity() { return INFTY; }

/**
 * Return negative infinity.
 *
 * @return Negative infinity.
 */
inline double negative_infinity() { return NEGATIVE_INFTY; }

/**
 * Return (quiet) not-a-number.
 *
 * @return Quiet not-a-number.
 */
inline double not_a_number() { return NOT_A_NUMBER; }

/**
 * Returns the difference between 1.0 and the next value
 * representable.
 *
 * @return Minimum positive number.
 */
inline double machine_precision() { return EPSILON; }

const double SQRT_PI = std::sqrt(boost::math::constants::pi<double>());

const double SQRT_2_TIMES_SQRT_PI = SQRT_2 * SQRT_PI;

const double TWO_OVER_SQRT_PI = 2.0 / SQRT_PI;

const double NEG_TWO_OVER_SQRT_PI = -TWO_OVER_SQRT_PI;

const double INV_SQRT_TWO_PI
    = inv(std::sqrt(2.0 * boost::math::constants::pi<double>()));

const double LOG_PI = std::log(boost::math::constants::pi<double>());

const double LOG_SQRT_PI = std::log(SQRT_PI);

const double LOG_ZERO = std::log(0.0);

const double LOG_TWO = std::log(2.0);

const double LOG_HALF = std::log(0.5);

const double NEG_LOG_TWO = -LOG_TWO;

const double NEG_LOG_SQRT_TWO_PI
    = -std::log(std::sqrt(2.0 * boost::math::constants::pi<double>()));

const double NEG_LOG_PI = -LOG_PI;

const double NEG_LOG_SQRT_PI
    = -std::log(std::sqrt(boost::math::constants::pi<double>()));

const double NEG_LOG_TWO_OVER_TWO = -LOG_TWO / 2.0;

const double LOG_TWO_PI = LOG_TWO + LOG_PI;

const double NEG_LOG_TWO_PI = -LOG_TWO_PI;

const double LOG_EPSILON = std::log(EPSILON);
}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>//===--- LLVMSupport.cpp - Swift Language ABI Metadata Support ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"

// ADT uses report_bad_alloc_error to report an error when it can't allocate
// elements for a data structure. The swift runtime uses ADT without linking
// against libSupport, so here we provide a stub to make sure we don't fail
// to link.
#if defined(swiftCore_EXPORTS)
namespace llvm {

#if defined(_WIN32)
extern void report_bad_alloc_error(const char *Reason, bool GenCrashDiag);
void _report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {}
#if defined(_WIN64)
#pragma comment(linker, "/alternatename:?report_bad_alloc_error@llvm@@YAXPEBD_N@Z=?_report_bad_alloc_error@llvm@@YAXPEBD_N@Z")
#else
#pragma comment(linker, "/alternatename:?report_bad_alloc_error@llvm@@YAXPBD_N@Z=?_report_bad_alloc_error@llvm@@YAXPBD_N@Z")
#endif
#else
void __attribute__((__weak__, __visibility__("hidden")))
report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {}
#endif

// The same for SmallVector: provide the grow_pod implementation (the only
// SmallVector function which is not inlined) as we don't link LLVM.
// TODO: This is a hack. This implementaiton is copied from LLVM and has to stay
// in sync with it.

// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
void
#if !defined(_WIN32)
__attribute__((__weak__, __visibility__("hidden")))
#endif
SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinCapacity,
                                       size_t TSize) {
  // Ensure we can fit the new capacity.
  // This is only going to be applicable when the capacity is 32 bit.
  if (MinCapacity > SizeTypeMax())
    report_bad_alloc_error("SmallVector capacity overflow during allocation");

  // Ensure we can meet the guarantee of space for at least one more element.
  // The above check alone will not catch the case where grow is called with a
  // default MinCapacity of 0, but the current capacity cannot be increased.
  // This is only going to be applicable when the capacity is 32 bit.
  if (capacity() == SizeTypeMax())
    report_bad_alloc_error("SmallVector capacity unable to grow");

  // In theory 2*capacity can overflow if the capacity is 64 bit, but the
  // original capacity would never be large enough for this to be a problem.
  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
  NewCapacity = std::min(std::max(NewCapacity, MinCapacity), SizeTypeMax());

  void *NewElts;
  if (BeginX == FirstEl) {
    NewElts = safe_malloc(NewCapacity * TSize);

    // Copy the elements over.  No need to run dtors on PODs.
    memcpy(NewElts, this->BeginX, size() * TSize);
  } else {
    // If this wasn't grown from the inline copy, grow the allocated space.
    NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
  }

  this->BeginX = NewElts;
  this->Capacity = NewCapacity;
}

template class llvm::SmallVectorBase<uint32_t>;
template class llvm::SmallVectorBase<uint64_t>;

} // end namespace llvm
#endif // defined(swiftCore_EXPORTS)
<commit_msg>Revert "Merge llvm:master; fix SmallVectorBase in the swift runtime."<commit_after>//===--- LLVMSupport.cpp - Swift Language ABI Metadata Support ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"

// ADT uses report_bad_alloc_error to report an error when it can't allocate
// elements for a data structure. The swift runtime uses ADT without linking
// against libSupport, so here we provide a stub to make sure we don't fail
// to link.
#if defined(swiftCore_EXPORTS)
namespace llvm {

#if defined(_WIN32)
extern void report_bad_alloc_error(const char *Reason, bool GenCrashDiag);
void _report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {}
#if defined(_WIN64)
#pragma comment(linker, "/alternatename:?report_bad_alloc_error@llvm@@YAXPEBD_N@Z=?_report_bad_alloc_error@llvm@@YAXPEBD_N@Z")
#else
#pragma comment(linker, "/alternatename:?report_bad_alloc_error@llvm@@YAXPBD_N@Z=?_report_bad_alloc_error@llvm@@YAXPBD_N@Z")
#endif
#else
void __attribute__((__weak__, __visibility__("hidden")))
report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {}
#endif

// The same for SmallVector: provide the grow_pod implementation (the only
// SmallVector function which is not inlined) as we don't link LLVM.
// TODO: This is a hack. This implementaiton is copied from LLVM and has to stay
// in sync with it.

/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
void
#if !defined(_WIN32)
__attribute__((__weak__, __visibility__("hidden")))
#endif
llvm::SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
                                size_t TSize) {
  // Ensure we can fit the new capacity in 32 bits.
  if (MinCapacity > UINT32_MAX)
    report_bad_alloc_error("SmallVector capacity overflow during allocation");

  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
  NewCapacity =
    std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));

  void *NewElts;
  if (BeginX == FirstEl) {
    NewElts = safe_malloc(NewCapacity * TSize);

    // Copy the elements over.  No need to run dtors on PODs.
    memcpy(NewElts, this->BeginX, size() * TSize);
  } else {
    // If this wasn't grown from the inline copy, grow the allocated space.
    NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
  }

  this->BeginX = NewElts;
  this->Capacity = NewCapacity;
}

} // end namespace llvm
#endif // defined(swiftCore_EXPORTS)
<|endoftext|>


<commit_before>#include <sti/codecs/codec_png.h>
#include <sti/color_image.hpp>
#include <aeon/streams/file_stream.h>

#include <gtest/gtest.h>
#include <build_config.h>

TEST(test_png_codec, decode_image)
{
    auto stream = aeon::streams::file_stream(STI_TEST_DATA_PATH "/DSC_7000.png");
    auto image = sti::color_image();
    ASSERT_NO_THROW(image = sti::codecs::png::decode(stream));

    auto &info = image.info();

    EXPECT_EQ(256, info.width);
    EXPECT_EQ(171, info.height);
    EXPECT_EQ(sti::color_image_format::RGBA, info.format);
    EXPECT_EQ(4, info.bytes_per_pixel);
    EXPECT_EQ(info.width, info.stride);
}
<commit_msg>Added test for decoding and then reencoding a png file.<commit_after>#include <sti/codecs/codec_png.h>
#include <sti/color_image.hpp>
#include <aeon/streams/file_stream.h>

#include <gtest/gtest.h>
#include <build_config.h>

TEST(test_png_codec, decode_image)
{
    auto stream = aeon::streams::file_stream(STI_TEST_DATA_PATH "/DSC_7000.png");
    auto image = sti::color_image();
    ASSERT_NO_THROW(image = sti::codecs::png::decode(stream));

    auto &info = image.info();

    EXPECT_EQ(256, info.width);
    EXPECT_EQ(171, info.height);
    EXPECT_EQ(sti::color_image_format::RGBA, info.format);
    EXPECT_EQ(4, info.bytes_per_pixel);
    EXPECT_EQ(info.width, info.stride);
}

TEST(test_png_codec, decode_encode_image)
{
    auto stream = aeon::streams::file_stream(STI_TEST_DATA_PATH "/DSC_7000.png");
    auto image = sti::color_image();
    ASSERT_NO_THROW(image = sti::codecs::png::decode(stream));

    auto output_stream = aeon::streams::file_stream(
        "DSC_7000_encoded.png", aeon::streams::access_mode::write | aeon::streams::access_mode::truncate);
    sti::codecs::png::encode(image, output_stream);
}
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	startHighlight = 0;
	endHighlight = 0;

	colourBG.desired = Colour(0xff, 0xff, 0xff);
	colourUnSel.desired = Colour(0x80, 0x80, 0x80);
	colourSel.desired = Colour(0, 0, 0x80);
	colourShade.desired = Colour(0, 0, 0);
	colourLight.desired = Colour(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);
	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int lineHeight = surfaceWindow->Height(font);
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		int x = 5;
		int xEnd = x + surfaceWindow->WidthText(font, chunkVal, thisStartHighlight);
		rcClient.left = x;
		rcClient.top = ytext - ascent - 1;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal, thisStartHighlight,
		                        colourUnSel.allocated, colourBG.allocated);
		x = xEnd;

		xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisStartHighlight,
		                                    thisEndHighlight - thisStartHighlight);
		rcClient.top = ytext;
		rcClient.left = x;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal + thisStartHighlight, thisEndHighlight - thisStartHighlight,
		                        colourSel.allocated, colourBG.allocated);
		x = xEnd;

		xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisEndHighlight,
		                                    chunkLength - thisEndHighlight);
		rcClient.left = x;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal + thisEndHighlight, chunkLength - thisEndHighlight,
		                        colourUnSel.allocated, colourBG.allocated);
		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
	}
	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size) {
	Surface surfaceMeasure;
	surfaceMeasure.Init();
	int deviceHeight = (size * surfaceMeasure.LogPixelsY()) / 72;
	font.Create(faceName, SC_CHARSET_DEFAULT, deviceHeight, false, false);
	if (val)
		delete []val;
	val = new char[strlen(defn) + 1];
	if (!val)
		return PRectangle();
	strcpy(val, defn);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int width = 0;
	int numLines = 1;
	const char *newline;
	const char *look = val;
	while ((newline = strchr(look, '\n')) != NULL) {
		int thisWidth = surfaceMeasure.WidthText(font, look, newline - look);
		width = Platform::Maximum(width, thisWidth);
		look = newline + 1;
		numLines++;
	}
	int lastWidth = surfaceMeasure.WidthText(font, look, strlen(look));
	width = Platform::Maximum(width, lastWidth) + 10;
	int lineHeight = surfaceMeasure.Height(font);
	// Extra line for border and an empty line at top and bottom
	int height = lineHeight * numLines - surfaceMeasure.InternalLeading(font) + 2 + 2;
	return PRectangle(pt.x -5, pt.y + lineHeight + 1, pt.x + width - 5, pt.y + lineHeight + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}
<commit_msg>Fixed font leak.<commit_after>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	startHighlight = 0;
	endHighlight = 0;

	colourBG.desired = Colour(0xff, 0xff, 0xff);
	colourUnSel.desired = Colour(0x80, 0x80, 0x80);
	colourSel.desired = Colour(0, 0, 0x80);
	colourShade.desired = Colour(0, 0, 0);
	colourLight.desired = Colour(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
    font.Release();
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);
	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int lineHeight = surfaceWindow->Height(font);
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		int x = 5;
		int xEnd = x + surfaceWindow->WidthText(font, chunkVal, thisStartHighlight);
		rcClient.left = x;
		rcClient.top = ytext - ascent - 1;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal, thisStartHighlight,
		                        colourUnSel.allocated, colourBG.allocated);
		x = xEnd;

		xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisStartHighlight,
		                                    thisEndHighlight - thisStartHighlight);
		rcClient.top = ytext;
		rcClient.left = x;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal + thisStartHighlight, thisEndHighlight - thisStartHighlight,
		                        colourSel.allocated, colourBG.allocated);
		x = xEnd;

		xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisEndHighlight,
		                                    chunkLength - thisEndHighlight);
		rcClient.left = x;
		rcClient.right = xEnd;
		surfaceWindow->DrawText(rcClient, font, ytext,
		                        chunkVal + thisEndHighlight, chunkLength - thisEndHighlight,
		                        colourUnSel.allocated, colourBG.allocated);
		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
	}
	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size) {
	Surface surfaceMeasure;
	surfaceMeasure.Init();
	int deviceHeight = (size * surfaceMeasure.LogPixelsY()) / 72;
	font.Create(faceName, SC_CHARSET_DEFAULT, deviceHeight, false, false);
	if (val)
		delete []val;
	val = new char[strlen(defn) + 1];
	if (!val)
		return PRectangle();
	strcpy(val, defn);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int width = 0;
	int numLines = 1;
	const char *newline;
	const char *look = val;
	while ((newline = strchr(look, '\n')) != NULL) {
		int thisWidth = surfaceMeasure.WidthText(font, look, newline - look);
		width = Platform::Maximum(width, thisWidth);
		look = newline + 1;
		numLines++;
	}
	int lastWidth = surfaceMeasure.WidthText(font, look, strlen(look));
	width = Platform::Maximum(width, lastWidth) + 10;
	int lineHeight = surfaceMeasure.Height(font);
	// Extra line for border and an empty line at top and bottom
	int height = lineHeight * numLines - surfaceMeasure.InternalLeading(font) + 2 + 2;
	return PRectangle(pt.x -5, pt.y + lineHeight + 1, pt.x + width - 5, pt.y + lineHeight + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/socks5_stream.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{

	void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
		, boost::shared_ptr<handler_type> h)
	{
		if (e || i == tcp::resolver::iterator())
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_sock.async_connect(i->endpoint(), boost::bind(
			&socks5_stream::connected, this, _1, h));
	}

	void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;
		// send SOCKS5 authentication methods
		m_buffer.resize(m_user.empty()?3:4);
		char* p = &m_buffer[0];
		write_uint8(5, p); // SOCKS VERSION 5
		if (m_user.empty())
		{
			write_uint8(1, p); // 1 authentication method (no auth)
			write_uint8(0, p); // no authentication
		}
		else
		{
			write_uint8(2, p); // 2 authentication methods
			write_uint8(0, p); // no authentication
			write_uint8(2, p); // username/password
		}
		asio::async_write(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake1, this, _1, h));
	}

	void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(2);
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake2, this, _1, h));
	}

	void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		char* p = &m_buffer[0];
		int version = read_uint8(p);
		int method = read_uint8(p);

		if (version < 5)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		if (method == 0)
		{
			socks_connect(h);
		}
		else if (method == 2)
		{
			if (m_user.empty())
			{
				(*h)(asio::error::operation_not_supported);
				asio::error_code ec;
				close(ec);
				return;
			}

			// start sub-negotiation
			m_buffer.resize(m_user.size() + m_password.size() + 3);
			char* p = &m_buffer[0];
			write_uint8(1, p);
			write_uint8(m_user.size(), p);
			write_string(m_user, p);
			write_uint8(m_password.size(), p);
			write_string(m_password, p);
			asio::async_write(m_sock, asio::buffer(m_buffer)
				, boost::bind(&socks5_stream::handshake3, this, _1, h));
		}
		else
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
	}

	void socks5_stream::handshake3(asio::error_code const& e
		, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(2);
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake4, this, _1, h));
	}

	void socks5_stream::handshake4(asio::error_code const& e
		, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		char* p = &m_buffer[0];
		int version = read_uint8(p);
		int status = read_uint8(p);

		if (version != 1)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		if (status != 0)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		std::vector<char>().swap(m_buffer);
		(*h)(e);
	}

	void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
	{
		using namespace libtorrent::detail;

		// send SOCKS5 connect command
		m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
		char* p = &m_buffer[0];
		write_uint8(5, p); // SOCKS VERSION 5
		write_uint8(1, p); // CONNECT command
		write_uint8(0, p); // reserved
		write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
		write_address(m_remote_endpoint.address(), p);
		write_uint16(m_remote_endpoint.port(), p);
		TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size()));

		asio::async_write(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect1, this, _1, h));
	}

	void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(6 + 4); // assume an IPv4 address
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect2, this, _1, h));
	}

	void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		// send SOCKS5 connect command
		char* p = &m_buffer[0];
		int version = read_uint8(p);
		if (version < 5)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
		int response = read_uint8(p);
		if (response != 0)
		{
			asio::error_code e = asio::error::fault;
			switch (response)
			{
				case 1: e = asio::error::fault; break;
				case 2: e = asio::error::no_permission; break;
				case 3: e = asio::error::network_unreachable; break;
				case 4: e = asio::error::host_unreachable; break;
				case 5: e = asio::error::connection_refused; break;
				case 6: e = asio::error::timed_out; break;
				case 7: e = asio::error::operation_not_supported; break;
				case 8: e = asio::error::address_family_not_supported; break;
			}
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}
		p += 1; // reserved
		int atyp = read_uint8(p);
		// we ignore the proxy IP it was bound to
		if (atyp == 1)
		{
			std::vector<char>().swap(m_buffer);
			(*h)(e);
			return;
		}
		int skip_bytes = 0;
		if (atyp == 4)
		{
			skip_bytes = 12;
		}
		else if (atyp == 3)
		{
			skip_bytes = read_uint8(p) - 3;
		}
		else
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
		m_buffer.resize(skip_bytes);

		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect3, this, _1, h));
	}

	void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		std::vector<char>().swap(m_buffer);
		(*h)(e);
	}
}

<commit_msg>fixed bug in socks5 implementation when using user/pass authentication<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/socks5_stream.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{

	void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
		, boost::shared_ptr<handler_type> h)
	{
		if (e || i == tcp::resolver::iterator())
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_sock.async_connect(i->endpoint(), boost::bind(
			&socks5_stream::connected, this, _1, h));
	}

	void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;
		// send SOCKS5 authentication methods
		m_buffer.resize(m_user.empty()?3:4);
		char* p = &m_buffer[0];
		write_uint8(5, p); // SOCKS VERSION 5
		if (m_user.empty())
		{
			write_uint8(1, p); // 1 authentication method (no auth)
			write_uint8(0, p); // no authentication
		}
		else
		{
			write_uint8(2, p); // 2 authentication methods
			write_uint8(0, p); // no authentication
			write_uint8(2, p); // username/password
		}
		asio::async_write(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake1, this, _1, h));
	}

	void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(2);
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake2, this, _1, h));
	}

	void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		char* p = &m_buffer[0];
		int version = read_uint8(p);
		int method = read_uint8(p);

		if (version < 5)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		if (method == 0)
		{
			socks_connect(h);
		}
		else if (method == 2)
		{
			if (m_user.empty())
			{
				(*h)(asio::error::operation_not_supported);
				asio::error_code ec;
				close(ec);
				return;
			}

			// start sub-negotiation
			m_buffer.resize(m_user.size() + m_password.size() + 3);
			char* p = &m_buffer[0];
			write_uint8(1, p);
			write_uint8(m_user.size(), p);
			write_string(m_user, p);
			write_uint8(m_password.size(), p);
			write_string(m_password, p);
			asio::async_write(m_sock, asio::buffer(m_buffer)
				, boost::bind(&socks5_stream::handshake3, this, _1, h));
		}
		else
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
	}

	void socks5_stream::handshake3(asio::error_code const& e
		, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(2);
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::handshake4, this, _1, h));
	}

	void socks5_stream::handshake4(asio::error_code const& e
		, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		char* p = &m_buffer[0];
		int version = read_uint8(p);
		int status = read_uint8(p);

		if (version != 1)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		if (status != 0)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}

		std::vector<char>().swap(m_buffer);
		socks_connect(h);
	}

	void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
	{
		using namespace libtorrent::detail;

		// send SOCKS5 connect command
		m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
		char* p = &m_buffer[0];
		write_uint8(5, p); // SOCKS VERSION 5
		write_uint8(1, p); // CONNECT command
		write_uint8(0, p); // reserved
		write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
		write_address(m_remote_endpoint.address(), p);
		write_uint16(m_remote_endpoint.port(), p);
		TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size()));

		asio::async_write(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect1, this, _1, h));
	}

	void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		m_buffer.resize(6 + 4); // assume an IPv4 address
		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect2, this, _1, h));
	}

	void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		using namespace libtorrent::detail;

		// send SOCKS5 connect command
		char* p = &m_buffer[0];
		int version = read_uint8(p);
		if (version < 5)
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
		int response = read_uint8(p);
		if (response != 0)
		{
			asio::error_code e = asio::error::fault;
			switch (response)
			{
				case 1: e = asio::error::fault; break;
				case 2: e = asio::error::no_permission; break;
				case 3: e = asio::error::network_unreachable; break;
				case 4: e = asio::error::host_unreachable; break;
				case 5: e = asio::error::connection_refused; break;
				case 6: e = asio::error::timed_out; break;
				case 7: e = asio::error::operation_not_supported; break;
				case 8: e = asio::error::address_family_not_supported; break;
			}
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}
		p += 1; // reserved
		int atyp = read_uint8(p);
		// we ignore the proxy IP it was bound to
		if (atyp == 1)
		{
			std::vector<char>().swap(m_buffer);
			(*h)(e);
			return;
		}
		int skip_bytes = 0;
		if (atyp == 4)
		{
			skip_bytes = 12;
		}
		else if (atyp == 3)
		{
			skip_bytes = read_uint8(p) - 3;
		}
		else
		{
			(*h)(asio::error::operation_not_supported);
			asio::error_code ec;
			close(ec);
			return;
		}
		m_buffer.resize(skip_bytes);

		asio::async_read(m_sock, asio::buffer(m_buffer)
			, boost::bind(&socks5_stream::connect3, this, _1, h));
	}

	void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h)
	{
		if (e)
		{
			(*h)(e);
			asio::error_code ec;
			close(ec);
			return;
		}

		std::vector<char>().swap(m_buffer);
		(*h)(e);
	}
}

<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/cert_database.h"

#include <openssl/x509.h>

#include "base/logging.h"
#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/openssl_private_key_store.h"
#include "net/base/x509_certificate.h"

namespace net {

CertDatabase::CertDatabase() {
}

int CertDatabase::CheckUserCert(X509Certificate* cert) {
  if (!cert)
    return ERR_CERT_INVALID;
  if (cert->HasExpired())
    return ERR_CERT_DATE_INVALID;

  if (!OpenSSLPrivateKeyStore::GetInstance()->FetchPrivateKey(
      X509_PUBKEY_get(X509_get_X509_PUBKEY(cert->os_cert_handle()))))
    return ERR_NO_PRIVATE_KEY_FOR_CERT;

  return OK;
}

int CertDatabase::AddUserCert(X509Certificate* cert) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

void CertDatabase::ListCerts(CertificateList* certs) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
}

CryptoModule* CertDatabase::GetPublicModule() const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return NULL;
}

CryptoModule* CertDatabase::GetPrivateModule() const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return NULL;
}

void CertDatabase::ListModules(CryptoModuleList* modules, bool need_rw) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  modules->clear();
}

int CertDatabase::ImportFromPKCS12(CryptoModule* module,
                                   const std::string& data,
                                   const string16& password,
                                   bool is_extractable) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int CertDatabase::ExportToPKCS12(const CertificateList& certs,
                                 const string16& password,
                                 std::string* output) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return 0;
}

bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return false;
}

CertDatabase::TrustBits CertDatabase::GetCertTrust(const X509Certificate* cert,
                                                   CertType type) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return 0;
}

bool CertDatabase::SetCertTrust(const X509Certificate* cert,
                                CertType type,
                                TrustBits trust_bits) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return false;
}

}  // namespace net
<commit_msg>net: build fix for OpenSSL from r113998<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/cert_database.h"

#include <openssl/x509.h>

#include "base/logging.h"
#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/openssl_private_key_store.h"
#include "net/base/x509_certificate.h"

namespace net {

CertDatabase::CertDatabase() {
}

int CertDatabase::CheckUserCert(X509Certificate* cert) {
  if (!cert)
    return ERR_CERT_INVALID;
  if (cert->HasExpired())
    return ERR_CERT_DATE_INVALID;

  if (!OpenSSLPrivateKeyStore::GetInstance()->FetchPrivateKey(
      X509_PUBKEY_get(X509_get_X509_PUBKEY(cert->os_cert_handle()))))
    return ERR_NO_PRIVATE_KEY_FOR_CERT;

  return OK;
}

int CertDatabase::AddUserCert(X509Certificate* cert) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

void CertDatabase::ListCerts(CertificateList* certs) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
}

CryptoModule* CertDatabase::GetPublicModule() const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return NULL;
}

CryptoModule* CertDatabase::GetPrivateModule() const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return NULL;
}

void CertDatabase::ListModules(CryptoModuleList* modules, bool need_rw) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  modules->clear();
}

int CertDatabase::ImportFromPKCS12(CryptoModule* module,
                                   const std::string& data,
                                   const string16& password,
                                   bool is_extractable,
                                   CertificateList* imported_certs) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int CertDatabase::ExportToPKCS12(const CertificateList& certs,
                                 const string16& password,
                                 std::string* output) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return 0;
}

bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return false;
}

CertDatabase::TrustBits CertDatabase::GetCertTrust(const X509Certificate* cert,
                                                   CertType type) const {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return 0;
}

bool CertDatabase::SetCertTrust(const X509Certificate* cert,
                                CertType type,
                                TrustBits trust_bits) {
  // TODO(bulach): implement me.
  NOTIMPLEMENTED();
  return false;
}

}  // namespace net
<|endoftext|>


<commit_before>#include "AssemblyVisitor.h"

#include <stdexcept>

#include "Program.h"
#include "FunctionBlock.h"

#include "Binary.h"
#include "Unary.h"
#include "Add.h"
#include "Subtract.h"
#include "Multiply.h"
#include "Divide.h"
#include "Modulus.h"
#include "Negate.h"
#include "FuncCall.h"

#include "Variable.h"
#include "Value.h"

#include "AssignStmt.h"
#include "WriteStmt.h"
#include "ReturnStatement.h"

#include "LessThan.h"
#include "GreaterThan.h"

void AssemblyVisitor::Visit(const Program & p)
{
    _out << ".section .text" << std::endl
         << ".globl _start" << std::endl << std::endl
         << "_start:" << std::endl
         << "\tcall main" << std::endl
         << "\tjmp exit" << std::endl
         << ".include \"./x86asm/print_int.s\"" << std::endl;

    // Visit each FunctionBlock in Program
    Program::ListT funcs = p.GetFunctions();
    for (Program::ListT::const_iterator it = funcs.begin();
         it != funcs.end();
         ++it) {
        if (*it) {
            (*it)->Accept(*this);
        }
    }

    _out << ".type exit, @function" << std::endl
         << "exit:" << std::endl
         << "\tmovl $0, %ebx" << std::endl
         << "\tmovl $1, %eax" << std::endl
         << "\tint $0x80" << std::endl;
}

void AssemblyVisitor::Visit(const FunctionBlock & f)
{
    // get the current SymbolTable and store it on a stack of symbol tables?
    _currTable = f.GetSymbolTable();
    // Print prolog
    _out << ".global " << f.GetName() << std::endl
         << ".type " << f.GetName() << ", @function" << std::endl
         << f.GetName() << ":" << std::endl
         << "\tpushl %ebp /* base pointer on stack */" << std::endl
         << "\tmovl  %esp, %ebp /* change base pointer */" << std::endl;

    // make space for locals
    int localCount = f.GetVariableSpace();
    if (localCount != 0) {
        _out << "\taddl $" << (localCount) << ", %esp" << std::endl;
    }

    // visit statements
    StatementList const *stmts = f.GetStatements();
    StatementList::ListT slist = stmts->GetStatements();
    for (StatementList::ListT::const_iterator it = slist.begin();
         it != slist.end();
         ++it) {
        (*it)->Accept(*this);
    }

    // Print epilog
    _out << "\tmovl %ebp, %esp" << std::endl
         << "\tpopl %ebp /* restore base pointer */" << std::endl
         << "\tret" << std::endl;
}

void AssemblyVisitor::Visit(const Add & a)
{
    VisitBinary(a, "addl");
}

void AssemblyVisitor::Visit(const Divide & d)
{
    // I'm too lazy to make VisitBinary more generic...
    // get the two children results
    const Expr *l = d.GetLeft();
    const Expr *r = d.GetRight();
    if (!l || !r) {
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %ebx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // need to divide %eax by %ebx
    _out << "\tcltd" << std::endl
         << "\tidiv %ebx" << std::endl;
    // push result
	_out << "push %eax" << std::endl;
}

void AssemblyVisitor::Visit(const Modulus & d)
{
    // same as divide but return remainder
    // get the two children results
    const Expr *l = d.GetLeft();
    const Expr *r = d.GetRight();
    if (!l || !r) {
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %ebx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // need to divide %eax by %ebx
    _out << "\tcltd" << std::endl
         << "\tidiv %ebx" << std::endl;
    // push result (remainder)
	_out << "push %edx" << std::endl;
}

void AssemblyVisitor::Visit(const Multiply & m)
{
    VisitBinary(m, "imull");
}

void AssemblyVisitor::Visit(const Negate & n)
{
    VisitUnary(n, "negl");
}

void AssemblyVisitor::Visit(const Subtract & s)
{
    VisitBinary(s, "subl");
}

void AssemblyVisitor::Visit(const GreaterThan &g)
{
    //cmp arg2, arg1 does subtraction and sets flags
    VisitBinary(g, "cmp");
    _out << "" << std::endl;
}

void AssemblyVisitor::Visit(const LessThan &l)
{

    //cmp arg2, arg1 does subtraction and sets flags
    VisitBinary(l, "cmp");
    _out << "" << std::endl;
}

void AssemblyVisitor::Visit(const IfStmt & i)
{

    /** Notes
    * jne = branch not equal
    * je = branch equal
    */

    /*
    *   Plan of Attack
    *   Order in Assembly:
    *
    *
    *   Evaluate the "if"
    *   jne to ending tag
    *
    *   Put the stuff in the "if" down
    *
    *   Put ending tag at the end
    *
    */
    //@TODO figure out how the hell do to this

}

void AssemblyVisitor::Visit(const Value & v)
{
    // push on stack?
    _out << "\tpushl $" << v.Get() << std::endl;
}

void AssemblyVisitor::Visit(const Variable & v)
{
    // Look up in current symbol table, push some offset of ebp on stack
    if (!_currTable->DoesExist(v.GetName())) {
        std::cerr << "Undefined variable: " << v.GetName()
                  << ", on line " << v.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(v.GetName());
    _out << "\tpushl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const AssignStmt & a)
{
    // pop something and store it in some offset to ebp depending on var
    Expr const *value = a.GetValue();
    value->Accept(*this);
    // after visiting the RHS of the assignment, the answer is on the stack
    if (!_currTable->DoesExist(a.GetName())) {
        std::cerr << "FATAL: Undefined variable: " << a.GetName()
                  << ", on line " << a.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(a.GetName());
    _out << "\tpopl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const DecAssignStmt & a)
{
    // pop something and store it in some offset to ebp depending on var
    Expr const *value = a.GetValue();
    value->Accept(*this);
    // after visiting the RHS of the assignment, the answer is on the stack
    if (!_currTable->DoesExist(a.GetName())) {
        std::cerr << "FATAL: Undefined variable: " << a.GetName()
                  << ", on line " << a.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(a.GetName());
    _out << "\tpopl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const WriteStmt & w)
{
    // may need to evaluate the RHS, then just output "write ???"
    Expr const *value = w.GetExpr();
    value->Accept(*this);
    // this will evaluate the expression with the result on the stack
    _out << "\tcall print_int" << std::endl;
}

void AssemblyVisitor::Visit(const DeclStmt & d)
{
    // allocate space on stack for local, put in current symbol table?
    // this is already done, maybe we don't need a visitor here?
}

void AssemblyVisitor::Visit(const ReturnStmt & r)
{
    // return statement means writing something to eax
    Expr const *val = r.GetExpr();
    val->Accept(*this);
    _out << "\tpopl %eax" << std::endl;
}

void AssemblyVisitor::Visit(const FuncCall & f)
{
    // visit the parameters (which will push them, then call the function
    ExprList const* params = f.GetParams();
    ExprList::ListT l = params->GetExprs();
    for (ExprList::ListT::const_iterator it = l.begin();
         it != l.end();
         ++it) {
        (*it)->Accept(*this);
    }
    // now all params are on stack
    _out << "\tcall " << f.GetName() << std::endl;
    // this is an expression so take the result from %eax and push it
    _out << "\tpushl %eax" << std::endl;
}

void AssemblyVisitor::VisitBinary(const Binary &b, const std::string &op)
{
    // get the two children results
    const Expr *l = b.GetLeft();
    const Expr *r = b.GetRight();
    if (!l || !r) {
        // WTF, exception
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %edx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // do op (example addl %edx, %eax // will do %eax = %eax + %edx)
    _out << "\t" << op << " %edx, %eax" << std::endl;
    // push result
	_out << "\tpush %eax" << std::endl;
}

void AssemblyVisitor::VisitUnary(const Unary &u, const std::string &op)
{
    // get the child result
    const Expr *c = u.GetChild();
    if (!c) {
        // WTF, exception
        throw std::runtime_error("Could not evaluate unary expression");
    }
    c->Accept(*this);
    // grab result into register
	_out << "\tpopl %eax" << std::endl;
    // do op (example negl %eax // will do %eax = - %eax)
    _out << "\t" << op << " %eax" << std::endl;
    // push result
	_out << "push %eax" << std::endl;
}
<commit_msg>comments<commit_after>#include "AssemblyVisitor.h"

#include <stdexcept>

#include "Program.h"
#include "FunctionBlock.h"

#include "Binary.h"
#include "Unary.h"
#include "Add.h"
#include "Subtract.h"
#include "Multiply.h"
#include "Divide.h"
#include "Modulus.h"
#include "Negate.h"
#include "FuncCall.h"

#include "Variable.h"
#include "Value.h"

#include "AssignStmt.h"
#include "WriteStmt.h"
#include "ReturnStatement.h"

#include "LessThan.h"
#include "GreaterThan.h"

void AssemblyVisitor::Visit(const Program & p)
{
    _out << ".section .text" << std::endl
         << ".globl _start" << std::endl << std::endl
         << "_start:" << std::endl
         << "\tcall main" << std::endl
         << "\tjmp exit" << std::endl
         << ".include \"./x86asm/print_int.s\"" << std::endl;

    // Visit each FunctionBlock in Program
    Program::ListT funcs = p.GetFunctions();
    for (Program::ListT::const_iterator it = funcs.begin();
         it != funcs.end();
         ++it) {
        if (*it) {
            (*it)->Accept(*this);
        }
    }

    _out << ".type exit, @function" << std::endl
         << "exit:" << std::endl
         << "\tmovl $0, %ebx" << std::endl
         << "\tmovl $1, %eax" << std::endl
         << "\tint $0x80" << std::endl;
}

void AssemblyVisitor::Visit(const FunctionBlock & f)
{
    // get the current SymbolTable and store it on a stack of symbol tables?
    _currTable = f.GetSymbolTable();
    // Print prolog
    _out << ".global " << f.GetName() << std::endl
         << ".type " << f.GetName() << ", @function" << std::endl
         << f.GetName() << ":" << std::endl
         << "\tpushl %ebp /* base pointer on stack */" << std::endl
         << "\tmovl  %esp, %ebp /* change base pointer */" << std::endl;

    // make space for locals
    int localCount = f.GetVariableSpace();
    if (localCount != 0) {
        _out << "\taddl $" << (localCount) << ", %esp" << std::endl;
    }

    // visit statements
    StatementList const *stmts = f.GetStatements();
    StatementList::ListT slist = stmts->GetStatements();
    for (StatementList::ListT::const_iterator it = slist.begin();
         it != slist.end();
         ++it) {
        (*it)->Accept(*this);
    }

    // Print epilog
    _out << "\tmovl %ebp, %esp" << std::endl
         << "\tpopl %ebp /* restore base pointer */" << std::endl
         << "\tret" << std::endl;
}

void AssemblyVisitor::Visit(const Add & a)
{
    VisitBinary(a, "addl");
}

void AssemblyVisitor::Visit(const Divide & d)
{
    // I'm too lazy to make VisitBinary more generic...
    // get the two children results
    const Expr *l = d.GetLeft();
    const Expr *r = d.GetRight();
    if (!l || !r) {
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %ebx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // need to divide %eax by %ebx
    _out << "\tcltd" << std::endl
         << "\tidiv %ebx" << std::endl;
    // push result
	_out << "push %eax" << std::endl;
}

void AssemblyVisitor::Visit(const Modulus & d)
{
    // same as divide but return remainder
    // get the two children results
    const Expr *l = d.GetLeft();
    const Expr *r = d.GetRight();
    if (!l || !r) {
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %ebx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // need to divide %eax by %ebx
    _out << "\tcltd" << std::endl
         << "\tidiv %ebx" << std::endl;
    // push result (remainder)
	_out << "push %edx" << std::endl;
}

void AssemblyVisitor::Visit(const Multiply & m)
{
    VisitBinary(m, "imull");
}

void AssemblyVisitor::Visit(const Negate & n)
{
    VisitUnary(n, "negl");
}

void AssemblyVisitor::Visit(const Subtract & s)
{
    VisitBinary(s, "subl");
}

void AssemblyVisitor::Visit(const GreaterThan &g)
{
    //cmp arg2, arg1 does subtraction and sets flags
    VisitBinary(g, "cmp");
    _out << "" << std::endl;
}

void AssemblyVisitor::Visit(const LessThan &l)
{

    //cmp arg2, arg1 does subtraction and sets flags
    VisitBinary(l, "cmp");
    _out << "" << std::endl;
}

void AssemblyVisitor::Visit(const IfStmt & i)
{

    /** Notes
    * jne = branch not equal
    * je = branch equal
    * jl = branch less
    * jg = branch greater
    */

    /*
    *   Plan of Attack
    *   Order in Assembly:
    *
    *
    *   Evaluate the "if"
    *   jne to ending tag
    *
    *   Put the stuff in the "if" down
    *
    *   Put ending tag at the end
    *
    */
    //@TODO figure out how the hell do to this

}

void AssemblyVisitor::Visit(const Value & v)
{
    // push on stack?
    _out << "\tpushl $" << v.Get() << std::endl;
}

void AssemblyVisitor::Visit(const Variable & v)
{
    // Look up in current symbol table, push some offset of ebp on stack
    if (!_currTable->DoesExist(v.GetName())) {
        std::cerr << "Undefined variable: " << v.GetName()
                  << ", on line " << v.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(v.GetName());
    _out << "\tpushl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const AssignStmt & a)
{
    // pop something and store it in some offset to ebp depending on var
    Expr const *value = a.GetValue();
    value->Accept(*this);
    // after visiting the RHS of the assignment, the answer is on the stack
    if (!_currTable->DoesExist(a.GetName())) {
        std::cerr << "FATAL: Undefined variable: " << a.GetName()
                  << ", on line " << a.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(a.GetName());
    _out << "\tpopl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const DecAssignStmt & a)
{
    // pop something and store it in some offset to ebp depending on var
    Expr const *value = a.GetValue();
    value->Accept(*this);
    // after visiting the RHS of the assignment, the answer is on the stack
    if (!_currTable->DoesExist(a.GetName())) {
        std::cerr << "FATAL: Undefined variable: " << a.GetName()
                  << ", on line " << a.GetLine() << std::endl;
        throw std::logic_error("Undefined variable");
    }
    int off = _currTable->GetOffset(a.GetName());
    _out << "\tpopl " << off << "(%ebp)" << std::endl;
}

void AssemblyVisitor::Visit(const WriteStmt & w)
{
    // may need to evaluate the RHS, then just output "write ???"
    Expr const *value = w.GetExpr();
    value->Accept(*this);
    // this will evaluate the expression with the result on the stack
    _out << "\tcall print_int" << std::endl;
}

void AssemblyVisitor::Visit(const DeclStmt & d)
{
    // allocate space on stack for local, put in current symbol table?
    // this is already done, maybe we don't need a visitor here?
}

void AssemblyVisitor::Visit(const ReturnStmt & r)
{
    // return statement means writing something to eax
    Expr const *val = r.GetExpr();
    val->Accept(*this);
    _out << "\tpopl %eax" << std::endl;
}

void AssemblyVisitor::Visit(const FuncCall & f)
{
    // visit the parameters (which will push them, then call the function
    ExprList const* params = f.GetParams();
    ExprList::ListT l = params->GetExprs();
    for (ExprList::ListT::const_iterator it = l.begin();
         it != l.end();
         ++it) {
        (*it)->Accept(*this);
    }
    // now all params are on stack
    _out << "\tcall " << f.GetName() << std::endl;
    // this is an expression so take the result from %eax and push it
    _out << "\tpushl %eax" << std::endl;
}

void AssemblyVisitor::VisitBinary(const Binary &b, const std::string &op)
{
    // get the two children results
    const Expr *l = b.GetLeft();
    const Expr *r = b.GetRight();
    if (!l || !r) {
        // WTF, exception
        throw std::runtime_error("Could not evaluate binary expression");
    }
    l->Accept(*this);
    r->Accept(*this);
    // grab results into registers
	_out << "\tpopl %edx" << std::endl; // right
	_out << "\tpopl %eax" << std::endl; // left
    // do op (example addl %edx, %eax // will do %eax = %eax + %edx)
    _out << "\t" << op << " %edx, %eax" << std::endl;
    // push result
	_out << "\tpush %eax" << std::endl;
}

void AssemblyVisitor::VisitUnary(const Unary &u, const std::string &op)
{
    // get the child result
    const Expr *c = u.GetChild();
    if (!c) {
        // WTF, exception
        throw std::runtime_error("Could not evaluate unary expression");
    }
    c->Accept(*this);
    // grab result into register
	_out << "\tpopl %eax" << std::endl;
    // do op (example negl %eax // will do %eax = - %eax)
    _out << "\t" << op << " %eax" << std::endl;
    // push result
	_out << "push %eax" << std::endl;
}
<|endoftext|>