<commit_before>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// Instruments code to check for incorrect heap access. This checks
// for dereferencing 0 (null pointer access), reading past the valid
// top of sbrk()-addressible memory, and incorrect alignment notation.
//

#include "asmjs/shared-constants.h"
#include "ir/bits.h"
#include "ir/import-utils.h"
#include "ir/load-utils.h"
#include "pass.h"
#include "wasm-builder.h"
#include "wasm.h"

namespace wasm {

static const Name GET_SBRK_PTR("emscripten_get_sbrk_ptr");
static const Name SBRK("sbrk");
static const Name SEGFAULT_IMPORT("segfault");
static const Name ALIGNFAULT_IMPORT("alignfault");

static Name getLoadName(Load* curr) {
  std::string ret = "SAFE_HEAP_LOAD_";
  ret += curr->type.toString();
  ret += "_" + std::to_string(curr->bytes) + "_";
  if (LoadUtils::isSignRelevant(curr) && !curr->signed_) {
    ret += "U_";
  }
  if (curr->isAtomic) {
    ret += "A";
  } else {
    ret += std::to_string(curr->align);
  }
  return ret;
}

static Name getStoreName(Store* curr) {
  std::string ret = "SAFE_HEAP_STORE_";
  ret += curr->valueType.toString();
  ret += "_" + std::to_string(curr->bytes) + "_";
  if (curr->isAtomic) {
    ret += "A";
  } else {
    ret += std::to_string(curr->align);
  }
  return ret;
}

struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
  // If the getSbrkPtr function is implemented in the wasm, we must not
  // instrument that, as it would lead to infinite recursion of it calling
  // SAFE_HEAP_LOAD that calls it and so forth.
  // As well as the getSbrkPtr function we also avoid instrumenting the
  // module start function.  This is because this function is used in
  // shared memory builds to load the passive memory segments, which in
  // turn means that value of sbrk() is not available.
  Name getSbrkPtr;

  bool isFunctionParallel() override { return true; }

  AccessInstrumenter* create() override {
    return new AccessInstrumenter(getSbrkPtr);
  }

  AccessInstrumenter(Name getSbrkPtr) : getSbrkPtr(getSbrkPtr) {}

  void visitLoad(Load* curr) {
    if (getFunction()->name == getModule()->start ||
        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
      return;
    }
    Builder builder(*getModule());
    replaceCurrent(
      builder.makeCall(getLoadName(curr),
                       {curr->ptr, builder.makeConstPtr(curr->offset.addr)},
                       curr->type));
  }

  void visitStore(Store* curr) {
    if (getFunction()->name == getModule()->start ||
        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
      return;
    }
    Builder builder(*getModule());
    replaceCurrent(builder.makeCall(
      getStoreName(curr),
      {curr->ptr, builder.makeConstPtr(curr->offset.addr), curr->value},
      Type::none));
  }
};

struct SafeHeap : public Pass {
  PassOptions options;

  void run(PassRunner* runner, Module* module) override {
    options = runner->options;
    // add imports
    addImports(module);
    // instrument loads and stores
    AccessInstrumenter(getSbrkPtr).run(runner, module);
    // add helper checking funcs and imports
    addGlobals(module, module->features);
  }

  Name dynamicTopPtr, getSbrkPtr, sbrk, segfault, alignfault;

  void addImports(Module* module) {
    ImportInfo info(*module);
    auto indexType = module->memory.indexType;
    if (auto* existing = info.getImportedFunction(ENV, GET_SBRK_PTR)) {
      getSbrkPtr = existing->name;
    } else if (auto* existing = module->getExportOrNull(GET_SBRK_PTR)) {
      getSbrkPtr = existing->value;
    } else if (auto* existing = info.getImportedFunction(ENV, SBRK)) {
      sbrk = existing->name;
    } else {
      auto* import = new Function;
      import->name = getSbrkPtr = GET_SBRK_PTR;
      import->module = ENV;
      import->base = GET_SBRK_PTR;
      import->sig = Signature(Type::none, indexType);
      module->addFunction(import);
    }
    if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) {
      segfault = existing->name;
    } else {
      auto* import = new Function;
      import->name = segfault = SEGFAULT_IMPORT;
      import->module = ENV;
      import->base = SEGFAULT_IMPORT;
      import->sig = Signature(Type::none, Type::none);
      module->addFunction(import);
    }
    if (auto* existing = info.getImportedFunction(ENV, ALIGNFAULT_IMPORT)) {
      alignfault = existing->name;
    } else {
      auto* import = new Function;
      import->name = alignfault = ALIGNFAULT_IMPORT;
      import->module = ENV;
      import->base = ALIGNFAULT_IMPORT;
      import->sig = Signature(Type::none, Type::none);
      module->addFunction(import);
    }
  }

  bool
  isPossibleAtomicOperation(Index align, Index bytes, bool shared, Type type) {
    return align == bytes && shared && type.isInteger();
  }

  void addGlobals(Module* module, FeatureSet features) {
    // load funcs
    Load load;
    for (Type type : {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
      if (type == Type::v128 && !features.hasSIMD()) {
        continue;
      }
      load.type = type;
      for (Index bytes : {1, 2, 4, 8, 16}) {
        load.bytes = bytes;
        if (bytes > type.getByteSize() || (type == Type::f32 && bytes != 4) ||
            (type == Type::f64 && bytes != 8) ||
            (type == Type::v128 && bytes != 16)) {
          continue;
        }
        for (auto signed_ : {true, false}) {
          load.signed_ = signed_;
          if (type.isFloat() && signed_) {
            continue;
          }
          for (Index align : {1, 2, 4, 8, 16}) {
            load.align = align;
            if (align > bytes) {
              continue;
            }
            for (auto isAtomic : {true, false}) {
              load.isAtomic = isAtomic;
              if (isAtomic && !isPossibleAtomicOperation(
                                align, bytes, module->memory.shared, type)) {
                continue;
              }
              addLoadFunc(load, module);
            }
          }
        }
      }
    }
    // store funcs
    Store store;
    for (Type valueType :
         {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
      if (valueType == Type::v128 && !features.hasSIMD()) {
        continue;
      }
      store.valueType = valueType;
      store.type = Type::none;
      for (Index bytes : {1, 2, 4, 8, 16}) {
        store.bytes = bytes;
        if (bytes > valueType.getByteSize() ||
            (valueType == Type::f32 && bytes != 4) ||
            (valueType == Type::f64 && bytes != 8) ||
            (valueType == Type::v128 && bytes != 16)) {
          continue;
        }
        for (Index align : {1, 2, 4, 8, 16}) {
          store.align = align;
          if (align > bytes) {
            continue;
          }
          for (auto isAtomic : {true, false}) {
            store.isAtomic = isAtomic;
            if (isAtomic && !isPossibleAtomicOperation(
                              align, bytes, module->memory.shared, valueType)) {
              continue;
            }
            addStoreFunc(store, module);
          }
        }
      }
    }
  }

  // creates a function for a particular style of load
  void addLoadFunc(Load style, Module* module) {
    auto name = getLoadName(&style);
    if (module->getFunctionOrNull(name)) {
      return;
    }
    auto* func = new Function;
    func->name = name;
    // pointer, offset
    auto indexType = module->memory.indexType;
    func->sig = Signature({indexType, indexType}, style.type);
    func->vars.push_back(indexType); // pointer + offset
    Builder builder(*module);
    auto* block = builder.makeBlock();
    block->list.push_back(builder.makeLocalSet(
      2,
      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
                         builder.makeLocalGet(0, indexType),
                         builder.makeLocalGet(1, indexType))));
    // check for reading past valid memory: if pointer + offset + bytes
    block->list.push_back(
      makeBoundsCheck(style.type, builder, 2, style.bytes, module));
    // check proper alignment
    if (style.align > 1) {
      block->list.push_back(makeAlignCheck(style.align, builder, 2, module));
    }
    // do the load
    auto* load = module->allocator.alloc<Load>();
    *load = style; // basically the same as the template we are given!
    load->ptr = builder.makeLocalGet(2, indexType);
    Expression* last = load;
    if (load->isAtomic && load->signed_) {
      // atomic loads cannot be signed, manually sign it
      last = Bits::makeSignExt(load, load->bytes, *module);
      load->signed_ = false;
    }
    block->list.push_back(last);
    block->finalize(style.type);
    func->body = block;
    module->addFunction(func);
  }

  // creates a function for a particular type of store
  void addStoreFunc(Store style, Module* module) {
    auto name = getStoreName(&style);
    if (module->getFunctionOrNull(name)) {
      return;
    }
    auto* func = new Function;
    func->name = name;
    // pointer, offset, value
    auto indexType = module->memory.indexType;
    func->sig = Signature({indexType, indexType, style.valueType}, Type::none);
    func->vars.push_back(indexType); // pointer + offset
    Builder builder(*module);
    auto* block = builder.makeBlock();
    block->list.push_back(builder.makeLocalSet(
      3,
      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
                         builder.makeLocalGet(0, indexType),
                         builder.makeLocalGet(1, indexType))));
    // check for reading past valid memory: if pointer + offset + bytes
    block->list.push_back(
      makeBoundsCheck(style.valueType, builder, 3, style.bytes, module));
    // check proper alignment
    if (style.align > 1) {
      block->list.push_back(makeAlignCheck(style.align, builder, 3, module));
    }
    // do the store
    auto* store = module->allocator.alloc<Store>();
    *store = style; // basically the same as the template we are given!
    store->ptr = builder.makeLocalGet(3, indexType);
    store->value = builder.makeLocalGet(2, style.valueType);
    block->list.push_back(store);
    block->finalize(Type::none);
    func->body = block;
    module->addFunction(func);
  }

  Expression*
  makeAlignCheck(Address align, Builder& builder, Index local, Module* module) {
    auto indexType = module->memory.indexType;
    Expression* ptrBits = builder.makeLocalGet(local, indexType);
    if (module->memory.is64()) {
      ptrBits = builder.makeUnary(WrapInt64, ptrBits);
    }
    return builder.makeIf(
      builder.makeBinary(
        AndInt32, ptrBits, builder.makeConst(int32_t(align - 1))),
      builder.makeCall(alignfault, {}, Type::none));
  }

  Expression* makeBoundsCheck(
    Type type, Builder& builder, Index local, Index bytes, Module* module) {
    auto indexType = module->memory.indexType;
    auto upperOp = module->memory.is64()
                     ? options.lowMemoryUnused ? LtUInt64 : EqInt64
                     : options.lowMemoryUnused ? LtUInt32 : EqInt32;
    auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
    Expression* brkLocation;
    if (sbrk.is()) {
      brkLocation =
        builder.makeCall(sbrk, {builder.makeConstPtr(0)}, indexType);
    } else {
      Expression* sbrkPtr;
      if (dynamicTopPtr.is()) {
        sbrkPtr = builder.makeGlobalGet(dynamicTopPtr, indexType);
      } else {
        sbrkPtr = builder.makeCall(getSbrkPtr, {}, indexType);
      }
      auto size = module->memory.is64() ? 8 : 4;
      brkLocation = builder.makeLoad(size, false, 0, size, sbrkPtr, indexType);
    }
    auto gtuOp = module->memory.is64() ? GtUInt64 : GtUInt32;
    auto addOp = module->memory.is64() ? AddInt64 : AddInt32;
    return builder.makeIf(
      builder.makeBinary(
        OrInt32,
        builder.makeBinary(upperOp,
                           builder.makeLocalGet(local, indexType),
                           builder.makeConstPtr(upperBound)),
        builder.makeBinary(
          gtuOp,
          builder.makeBinary(addOp,
                             builder.makeLocalGet(local, indexType),
                             builder.makeConstPtr(bytes)),
          brkLocation)),
      builder.makeCall(segfault, {}, Type::none));
  }
};

Pass* createSafeHeapPass() { return new SafeHeap(); }

} // namespace wasm
<commit_msg>Add comment a followup to #3424. NFC. (#3449)<commit_after>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// Instruments code to check for incorrect heap access. This checks
// for dereferencing 0 (null pointer access), reading past the valid
// top of sbrk()-addressible memory, and incorrect alignment notation.
//

#include "asmjs/shared-constants.h"
#include "ir/bits.h"
#include "ir/import-utils.h"
#include "ir/load-utils.h"
#include "pass.h"
#include "wasm-builder.h"
#include "wasm.h"

namespace wasm {

static const Name GET_SBRK_PTR("emscripten_get_sbrk_ptr");
static const Name SBRK("sbrk");
static const Name SEGFAULT_IMPORT("segfault");
static const Name ALIGNFAULT_IMPORT("alignfault");

static Name getLoadName(Load* curr) {
  std::string ret = "SAFE_HEAP_LOAD_";
  ret += curr->type.toString();
  ret += "_" + std::to_string(curr->bytes) + "_";
  if (LoadUtils::isSignRelevant(curr) && !curr->signed_) {
    ret += "U_";
  }
  if (curr->isAtomic) {
    ret += "A";
  } else {
    ret += std::to_string(curr->align);
  }
  return ret;
}

static Name getStoreName(Store* curr) {
  std::string ret = "SAFE_HEAP_STORE_";
  ret += curr->valueType.toString();
  ret += "_" + std::to_string(curr->bytes) + "_";
  if (curr->isAtomic) {
    ret += "A";
  } else {
    ret += std::to_string(curr->align);
  }
  return ret;
}

struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
  // If the getSbrkPtr function is implemented in the wasm, we must not
  // instrument that, as it would lead to infinite recursion of it calling
  // SAFE_HEAP_LOAD that calls it and so forth.
  // As well as the getSbrkPtr function we also avoid instrumenting the
  // module start function.  This is because this function is used in
  // shared memory builds to load the passive memory segments, which in
  // turn means that value of sbrk() is not available.
  Name getSbrkPtr;

  bool isFunctionParallel() override { return true; }

  AccessInstrumenter* create() override {
    return new AccessInstrumenter(getSbrkPtr);
  }

  AccessInstrumenter(Name getSbrkPtr) : getSbrkPtr(getSbrkPtr) {}

  void visitLoad(Load* curr) {
    // As well as the getSbrkPtr function we also avoid insturmenting the
    // module start function.  This is because this function is used in
    // shared memory builds to load the passive memory segments, which in
    // turn means that value of sbrk() is not available.
    if (getFunction()->name == getModule()->start ||
        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
      return;
    }
    Builder builder(*getModule());
    replaceCurrent(
      builder.makeCall(getLoadName(curr),
                       {curr->ptr, builder.makeConstPtr(curr->offset.addr)},
                       curr->type));
  }

  void visitStore(Store* curr) {
    if (getFunction()->name == getModule()->start ||
        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
      return;
    }
    Builder builder(*getModule());
    replaceCurrent(builder.makeCall(
      getStoreName(curr),
      {curr->ptr, builder.makeConstPtr(curr->offset.addr), curr->value},
      Type::none));
  }
};

struct SafeHeap : public Pass {
  PassOptions options;

  void run(PassRunner* runner, Module* module) override {
    options = runner->options;
    // add imports
    addImports(module);
    // instrument loads and stores
    AccessInstrumenter(getSbrkPtr).run(runner, module);
    // add helper checking funcs and imports
    addGlobals(module, module->features);
  }

  Name dynamicTopPtr, getSbrkPtr, sbrk, segfault, alignfault;

  void addImports(Module* module) {
    ImportInfo info(*module);
    auto indexType = module->memory.indexType;
    if (auto* existing = info.getImportedFunction(ENV, GET_SBRK_PTR)) {
      getSbrkPtr = existing->name;
    } else if (auto* existing = module->getExportOrNull(GET_SBRK_PTR)) {
      getSbrkPtr = existing->value;
    } else if (auto* existing = info.getImportedFunction(ENV, SBRK)) {
      sbrk = existing->name;
    } else {
      auto* import = new Function;
      import->name = getSbrkPtr = GET_SBRK_PTR;
      import->module = ENV;
      import->base = GET_SBRK_PTR;
      import->sig = Signature(Type::none, indexType);
      module->addFunction(import);
    }
    if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) {
      segfault = existing->name;
    } else {
      auto* import = new Function;
      import->name = segfault = SEGFAULT_IMPORT;
      import->module = ENV;
      import->base = SEGFAULT_IMPORT;
      import->sig = Signature(Type::none, Type::none);
      module->addFunction(import);
    }
    if (auto* existing = info.getImportedFunction(ENV, ALIGNFAULT_IMPORT)) {
      alignfault = existing->name;
    } else {
      auto* import = new Function;
      import->name = alignfault = ALIGNFAULT_IMPORT;
      import->module = ENV;
      import->base = ALIGNFAULT_IMPORT;
      import->sig = Signature(Type::none, Type::none);
      module->addFunction(import);
    }
  }

  bool
  isPossibleAtomicOperation(Index align, Index bytes, bool shared, Type type) {
    return align == bytes && shared && type.isInteger();
  }

  void addGlobals(Module* module, FeatureSet features) {
    // load funcs
    Load load;
    for (Type type : {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
      if (type == Type::v128 && !features.hasSIMD()) {
        continue;
      }
      load.type = type;
      for (Index bytes : {1, 2, 4, 8, 16}) {
        load.bytes = bytes;
        if (bytes > type.getByteSize() || (type == Type::f32 && bytes != 4) ||
            (type == Type::f64 && bytes != 8) ||
            (type == Type::v128 && bytes != 16)) {
          continue;
        }
        for (auto signed_ : {true, false}) {
          load.signed_ = signed_;
          if (type.isFloat() && signed_) {
            continue;
          }
          for (Index align : {1, 2, 4, 8, 16}) {
            load.align = align;
            if (align > bytes) {
              continue;
            }
            for (auto isAtomic : {true, false}) {
              load.isAtomic = isAtomic;
              if (isAtomic && !isPossibleAtomicOperation(
                                align, bytes, module->memory.shared, type)) {
                continue;
              }
              addLoadFunc(load, module);
            }
          }
        }
      }
    }
    // store funcs
    Store store;
    for (Type valueType :
         {Type::i32, Type::i64, Type::f32, Type::f64, Type::v128}) {
      if (valueType == Type::v128 && !features.hasSIMD()) {
        continue;
      }
      store.valueType = valueType;
      store.type = Type::none;
      for (Index bytes : {1, 2, 4, 8, 16}) {
        store.bytes = bytes;
        if (bytes > valueType.getByteSize() ||
            (valueType == Type::f32 && bytes != 4) ||
            (valueType == Type::f64 && bytes != 8) ||
            (valueType == Type::v128 && bytes != 16)) {
          continue;
        }
        for (Index align : {1, 2, 4, 8, 16}) {
          store.align = align;
          if (align > bytes) {
            continue;
          }
          for (auto isAtomic : {true, false}) {
            store.isAtomic = isAtomic;
            if (isAtomic && !isPossibleAtomicOperation(
                              align, bytes, module->memory.shared, valueType)) {
              continue;
            }
            addStoreFunc(store, module);
          }
        }
      }
    }
  }

  // creates a function for a particular style of load
  void addLoadFunc(Load style, Module* module) {
    auto name = getLoadName(&style);
    if (module->getFunctionOrNull(name)) {
      return;
    }
    auto* func = new Function;
    func->name = name;
    // pointer, offset
    auto indexType = module->memory.indexType;
    func->sig = Signature({indexType, indexType}, style.type);
    func->vars.push_back(indexType); // pointer + offset
    Builder builder(*module);
    auto* block = builder.makeBlock();
    block->list.push_back(builder.makeLocalSet(
      2,
      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
                         builder.makeLocalGet(0, indexType),
                         builder.makeLocalGet(1, indexType))));
    // check for reading past valid memory: if pointer + offset + bytes
    block->list.push_back(
      makeBoundsCheck(style.type, builder, 2, style.bytes, module));
    // check proper alignment
    if (style.align > 1) {
      block->list.push_back(makeAlignCheck(style.align, builder, 2, module));
    }
    // do the load
    auto* load = module->allocator.alloc<Load>();
    *load = style; // basically the same as the template we are given!
    load->ptr = builder.makeLocalGet(2, indexType);
    Expression* last = load;
    if (load->isAtomic && load->signed_) {
      // atomic loads cannot be signed, manually sign it
      last = Bits::makeSignExt(load, load->bytes, *module);
      load->signed_ = false;
    }
    block->list.push_back(last);
    block->finalize(style.type);
    func->body = block;
    module->addFunction(func);
  }

  // creates a function for a particular type of store
  void addStoreFunc(Store style, Module* module) {
    auto name = getStoreName(&style);
    if (module->getFunctionOrNull(name)) {
      return;
    }
    auto* func = new Function;
    func->name = name;
    // pointer, offset, value
    auto indexType = module->memory.indexType;
    func->sig = Signature({indexType, indexType, style.valueType}, Type::none);
    func->vars.push_back(indexType); // pointer + offset
    Builder builder(*module);
    auto* block = builder.makeBlock();
    block->list.push_back(builder.makeLocalSet(
      3,
      builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
                         builder.makeLocalGet(0, indexType),
                         builder.makeLocalGet(1, indexType))));
    // check for reading past valid memory: if pointer + offset + bytes
    block->list.push_back(
      makeBoundsCheck(style.valueType, builder, 3, style.bytes, module));
    // check proper alignment
    if (style.align > 1) {
      block->list.push_back(makeAlignCheck(style.align, builder, 3, module));
    }
    // do the store
    auto* store = module->allocator.alloc<Store>();
    *store = style; // basically the same as the template we are given!
    store->ptr = builder.makeLocalGet(3, indexType);
    store->value = builder.makeLocalGet(2, style.valueType);
    block->list.push_back(store);
    block->finalize(Type::none);
    func->body = block;
    module->addFunction(func);
  }

  Expression*
  makeAlignCheck(Address align, Builder& builder, Index local, Module* module) {
    auto indexType = module->memory.indexType;
    Expression* ptrBits = builder.makeLocalGet(local, indexType);
    if (module->memory.is64()) {
      ptrBits = builder.makeUnary(WrapInt64, ptrBits);
    }
    return builder.makeIf(
      builder.makeBinary(
        AndInt32, ptrBits, builder.makeConst(int32_t(align - 1))),
      builder.makeCall(alignfault, {}, Type::none));
  }

  Expression* makeBoundsCheck(
    Type type, Builder& builder, Index local, Index bytes, Module* module) {
    auto indexType = module->memory.indexType;
    auto upperOp = module->memory.is64()
                     ? options.lowMemoryUnused ? LtUInt64 : EqInt64
                     : options.lowMemoryUnused ? LtUInt32 : EqInt32;
    auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
    Expression* brkLocation;
    if (sbrk.is()) {
      brkLocation =
        builder.makeCall(sbrk, {builder.makeConstPtr(0)}, indexType);
    } else {
      Expression* sbrkPtr;
      if (dynamicTopPtr.is()) {
        sbrkPtr = builder.makeGlobalGet(dynamicTopPtr, indexType);
      } else {
        sbrkPtr = builder.makeCall(getSbrkPtr, {}, indexType);
      }
      auto size = module->memory.is64() ? 8 : 4;
      brkLocation = builder.makeLoad(size, false, 0, size, sbrkPtr, indexType);
    }
    auto gtuOp = module->memory.is64() ? GtUInt64 : GtUInt32;
    auto addOp = module->memory.is64() ? AddInt64 : AddInt32;
    return builder.makeIf(
      builder.makeBinary(
        OrInt32,
        builder.makeBinary(upperOp,
                           builder.makeLocalGet(local, indexType),
                           builder.makeConstPtr(upperBound)),
        builder.makeBinary(
          gtuOp,
          builder.makeBinary(addOp,
                             builder.makeLocalGet(local, indexType),
                             builder.makeConstPtr(bytes)),
          brkLocation)),
      builder.makeCall(segfault, {}, Type::none));
  }
};

Pass* createSafeHeapPass() { return new SafeHeap(); }

} // namespace wasm
<|endoftext|>


<commit_before>/**
 *  @file api_tests.cpp
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <boost/test/unit_test.hpp>
#pragma GCC diagnostic pop

#include <eosio/testing/tester.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/resource_limits.hpp>

#include <fc/exception/exception.hpp>
#include <fc/variant_object.hpp>

#include "eosio_system_tester.hpp"

#include <test_ram_limit/test_ram_limit.abi.hpp>
#include <test_ram_limit/test_ram_limit.wast.hpp>

#define DISABLE_EOSLIB_SERIALIZE
#include <test_api/test_api_common.hpp>

/*
 * register test suite `ram_tests`
 */
BOOST_AUTO_TEST_SUITE(ram_tests)

/*************************************************************************************
 * ram_tests test case
 *************************************************************************************/
BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try {
   auto init_request_bytes = 80000;
   const auto increment_contract_bytes = 10000;
   const auto table_allocation_bytes = 12000;
   BOOST_REQUIRE_MESSAGE(table_allocation_bytes > increment_contract_bytes, "increment_contract_bytes must be less than table_allocation_bytes for this test setup to work");
   buyrambytes(N(eosio), N(eosio), 70000);
   produce_blocks(10);
   create_account_with_resources(N(testram11111),N(eosio), init_request_bytes);
   create_account_with_resources(N(testram22222),N(eosio), init_request_bytes + 1150);
   produce_blocks(10);
   BOOST_REQUIRE_EQUAL( success(), stake( "eosio.stake", "testram11111", core_from_string("10.0000"), core_from_string("5.0000") ) );
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_code( N(testram11111), test_ram_limit_wast );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(N(eosio), N(testram11111), increment_contract_bytes);
         buyrambytes(N(eosio), N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_abi( N(testram11111), test_ram_limit_abi );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(N(eosio), N(testram11111), increment_contract_bytes);
         buyrambytes(N(eosio), N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);
   set_code( N(testram22222), test_ram_limit_wast );
   set_abi( N(testram22222), test_ram_limit_abi );
   produce_blocks(10);

   auto total = get_total_stake( N(testram11111) );
   const auto init_bytes =  total["ram_bytes"].as_uint64();

   auto rlm = control->get_resource_limits_manager();
   auto initial_ram_usage = rlm.get_account_ram_usage(N(testram11111));

   // calculate how many more bytes we need to have table_allocation_bytes for database stores
   auto more_ram = table_allocation_bytes + init_bytes - init_request_bytes;
   BOOST_REQUIRE_MESSAGE(more_ram >= 0, "Underlying understanding changed, need to reduce size of init_request_bytes");
   wdump((init_bytes)(initial_ram_usage)(init_request_bytes)(more_ram) );
   buyrambytes(N(eosio), N(testram11111), more_ram);
   buyrambytes(N(eosio), N(testram22222), more_ram);

   TESTER* tester = this;
   // allocate just under the allocated bytes
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        ("size", 1780 /*1910*/));
   produce_blocks(1);
   auto ram_usage = rlm.get_account_ram_usage(N(testram11111));

   total = get_total_stake( N(testram11111) );
   const auto ram_bytes =  total["ram_bytes"].as_uint64();
   wdump((ram_bytes)(ram_usage)(initial_ram_usage)(init_bytes)(ram_usage - initial_ram_usage)(init_bytes - ram_usage) );

   wlog("ram_tests 1    %%%%%%");
   // allocate just beyond the allocated bytes
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 10)
                           ("size", 1790 /*1920*/)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   wlog("ram_tests 2    %%%%%%");
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage, rlm.get_account_ram_usage(N(testram11111)));

   // update the entries with smaller allocations so that we can verify space is freed and new allocations can be made
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        ("size", 1680/*1810*/));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the added entry is beyond the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 11)
                           ("size", 1680/*1810*/)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the new entry's bytes minus the freed up bytes for existing entries still exceeds the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 11)
                           ("size", 1760)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the new entry's bytes minus the freed up bytes for existing entries are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 11)
                        ("size", 1600/*1720*/));
   produce_blocks(1);

   tester->push_action( N(testram11111), N(rmentry), N(testram11111), mvo()
                        ("from", 3)
                        ("to", 3));
   produce_blocks(1);

   // verify that the new entry will exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 12)
                           ("to", 12)
                           ("size", 1780)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   // verify that the new entry is under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 12)
                        ("to", 12)
                        ("size", 1620/*1720*/));
   produce_blocks(1);

   // verify that anoth new entry will exceed the allocation bytes limit, to setup testing of new payer
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1660)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   // verify that the new entry is under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 12)
                        ("size", 1720));
   produce_blocks(1);

   // verify that another new entry that is too big will exceed the allocation bytes limit, to setup testing of new payer
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1900)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   wlog("ram_tests 18    %%%%%%");
   // verify that the new entry is under the allocation bytes limit, because entry 12 is now charged to testram22222
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 13)
                        ("to", 13)
                        ("size", 1720));
   produce_blocks(1);

   // verify that new entries for testram22222 exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 12)
                           ("to", 21)
                           ("size", 1930)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

   // verify that new entries for testram22222 are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 21)
                        ("size", 1910));
   produce_blocks(1);

   // verify that new entry for testram22222 exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 22)
                           ("to", 22)
                           ("size", 1910)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

   tester->push_action( N(testram11111), N(rmentry), N(testram11111), mvo()
                        ("from", 20)
                        ("to", 20));
   produce_blocks(1);

   // verify that new entry for testram22222 are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 22)
                        ("to", 22)
                        ("size", 1910));
   produce_blocks(1);

} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fix ram_tests<commit_after>/**
 *  @file api_tests.cpp
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <boost/test/unit_test.hpp>
#pragma GCC diagnostic pop

#include <eosio/testing/tester.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/resource_limits.hpp>

#include <fc/exception/exception.hpp>
#include <fc/variant_object.hpp>

#include "eosio_system_tester.hpp"

#include <test_ram_limit/test_ram_limit.abi.hpp>
#include <test_ram_limit/test_ram_limit.wast.hpp>

#define DISABLE_EOSLIB_SERIALIZE
#include <test_api/test_api_common.hpp>

/*
 * register test suite `ram_tests`
 */
BOOST_AUTO_TEST_SUITE(ram_tests)

/*************************************************************************************
 * ram_tests test case
 *************************************************************************************/
BOOST_FIXTURE_TEST_CASE(ram_tests, eosio_system::eosio_system_tester) { try {
   auto init_request_bytes = 80000;
   const auto increment_contract_bytes = 10000;
   const auto table_allocation_bytes = 12000;
   BOOST_REQUIRE_MESSAGE(table_allocation_bytes > increment_contract_bytes, "increment_contract_bytes must be less than table_allocation_bytes for this test setup to work");
   buyrambytes(N(eosio), N(eosio), 70000);
   produce_blocks(10);
   create_account_with_resources(N(testram11111),N(eosio), init_request_bytes + 40);
   create_account_with_resources(N(testram22222),N(eosio), init_request_bytes + 1190);
   produce_blocks(10);
   BOOST_REQUIRE_EQUAL( success(), stake( "eosio.stake", "testram11111", core_from_string("10.0000"), core_from_string("5.0000") ) );
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_code( N(testram11111), test_ram_limit_wast );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(N(eosio), N(testram11111), increment_contract_bytes);
         buyrambytes(N(eosio), N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);

   for (auto i = 0; i < 10; ++i) {
      try {
         set_abi( N(testram11111), test_ram_limit_abi );
         break;
      } catch (const ram_usage_exceeded&) {
         init_request_bytes += increment_contract_bytes;
         buyrambytes(N(eosio), N(testram11111), increment_contract_bytes);
         buyrambytes(N(eosio), N(testram22222), increment_contract_bytes);
      }
   }
   produce_blocks(10);
   set_code( N(testram22222), test_ram_limit_wast );
   set_abi( N(testram22222), test_ram_limit_abi );
   produce_blocks(10);

   auto total = get_total_stake( N(testram11111) );
   const auto init_bytes =  total["ram_bytes"].as_uint64();

   auto rlm = control->get_resource_limits_manager();
   auto initial_ram_usage = rlm.get_account_ram_usage(N(testram11111));

   // calculate how many more bytes we need to have table_allocation_bytes for database stores
   auto more_ram = table_allocation_bytes + init_bytes - init_request_bytes;
   BOOST_REQUIRE_MESSAGE(more_ram >= 0, "Underlying understanding changed, need to reduce size of init_request_bytes");
   wdump((init_bytes)(initial_ram_usage)(init_request_bytes)(more_ram) );
   buyrambytes(N(eosio), N(testram11111), more_ram);
   buyrambytes(N(eosio), N(testram22222), more_ram);

   TESTER* tester = this;
   // allocate just under the allocated bytes
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        ("size", 1780 /*1910*/));
   produce_blocks(1);
   auto ram_usage = rlm.get_account_ram_usage(N(testram11111));

   total = get_total_stake( N(testram11111) );
   const auto ram_bytes =  total["ram_bytes"].as_uint64();
   wdump((ram_bytes)(ram_usage)(initial_ram_usage)(init_bytes)(ram_usage - initial_ram_usage)(init_bytes - ram_usage) );

   wlog("ram_tests 1    %%%%%%");
   // allocate just beyond the allocated bytes
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 10)
                           ("size", 1790 /*1920*/)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   wlog("ram_tests 2    %%%%%%");
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage, rlm.get_account_ram_usage(N(testram11111)));

   // update the entries with smaller allocations so that we can verify space is freed and new allocations can be made
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 10)
                        ("size", 1680/*1810*/));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the added entry is beyond the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 11)
                           ("size", 1680/*1810*/)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the new entry's bytes minus the freed up bytes for existing entries still exceeds the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 1)
                           ("to", 11)
                           ("size", 1760)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);
   BOOST_REQUIRE_EQUAL(ram_usage - 1000, rlm.get_account_ram_usage(N(testram11111)));

   // verify the new entry's bytes minus the freed up bytes for existing entries are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 1)
                        ("to", 11)
                        ("size", 1600/*1720*/));
   produce_blocks(1);

   tester->push_action( N(testram11111), N(rmentry), N(testram11111), mvo()
                        ("from", 3)
                        ("to", 3));
   produce_blocks(1);

   // verify that the new entry will exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 12)
                           ("to", 12)
                           ("size", 1780)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   // verify that the new entry is under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 12)
                        ("to", 12)
                        ("size", 1620/*1720*/));
   produce_blocks(1);

   // verify that anoth new entry will exceed the allocation bytes limit, to setup testing of new payer
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1660)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   // verify that the new entry is under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 12)
                        ("size", 1720));
   produce_blocks(1);

   // verify that another new entry that is too big will exceed the allocation bytes limit, to setup testing of new payer
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                           ("payer", "testram11111")
                           ("from", 13)
                           ("to", 13)
                           ("size", 1900)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram11111 has insufficient ram"));
   produce_blocks(1);

   wlog("ram_tests 18    %%%%%%");
   // verify that the new entry is under the allocation bytes limit, because entry 12 is now charged to testram22222
   tester->push_action( N(testram11111), N(setentry), N(testram11111), mvo()
                        ("payer", "testram11111")
                        ("from", 13)
                        ("to", 13)
                        ("size", 1720));
   produce_blocks(1);

   // verify that new entries for testram22222 exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 12)
                           ("to", 21)
                           ("size", 1930)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

   // verify that new entries for testram22222 are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 12)
                        ("to", 21)
                        ("size", 1910));
   produce_blocks(1);

   // verify that new entry for testram22222 exceed the allocation bytes limit
   BOOST_REQUIRE_EXCEPTION(
      tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                           ("payer", "testram22222")
                           ("from", 22)
                           ("to", 22)
                           ("size", 1910)),
                           ram_usage_exceeded,
                           fc_exception_message_starts_with("account testram22222 has insufficient ram"));
   produce_blocks(1);

   tester->push_action( N(testram11111), N(rmentry), N(testram11111), mvo()
                        ("from", 20)
                        ("to", 20));
   produce_blocks(1);

   // verify that new entry for testram22222 are under the allocation bytes limit
   tester->push_action( N(testram11111), N(setentry), {N(testram11111),N(testram22222)}, mvo()
                        ("payer", "testram22222")
                        ("from", 22)
                        ("to", 22)
                        ("size", 1910));
   produce_blocks(1);

} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file trjactory_cost.h
 **/

#include "modules/planning/optimizer/dp_poly_path/trajectory_cost.h"

#include <algorithm>
#include <cmath>

#include "modules/common/math/vec2d.h"
#include "modules/common/proto/pnc_point.pb.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using Box2d = ::apollo::common::math::Box2d;
using Vec2d = ::apollo::common::math::Vec2d;
using TrajectoryPoint = ::apollo::common::TrajectoryPoint;

TrajectoryCost::TrajectoryCost(const DpPolyPathConfig &config,
                               const ReferenceLine &reference_line,
                               const common::VehicleParam &vehicle_param,
                               const SpeedData &heuristic_speed_data)
    : config_(config),
      reference_line_(&reference_line),
      vehicle_param_(vehicle_param),
      heuristic_speed_data_(heuristic_speed_data) {

  const double total_time =
      std::min(heuristic_speed_data_.total_time(), FLAGS_prediction_total_time);

  num_of_time_stamps_ = static_cast<uint32_t>(
      std::floor(total_time / config.eval_time_interval()));
}

double TrajectoryCost::calculate(const QuinticPolynomialCurve1d &curve,
                                 const double start_s,
                                 const double end_s) const {
  double total_cost = 0.0;
  // path_cost
  double path_s = 0.0;
  while (path_s < (end_s - start_s)) {
    double l = std::fabs(curve.evaluate(0, path_s));
    total_cost += l;

    double dl = std::fabs(curve.evaluate(1, path_s));
    total_cost += dl;

    path_s += config_.path_resolution();
  }
  // obstacle cost
  return total_cost;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>modify the increment pf path_s for more points to compute trajectory cost<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file trjactory_cost.h
 **/

#include "modules/planning/optimizer/dp_poly_path/trajectory_cost.h"

#include <algorithm>
#include <cmath>

#include "modules/common/math/vec2d.h"
#include "modules/common/proto/pnc_point.pb.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using Box2d = ::apollo::common::math::Box2d;
using Vec2d = ::apollo::common::math::Vec2d;
using TrajectoryPoint = ::apollo::common::TrajectoryPoint;

TrajectoryCost::TrajectoryCost(const DpPolyPathConfig &config,
                               const ReferenceLine &reference_line,
                               const common::VehicleParam &vehicle_param,
                               const SpeedData &heuristic_speed_data)
    : config_(config),
      reference_line_(&reference_line),
      vehicle_param_(vehicle_param),
      heuristic_speed_data_(heuristic_speed_data) {

  const double total_time =
      std::min(heuristic_speed_data_.total_time(), FLAGS_prediction_total_time);

  num_of_time_stamps_ = static_cast<uint32_t>(
      std::floor(total_time / config.eval_time_interval()));
}

double TrajectoryCost::calculate(const QuinticPolynomialCurve1d &curve,
                                 const double start_s,
                                 const double end_s) const {
  double total_cost = 0.0;
  // path_cost
  double path_s = 0.0;
  while (path_s < (end_s - start_s)) {
    double l = std::fabs(curve.evaluate(0, path_s));
    total_cost += l;

    double dl = std::fabs(curve.evaluate(1, path_s));
    total_cost += dl;
    // TODO(all): add the 5.0 as a parameter into config
    path_s += config_.path_resolution() / 5.0;
  }
  // obstacle cost
  return total_cost;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 - 2020 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>

#include <fstream>
#include <iostream>

#include "src/utils/geo_lookup.h"
#if WITH_MAXMIND
#include <maxminddb.h>
#elif WITH_GEOIP
#include <GeoIPCity.h>
#endif

namespace modsecurity {
namespace Utils {

GeoLookup::~GeoLookup() {
    cleanUp();
}

void GeoLookup::cleanUp() {
#ifdef WITH_MAXMIND
    if (m_version == VERSION_MAXMIND) {
        MMDB_close(&mmdb);
    }
#endif
#ifdef WITH_GEOIP
    if (m_version == VERSION_GEOIP && m_gi != NULL) {
        GeoIP_delete(m_gi);
        m_gi = NULL;
    }
#endif
    m_version = NOT_LOADED;
}

bool GeoLookup::setDataBase(const std::string& filePath,
    std::string *err) {
    std::string intMax;
    std::string intGeo;

#ifdef WITH_MAXMIND
    int status = MMDB_open(filePath.c_str(), MMDB_MODE_MMAP, &mmdb);
    if (status != MMDB_SUCCESS) {
        intMax.assign("libMaxMind: Can't open: " + std::string(MMDB_strerror(status)) + ".");
    } else {
        m_version = VERSION_MAXMIND;
    }
#endif

#ifdef WITH_GEOIP
    if (m_version == NOT_LOADED) {
        m_gi = GeoIP_open(filePath.c_str(), GEOIP_INDEX_CACHE);
        if (m_gi == NULL) {
            intGeo.append("GeoIP: Can't open: " + filePath + ".");
        } else {
            m_version = VERSION_GEOIP;
        }
    }
#endif

    if (m_version == NOT_LOADED) {
        err->assign("Can't open:  " + filePath + ". ");
        err->append("Support enabled for:");
#ifdef WITH_MAXMIND
        err->append(" libMaxMind");
#endif

#ifdef WITH_GEOIP
        err->append(" GeoIP");
#endif
        err->append(".");

        if (intMax.size() > 0) {
            err->append(" " + intMax);

        }
        if (intGeo.size() > 0) {
            err->append(" " + intGeo);
        }
        return false;
    }

    return true;
}

bool GeoLookup::lookup(const std::string& target, Transaction *trans,
    std::function<bool(int, const std::string &)> debug) const {

    if (m_version == NOT_LOADED) {
        if (debug) {
            debug(4, "Database is not open. " \
                "Use: SecGeoLookupDb directive.");
        }
        return false;
    }

#ifdef WITH_MAXMIND
    if (m_version == VERSION_MAXMIND) {
        int gai_error, mmdb_error;
        MMDB_lookup_result_s r;

        r = MMDB_lookup_string(&mmdb, target.c_str(), &gai_error, &mmdb_error);

        if (gai_error) {
            if (debug) {
                debug(4, "MaxMind: Error from getaddrinfo for: " +
                    target + ". " + gai_strerror(gai_error));
            }
            return false;
        }

        if (mmdb_error != MMDB_SUCCESS) {
            if (debug) {
                debug(4, "MaxMind: Got an error from libmaxminddb: " +
                    std::string(MMDB_strerror(mmdb_error)));
            }
            return false;
        }

        if (!r.found_entry) {
            return false;
        } else {
            MMDB_entry_data_s entry_data;

            int status = MMDB_get_value(&r.entry, &entry_data,
                "country", "iso_code", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CODE",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "country", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_NAME",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "continent", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CONTINENT",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "city", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("CITY",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "postal", "code", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("POSTAL_CODE",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "location", "latitude", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("LATITUDE",
                    std::to_string(entry_data.double_value), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "location", "longitude", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("LONGITUDE",
                    std::to_string(entry_data.double_value), 0);
            }

            /*
            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CODE3",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("REGION",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("DMA_CODE",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("AREA_CODE",
                    std::string(entry_data.utf8_string), 0);
            }
            */
        }
    }
#endif

#ifdef WITH_GEOIP
    if (m_version == VERSION_GEOIP) {
        GeoIPRecord *gir;
        gir = GeoIP_record_by_name(m_gi, target.c_str());
        if (gir == NULL) {
            return false;
        }

        if (trans) {
            if (gir->country_code) {
                trans->m_variableGeo.set("COUNTRY_CODE",
                    std::string(gir->country_code), 0);
            }
            if (gir->country_code3) {
                trans->m_variableGeo.set("COUNTRY_CODE3",
                    std::string(gir->country_code3), 0);
            }
            if (gir->country_name) {
                trans->m_variableGeo.set("COUNTRY_NAME",
                    std::string(gir->country_name), 0);
            }
            if (gir->continent_code) {
                trans->m_variableGeo.set("COUNTRY_CONTINENT",
                    std::string(gir->continent_code), 0);
            }
            if (gir->country_code && gir->region) {
                trans->m_variableGeo.set("REGION",
                    std::string(GeoIP_region_name_by_code(gir->country_code,
                        gir->region)), 0);
            }
            if (gir->city) {
                trans->m_variableGeo.set("CITY", std::string(gir->city), 0);
            }
            if (gir->postal_code) {
                trans->m_variableGeo.set("POSTAL_CODE",
                    std::string(gir->postal_code), 0);
            }
            if (gir->latitude) {
                trans->m_variableGeo.set("LATITUDE",
                    std::to_string(gir->latitude), 0);
            }
            if (gir->longitude) {
                trans->m_variableGeo.set("LONGITUDE",
                    std::to_string(gir->longitude), 0);
            }
            if (gir->metro_code) {
                trans->m_variableGeo.set("DMA_CODE",
                    std::to_string(gir->metro_code), 0);
            }
            if (gir->area_code) {
                trans->m_variableGeo.set("AREA_CODE",
                    std::to_string(gir->area_code), 0);
            }
        }

        GeoIPRecord_delete(gir);
    }
#endif

    return true;
}

}  // namespace Utils
}  // namespace modsecurity

<commit_msg>GeoIP: switch to GEOIP_MEMORY_CACHE from GEOIP_INDEX_CACHE<commit_after>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 - 2020 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>

#include <fstream>
#include <iostream>

#include "src/utils/geo_lookup.h"
#if WITH_MAXMIND
#include <maxminddb.h>
#elif WITH_GEOIP
#include <GeoIPCity.h>
#endif

namespace modsecurity {
namespace Utils {

GeoLookup::~GeoLookup() {
    cleanUp();
}

void GeoLookup::cleanUp() {
#ifdef WITH_MAXMIND
    if (m_version == VERSION_MAXMIND) {
        MMDB_close(&mmdb);
    }
#endif
#ifdef WITH_GEOIP
    if (m_version == VERSION_GEOIP && m_gi != NULL) {
        GeoIP_delete(m_gi);
        m_gi = NULL;
    }
#endif
    m_version = NOT_LOADED;
}

bool GeoLookup::setDataBase(const std::string& filePath,
    std::string *err) {
    std::string intMax;
    std::string intGeo;

#ifdef WITH_MAXMIND
    int status = MMDB_open(filePath.c_str(), MMDB_MODE_MMAP, &mmdb);
    if (status != MMDB_SUCCESS) {
        intMax.assign("libMaxMind: Can't open: " + std::string(MMDB_strerror(status)) + ".");
    } else {
        m_version = VERSION_MAXMIND;
    }
#endif

#ifdef WITH_GEOIP
    if (m_version == NOT_LOADED) {
        m_gi = GeoIP_open(filePath.c_str(), GEOIP_MEMORY_CACHE);
        if (m_gi == NULL) {
            intGeo.append("GeoIP: Can't open: " + filePath + ".");
        } else {
            m_version = VERSION_GEOIP;
        }
    }
#endif

    if (m_version == NOT_LOADED) {
        err->assign("Can't open:  " + filePath + ". ");
        err->append("Support enabled for:");
#ifdef WITH_MAXMIND
        err->append(" libMaxMind");
#endif

#ifdef WITH_GEOIP
        err->append(" GeoIP");
#endif
        err->append(".");

        if (intMax.size() > 0) {
            err->append(" " + intMax);

        }
        if (intGeo.size() > 0) {
            err->append(" " + intGeo);
        }
        return false;
    }

    return true;
}

bool GeoLookup::lookup(const std::string& target, Transaction *trans,
    std::function<bool(int, const std::string &)> debug) const {

    if (m_version == NOT_LOADED) {
        if (debug) {
            debug(4, "Database is not open. " \
                "Use: SecGeoLookupDb directive.");
        }
        return false;
    }

#ifdef WITH_MAXMIND
    if (m_version == VERSION_MAXMIND) {
        int gai_error, mmdb_error;
        MMDB_lookup_result_s r;

        r = MMDB_lookup_string(&mmdb, target.c_str(), &gai_error, &mmdb_error);

        if (gai_error) {
            if (debug) {
                debug(4, "MaxMind: Error from getaddrinfo for: " +
                    target + ". " + gai_strerror(gai_error));
            }
            return false;
        }

        if (mmdb_error != MMDB_SUCCESS) {
            if (debug) {
                debug(4, "MaxMind: Got an error from libmaxminddb: " +
                    std::string(MMDB_strerror(mmdb_error)));
            }
            return false;
        }

        if (!r.found_entry) {
            return false;
        } else {
            MMDB_entry_data_s entry_data;

            int status = MMDB_get_value(&r.entry, &entry_data,
                "country", "iso_code", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CODE",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "country", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_NAME",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "continent", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CONTINENT",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "city", "names", "en", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("CITY",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "postal", "code", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("POSTAL_CODE",
                    std::string(entry_data.utf8_string,
                        entry_data.data_size), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "location", "latitude", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("LATITUDE",
                    std::to_string(entry_data.double_value), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                "location", "longitude", NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("LONGITUDE",
                    std::to_string(entry_data.double_value), 0);
            }

            /*
            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("COUNTRY_CODE3",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("REGION",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("DMA_CODE",
                    std::string(entry_data.utf8_string), 0);
            }

            status = MMDB_get_value(&r.entry, &entry_data,
                NULL);
            if (status == MMDB_SUCCESS && entry_data.has_data) {
                trans->m_variableGeo.set("AREA_CODE",
                    std::string(entry_data.utf8_string), 0);
            }
            */
        }
    }
#endif

#ifdef WITH_GEOIP
    if (m_version == VERSION_GEOIP) {
        GeoIPRecord *gir;
        gir = GeoIP_record_by_name(m_gi, target.c_str());
        if (gir == NULL) {
            return false;
        }

        if (trans) {
            if (gir->country_code) {
                trans->m_variableGeo.set("COUNTRY_CODE",
                    std::string(gir->country_code), 0);
            }
            if (gir->country_code3) {
                trans->m_variableGeo.set("COUNTRY_CODE3",
                    std::string(gir->country_code3), 0);
            }
            if (gir->country_name) {
                trans->m_variableGeo.set("COUNTRY_NAME",
                    std::string(gir->country_name), 0);
            }
            if (gir->continent_code) {
                trans->m_variableGeo.set("COUNTRY_CONTINENT",
                    std::string(gir->continent_code), 0);
            }
            if (gir->country_code && gir->region) {
                trans->m_variableGeo.set("REGION",
                    std::string(GeoIP_region_name_by_code(gir->country_code,
                        gir->region)), 0);
            }
            if (gir->city) {
                trans->m_variableGeo.set("CITY", std::string(gir->city), 0);
            }
            if (gir->postal_code) {
                trans->m_variableGeo.set("POSTAL_CODE",
                    std::string(gir->postal_code), 0);
            }
            if (gir->latitude) {
                trans->m_variableGeo.set("LATITUDE",
                    std::to_string(gir->latitude), 0);
            }
            if (gir->longitude) {
                trans->m_variableGeo.set("LONGITUDE",
                    std::to_string(gir->longitude), 0);
            }
            if (gir->metro_code) {
                trans->m_variableGeo.set("DMA_CODE",
                    std::to_string(gir->metro_code), 0);
            }
            if (gir->area_code) {
                trans->m_variableGeo.set("AREA_CODE",
                    std::to_string(gir->area_code), 0);
            }
        }

        GeoIPRecord_delete(gir);
    }
#endif

    return true;
}

}  // namespace Utils
}  // namespace modsecurity

<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014                                                                    *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

// open space includes
#include <openspace/rendering/renderablevolumegl.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/kameleonwrapper.h>

#include <ghoul/opengl/texturereader.h>
#include <ghoul/opencl/clworksize.h>
#include <ghoul/filesystem/filesystem.h>

#include <algorithm>

#include <openspace/engine/openspaceengine.h>

namespace {
    std::string _loggerCat = "RenderableVolumeGL";
}

namespace openspace {

RenderableVolumeGL::RenderableVolumeGL(const ghoul::Dictionary& dictionary):
    RenderableVolume(dictionary), _boxScaling(1.0, 1.0, 1.0),
    _updateTransferfunction(false), _id(-1) {

    _filename = "";
    if(dictionary.hasKey("Volume")) {
        if(dictionary.getValue("Volume", _filename)) {
            _filename = findPath(_filename);
        }
    }

    LDEBUG("filename: " << _filename);

    if(dictionary.hasKey("Hints"))
        dictionary.getValue("Hints", _hintsDictionary);

    _transferFunction = nullptr;
    _transferFunctionFile = nullptr;
    _transferFunctionPath = "";
    if (dictionary.hasKey("TransferFunction")) {
        std::string transferFunctionPath = "";
        if(dictionary.getValue("TransferFunction", transferFunctionPath)) {
            _transferFunctionPath = findPath(transferFunctionPath);
        }
    }
    _samplerFilename = "";
    if (dictionary.hasKey("Sampler")) {
        if(dictionary.getValue("Sampler", _samplerFilename)) {
            _samplerFilename = findPath(_samplerFilename);
        }
    }
    if( _transferFunctionPath == "") {
        LERROR("No transferFunction!");
    } else {
        _transferFunctionFile = new ghoul::filesystem::File(_transferFunctionPath, true);
    }
    if( _samplerFilename == "") {
        LERROR("No samplerfile!");
    }

    double tempValue;
    if(dictionary.hasKey("BoxScaling.1") && dictionary.getValue("BoxScaling.1", tempValue)) {
    	if(tempValue > 0.0)
    		_boxScaling[0] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.2") && dictionary.getValue("BoxScaling.2", tempValue)) {
    	if(tempValue > 0.0)
    		_boxScaling[1] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.3") && dictionary.getValue("BoxScaling.3", tempValue)) {
        if(tempValue > 0.0)
            _boxScaling[2] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.4") && dictionary.getValue("BoxScaling.4", tempValue)) {
        _w = tempValue;
    }

    _volumeName = "";
    if (dictionary.hasKey("VolumeName"))
        dictionary.getValue("VolumeName", _volumeName);
    _transferFunctionName = "";
    if (dictionary.hasKey("TransferFunctionName"))
        dictionary.getValue("TransferFunctionName", _transferFunctionName);

    setBoundingSphere(PowerScaledScalar::CreatePSS(glm::length(_boxScaling)*pow(10,_w)));
}

RenderableVolumeGL::~RenderableVolumeGL() {
    deinitialize();
    if(_volume)
        delete _volume;
    if(_transferFunctionFile)
        delete _transferFunctionFile;
    if(_transferFunction)
        delete _transferFunction;
}

bool RenderableVolumeGL::initialize() {
    // assert(_filename != "");
    //	------ VOLUME READING ----------------
// <<<<<<< HEAD
// =======
// 	_volume = loadVolume(_filename, _hintsDictionary);
// 	_volume->uploadTexture();
//     _transferFunction = loadTransferFunction(_transferFunctionPath);
//     _transferFunction->uploadTexture();

// >>>>>>> feature/fieldlines
    // TODO: fix volume an transferfunction names
    if(_filename != "") {
        _volume = loadVolume(_filename, _hintsDictionary);
        _boxOffset = getVolumeOffset(_filename, _hintsDictionary);
        _volume->uploadTexture();
        OsEng.renderEngine().abuffer()->addVolume(_volumeName, _volume);
    }

    if(_transferFunctionPath != "") {
        _transferFunction = loadTransferFunction(_transferFunctionPath);
        _transferFunction->uploadTexture();
        OsEng.renderEngine().abuffer()->addTransferFunction(_transferFunctionName, _transferFunction);

        auto textureCallback = [this](const ghoul::filesystem::File& file) {
            _updateTransferfunction = true;
        };
        _transferFunctionFile->setCallback(textureCallback);
    }

    // add the sampler and get the ID
    _id = OsEng.renderEngine().abuffer()->addSamplerfile(_samplerFilename);

    OsEng.configurationManager().getValue("RaycastProgram", _boxProgram);
    _MVPLocation = _boxProgram->uniformLocation("modelViewProjection");
    _modelTransformLocation = _boxProgram->uniformLocation("modelTransform");
    _typeLocation = _boxProgram->uniformLocation("volumeType");

    // ============================
    //      GEOMETRY (quad)
    // ============================
    const GLfloat size = 0.5f;
    const GLfloat vertex_data[] = { // square of two triangles (sigh)
        //  x,     y,     z,     s,
        -size, -size,  size,  _w,
         size,  size,  size,  _w,
        -size,  size,  size,  _w,
        -size, -size,  size,  _w,
         size, -size,  size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
         size,  size, -size,  _w,
        -size,  size, -size,  _w,
        -size, -size, -size,  _w,
         size, -size, -size,  _w,
         size,  size, -size,  _w,

         size, -size, -size,  _w,
         size,  size,  size,  _w,
         size, -size,  size,  _w,
         size, -size, -size,  _w,
         size,  size, -size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
        -size,  size,  size,  _w,
        -size, -size,  size,  _w,
        -size, -size, -size,  _w,
        -size,  size, -size,  _w,
        -size,  size,  size,  _w,

        -size,  size, -size,  _w,
         size,  size,  size,  _w,
        -size,  size,  size,  _w,
        -size,  size, -size,  _w,
         size,  size, -size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
         size, -size,  size,  _w,
        -size, -size,  size,  _w,
        -size, -size, -size,  _w,
         size, -size, -size,  _w,
         size, -size,  size,  _w,
    };
    GLuint vertexPositionBuffer;
    glGenVertexArrays(1, &_boxArray); // generate array
    glBindVertexArray(_boxArray); // bind array
    glGenBuffers(1, &vertexPositionBuffer); // generate buffer
    glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast<void*>(0));
    glEnableVertexAttribArray(0);

    return true;
}

bool RenderableVolumeGL::deinitialize() {
    return true;
}

void RenderableVolumeGL::render(const Camera *camera, const psc &thisPosition) {
    if(_updateTransferfunction) {
        _updateTransferfunction = false;
        ghoul::opengl::Texture* transferFunction = loadTransferFunction(_transferFunctionPath);
        if(transferFunction) {
            const void* data = transferFunction->pixelData();
            glBindBuffer(GL_COPY_READ_BUFFER, *transferFunction);
            _transferFunction->bind();
            glTexImage1D(   GL_TEXTURE_1D, 0, _transferFunction->internalFormat(),
                            _transferFunction->width(),0, _transferFunction->format(),
                            _transferFunction->dataType(), data);
            delete transferFunction;
            LDEBUG("Updated transferfunction!");

        }
    }

    glm::mat4 transform = glm::mat4(1.0);
    transform = glm::scale(transform, _boxScaling);

    // fetch data
    psc currentPosition         = thisPosition;
    psc campos                  = camera->position();
    glm::mat4 camrot            = camera->viewRotationMatrix();
    PowerScaledScalar scaling   = camera->scaling();

    // psc addon(-1.1,0.0,0.0,0.0);
    // currentPosition += addon;
    psc addon(_boxOffset/100.0f); // TODO: Proper scaling/units
    currentPosition += addon; // Move box to model barycenter

    // TODO: Use _id to identify this volume
    _boxProgram->activate();
    _boxProgram->setUniform(_typeLocation, _id);

    _boxProgram->setUniform("modelViewProjection", camera->viewProjectionMatrix());
    _boxProgram->setUniform("modelTransform", transform);
    _boxProgram->setUniform("campos", campos.vec4());
    _boxProgram->setUniform("objpos", currentPosition.vec4());
    _boxProgram->setUniform("camrot", camrot);
    _boxProgram->setUniform("scaling", scaling.vec2());

    // make sure GL_CULL_FACE is enabled (it should be)
    glEnable(GL_CULL_FACE);

    //  Draw backface
    glCullFace(GL_FRONT);
    glBindVertexArray(_boxArray);
    glDrawArrays(GL_TRIANGLES, 0, 6*6);

    //  Draw frontface (now the normal cull face is is set)
    glCullFace(GL_BACK);
    glDrawArrays(GL_TRIANGLES, 0, 6*6);

    _boxProgram->deactivate();
}

void RenderableVolumeGL::update() {
}

} // namespace openspace
<commit_msg>Fix for rendering volumes<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014                                                                    *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

// open space includes
#include <openspace/rendering/renderablevolumegl.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/kameleonwrapper.h>

#include <ghoul/opengl/texturereader.h>
#include <ghoul/opencl/clworksize.h>
#include <ghoul/filesystem/filesystem.h>

#include <algorithm>

#include <openspace/engine/openspaceengine.h>

namespace {
    std::string _loggerCat = "RenderableVolumeGL";
}

namespace openspace {

RenderableVolumeGL::RenderableVolumeGL(const ghoul::Dictionary& dictionary):
    RenderableVolume(dictionary), _boxScaling(1.0, 1.0, 1.0),
    _updateTransferfunction(false), _id(-1) {

    _filename = "";
    if(dictionary.hasKey("Volume")) {
        if(dictionary.getValue("Volume", _filename)) {
            _filename = findPath(_filename);
        }
    }

    LDEBUG("filename: " << _filename);

    if(dictionary.hasKey("Hints"))
        dictionary.getValue("Hints", _hintsDictionary);

    _transferFunction = nullptr;
    _transferFunctionFile = nullptr;
    _transferFunctionPath = "";
    if (dictionary.hasKey("TransferFunction")) {
        std::string transferFunctionPath = "";
        if(dictionary.getValue("TransferFunction", transferFunctionPath)) {
            _transferFunctionPath = findPath(transferFunctionPath);
        }
    }
    _samplerFilename = "";
    if (dictionary.hasKey("Sampler")) {
        if(dictionary.getValue("Sampler", _samplerFilename)) {
            _samplerFilename = findPath(_samplerFilename);
        }
    }
    if( _transferFunctionPath == "") {
        LERROR("No transferFunction!");
    } else {
        _transferFunctionFile = new ghoul::filesystem::File(_transferFunctionPath, true);
    }
    if( _samplerFilename == "") {
        LERROR("No samplerfile!");
    }

    double tempValue;
    if(dictionary.hasKey("BoxScaling.1") && dictionary.getValue("BoxScaling.1", tempValue)) {
    	if(tempValue > 0.0)
    		_boxScaling[0] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.2") && dictionary.getValue("BoxScaling.2", tempValue)) {
    	if(tempValue > 0.0)
    		_boxScaling[1] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.3") && dictionary.getValue("BoxScaling.3", tempValue)) {
        if(tempValue > 0.0)
            _boxScaling[2] = tempValue;
    }
    if(dictionary.hasKey("BoxScaling.4") && dictionary.getValue("BoxScaling.4", tempValue)) {
        _w = tempValue;
    }
	else
		_w = 0.0;

    _volumeName = "";
    if (dictionary.hasKey("VolumeName"))
        dictionary.getValue("VolumeName", _volumeName);
    _transferFunctionName = "";
    if (dictionary.hasKey("TransferFunctionName"))
        dictionary.getValue("TransferFunctionName", _transferFunctionName);

    setBoundingSphere(PowerScaledScalar::CreatePSS(glm::length(_boxScaling)*pow(10,_w)));
}

RenderableVolumeGL::~RenderableVolumeGL() {
    deinitialize();
    if(_volume)
        delete _volume;
    if(_transferFunctionFile)
        delete _transferFunctionFile;
    if(_transferFunction)
        delete _transferFunction;
}

bool RenderableVolumeGL::initialize() {
    // assert(_filename != "");
    //	------ VOLUME READING ----------------
// <<<<<<< HEAD
// =======
// 	_volume = loadVolume(_filename, _hintsDictionary);
// 	_volume->uploadTexture();
//     _transferFunction = loadTransferFunction(_transferFunctionPath);
//     _transferFunction->uploadTexture();

// >>>>>>> feature/fieldlines
    // TODO: fix volume an transferfunction names
    if(_filename != "") {
        _volume = loadVolume(_filename, _hintsDictionary);
        _boxOffset = getVolumeOffset(_filename, _hintsDictionary);
        _volume->uploadTexture();
        OsEng.renderEngine().abuffer()->addVolume(_volumeName, _volume);
    }

    if(_transferFunctionPath != "") {
        _transferFunction = loadTransferFunction(_transferFunctionPath);
        _transferFunction->uploadTexture();
        OsEng.renderEngine().abuffer()->addTransferFunction(_transferFunctionName, _transferFunction);

        auto textureCallback = [this](const ghoul::filesystem::File& file) {
            _updateTransferfunction = true;
        };
        _transferFunctionFile->setCallback(textureCallback);
    }

    // add the sampler and get the ID
    _id = OsEng.renderEngine().abuffer()->addSamplerfile(_samplerFilename);

    OsEng.configurationManager().getValue("RaycastProgram", _boxProgram);
    _MVPLocation = _boxProgram->uniformLocation("modelViewProjection");
    _modelTransformLocation = _boxProgram->uniformLocation("modelTransform");
    _typeLocation = _boxProgram->uniformLocation("volumeType");

    // ============================
    //      GEOMETRY (quad)
    // ============================
    const GLfloat size = 0.5f;
    const GLfloat vertex_data[] = { // square of two triangles (sigh)
        //  x,     y,     z,     s,
        -size, -size,  size,  _w,
         size,  size,  size,  _w,
        -size,  size,  size,  _w,
        -size, -size,  size,  _w,
         size, -size,  size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
         size,  size, -size,  _w,
        -size,  size, -size,  _w,
        -size, -size, -size,  _w,
         size, -size, -size,  _w,
         size,  size, -size,  _w,

         size, -size, -size,  _w,
         size,  size,  size,  _w,
         size, -size,  size,  _w,
         size, -size, -size,  _w,
         size,  size, -size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
        -size,  size,  size,  _w,
        -size, -size,  size,  _w,
        -size, -size, -size,  _w,
        -size,  size, -size,  _w,
        -size,  size,  size,  _w,

        -size,  size, -size,  _w,
         size,  size,  size,  _w,
        -size,  size,  size,  _w,
        -size,  size, -size,  _w,
         size,  size, -size,  _w,
         size,  size,  size,  _w,

        -size, -size, -size,  _w,
         size, -size,  size,  _w,
        -size, -size,  size,  _w,
        -size, -size, -size,  _w,
         size, -size, -size,  _w,
         size, -size,  size,  _w,
    };
    GLuint vertexPositionBuffer;
    glGenVertexArrays(1, &_boxArray); // generate array
    glBindVertexArray(_boxArray); // bind array
    glGenBuffers(1, &vertexPositionBuffer); // generate buffer
    glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast<void*>(0));
    glEnableVertexAttribArray(0);

    return true;
}

bool RenderableVolumeGL::deinitialize() {
    return true;
}

void RenderableVolumeGL::render(const Camera *camera, const psc &thisPosition) {
    if(_updateTransferfunction) {
        _updateTransferfunction = false;
        ghoul::opengl::Texture* transferFunction = loadTransferFunction(_transferFunctionPath);
        if(transferFunction) {
            const void* data = transferFunction->pixelData();
            glBindBuffer(GL_COPY_READ_BUFFER, *transferFunction);
            _transferFunction->bind();
            glTexImage1D(   GL_TEXTURE_1D, 0, _transferFunction->internalFormat(),
                            _transferFunction->width(),0, _transferFunction->format(),
                            _transferFunction->dataType(), data);
            delete transferFunction;
            LDEBUG("Updated transferfunction!");

        }
    }

    glm::mat4 transform = glm::mat4(1.0);
    transform = glm::scale(transform, _boxScaling);

    // fetch data
    psc currentPosition         = thisPosition;
    psc campos                  = camera->position();
    glm::mat4 camrot            = camera->viewRotationMatrix();
    PowerScaledScalar scaling   = camera->scaling();

    // psc addon(-1.1,0.0,0.0,0.0);
    // currentPosition += addon;
    psc addon(_boxOffset/100.0f); // TODO: Proper scaling/units
    currentPosition += addon; // Move box to model barycenter

    // TODO: Use _id to identify this volume
    _boxProgram->activate();
    _boxProgram->setUniform(_typeLocation, _id);

    _boxProgram->setUniform("modelViewProjection", camera->viewProjectionMatrix());
    _boxProgram->setUniform("modelTransform", transform);
    _boxProgram->setUniform("campos", campos.vec4());
    _boxProgram->setUniform("objpos", currentPosition.vec4());
    _boxProgram->setUniform("camrot", camrot);
    _boxProgram->setUniform("scaling", scaling.vec2());

    // make sure GL_CULL_FACE is enabled (it should be)
    glEnable(GL_CULL_FACE);

    //  Draw backface
    glCullFace(GL_FRONT);
    glBindVertexArray(_boxArray);
    glDrawArrays(GL_TRIANGLES, 0, 6*6);

    //  Draw frontface (now the normal cull face is is set)
    glCullFace(GL_BACK);
    glDrawArrays(GL_TRIANGLES, 0, 6*6);

    _boxProgram->deactivate();
}

void RenderableVolumeGL::update() {
}

} // namespace openspace
<|endoftext|>