<commit_before>//===-- MachineInstrInfo.cpp - Target Instruction Information -------------===//
//
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Constant.h"
#include "llvm/DerivedTypes.h"

// External object describing the machine instructions
// Initialized only when the TargetMachine class is created
// and reset when that class is destroyed.
//
const MachineInstrDescriptor* TargetInstrDescriptors = 0;

//---------------------------------------------------------------------------
// class MachineInstructionInfo
//	Interface to description of machine instructions
//---------------------------------------------------------------------------

MachineInstrInfo::MachineInstrInfo(const MachineInstrDescriptor* Desc,
				   unsigned DescSize,
				   unsigned NumRealOpCodes)
  : desc(Desc), descSize(DescSize), numRealOpCodes(NumRealOpCodes) {
  // FIXME: TargetInstrDescriptors should not be global
  assert(TargetInstrDescriptors == NULL && desc != NULL);
  TargetInstrDescriptors = desc;	// initialize global variable
}

MachineInstrInfo::~MachineInstrInfo() {
  TargetInstrDescriptors = NULL;	// reset global variable
}

void MachineInstrInfo::print(const MachineInstr *MI, std::ostream &O,
                             const TargetMachine &TM) const {
  MI->print(O, TM);
}

bool MachineInstrInfo::constantFitsInImmedField(MachineOpCode opCode,
                                                int64_t intValue) const {
  // First, check if opCode has an immed field.
  bool isSignExtended;
  uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended);
  if (maxImmedValue != 0)
    {
      // NEED TO HANDLE UNSIGNED VALUES SINCE THEY MAY BECOME MUCH
      // SMALLER AFTER CASTING TO SIGN-EXTENDED int, short, or char.
      // See CreateUIntSetInstruction in SparcInstrInfo.cpp.

      // Now check if the constant fits
      if (intValue <= (int64_t) maxImmedValue &&
	  intValue >= -((int64_t) maxImmedValue+1))
	return true;
    }

  return false;
}

bool MachineInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const {
  assert(CV->getType()->isPrimitiveType() || isa<PointerType>(CV->getType()));
  return !(CV->getType()->isIntegral() || isa<PointerType>(CV->getType()));
}
<commit_msg>Start renaming MachineInstrInfo -> TargetInstrInfo<commit_after>//===-- TargetInstrInfo.cpp - Target Instruction Information --------------===//
//
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Constant.h"
#include "llvm/DerivedTypes.h"

// External object describing the machine instructions
// Initialized only when the TargetMachine class is created
// and reset when that class is destroyed.
//
const TargetInstrDescriptor* TargetInstrDescriptors = 0;

TargetInstrInfo::TargetInstrInfo(const TargetInstrDescriptor* Desc,
				 unsigned DescSize,
				 unsigned NumRealOpCodes)
  : desc(Desc), descSize(DescSize), numRealOpCodes(NumRealOpCodes) {
  // FIXME: TargetInstrDescriptors should not be global
  assert(TargetInstrDescriptors == NULL && desc != NULL);
  TargetInstrDescriptors = desc;	// initialize global variable
}

TargetInstrInfo::~TargetInstrInfo() {
  TargetInstrDescriptors = NULL;	// reset global variable
}

void TargetInstrInfo::print(const MachineInstr *MI, std::ostream &O,
			    const TargetMachine &TM) const {
  MI->print(O, TM);
}

bool TargetInstrInfo::constantFitsInImmedField(MachineOpCode opCode,
					       int64_t intValue) const {
  // First, check if opCode has an immed field.
  bool isSignExtended;
  uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended);
  if (maxImmedValue != 0)
    {
      // NEED TO HANDLE UNSIGNED VALUES SINCE THEY MAY BECOME MUCH
      // SMALLER AFTER CASTING TO SIGN-EXTENDED int, short, or char.
      // See CreateUIntSetInstruction in SparcInstrInfo.cpp.

      // Now check if the constant fits
      if (intValue <= (int64_t) maxImmedValue &&
	  intValue >= -((int64_t) maxImmedValue+1))
	return true;
    }

  return false;
}

bool TargetInstrInfo::ConstantTypeMustBeLoaded(const Constant* CV) const {
  assert(CV->getType()->isPrimitiveType() || isa<PointerType>(CV->getType()));
  return !(CV->getType()->isIntegral() || isa<PointerType>(CV->getType()));
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/node_main.h"

#include <memory>
#include <utility>

#include "atom/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/crash_reporter/crash_reporter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/task_scheduler/task_scheduler.h"
#include "base/threading/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
#include "native_mate/dictionary.h"

#include "atom/common/node_includes.h"

namespace atom {

int NodeMain(int argc, char* argv[]) {
  base::CommandLine::Init(argc, argv);

  int exit_code = 1;
  {
    // Feed gin::PerIsolateData with a task runner.
    argv = uv_setup_args(argc, argv);
    uv_loop_t* loop = uv_default_loop();
    scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
    base::ThreadTaskRunnerHandle handle(uv_task_runner);

    // Initialize feature list.
    auto feature_list = std::make_unique<base::FeatureList>();
    feature_list->InitializeFromCommandLine("", "");
    base::FeatureList::SetInstance(std::move(feature_list));

    gin::V8Initializer::LoadV8Snapshot(
        gin::V8Initializer::V8SnapshotFileType::kWithAdditionalContext);
    gin::V8Initializer::LoadV8Natives();

    // V8 requires a task scheduler apparently
    base::TaskScheduler::CreateAndStartWithDefaultParams("Electron");

    // Initialize gin::IsolateHolder.
    JavascriptEnvironment gin_env;

    // Explicitly register electron's builtin modules.
    NodeBindings::RegisterBuiltinModules();

    int exec_argc;
    const char** exec_argv;
    node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

    node::Environment* env = node::CreateEnvironment(
        node::CreateIsolateData(gin_env.isolate(), loop, gin_env.platform()),
        gin_env.context(), argc, argv, exec_argc, exec_argv);

    // Enable support for v8 inspector.
    NodeDebugger node_debugger(env);
    node_debugger.Start();

    mate::Dictionary process(gin_env.isolate(), env->process_object());
#if defined(OS_WIN)
    process.SetMethod("log", &AtomBindings::Log);
#endif
    process.SetMethod("crash", &AtomBindings::Crash);

    // Setup process.crashReporter.start in child node processes
    auto reporter = mate::Dictionary::CreateEmpty(gin_env.isolate());
    reporter.SetMethod("start", &crash_reporter::CrashReporter::StartInstance);
    process.Set("crashReporter", reporter);

    node::LoadEnvironment(env);

    bool more;
    do {
      more = uv_run(env->event_loop(), UV_RUN_ONCE);
      gin_env.platform()->DrainBackgroundTasks(env->isolate());
      if (more == false) {
        node::EmitBeforeExit(env);

        // Emit `beforeExit` if the loop became alive either after emitting
        // event, or after running some callbacks.
        more = uv_loop_alive(env->event_loop());
        if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
          more = true;
      }
    } while (more == true);

    exit_code = node::EmitExit(env);
    node::RunAtExit(env);
    gin_env.platform()->DrainBackgroundTasks(env->isolate());
    gin_env.platform()->CancelPendingDelayedTasks(env->isolate());

    node::FreeEnvironment(env);
  }

  // According to "src/gin/shell/gin_main.cc":
  //
  // gin::IsolateHolder waits for tasks running in TaskScheduler in its
  // destructor and thus must be destroyed before TaskScheduler starts skipping
  // CONTINUE_ON_SHUTDOWN tasks.
  base::TaskScheduler::GetInstance()->Shutdown();

  v8::V8::Dispose();

  return exit_code;
}

}  // namespace atom
<commit_msg>DrainBackgroundTasks -> DrainTasks<commit_after>// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/app/node_main.h"

#include <memory>
#include <utility>

#include "atom/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/crash_reporter/crash_reporter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/task_scheduler/task_scheduler.h"
#include "base/threading/thread_task_runner_handle.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
#include "native_mate/dictionary.h"

#include "atom/common/node_includes.h"

namespace atom {

int NodeMain(int argc, char* argv[]) {
  base::CommandLine::Init(argc, argv);

  int exit_code = 1;
  {
    // Feed gin::PerIsolateData with a task runner.
    argv = uv_setup_args(argc, argv);
    uv_loop_t* loop = uv_default_loop();
    scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
    base::ThreadTaskRunnerHandle handle(uv_task_runner);

    // Initialize feature list.
    auto feature_list = std::make_unique<base::FeatureList>();
    feature_list->InitializeFromCommandLine("", "");
    base::FeatureList::SetInstance(std::move(feature_list));

    gin::V8Initializer::LoadV8Snapshot(
        gin::V8Initializer::V8SnapshotFileType::kWithAdditionalContext);
    gin::V8Initializer::LoadV8Natives();

    // V8 requires a task scheduler apparently
    base::TaskScheduler::CreateAndStartWithDefaultParams("Electron");

    // Initialize gin::IsolateHolder.
    JavascriptEnvironment gin_env;

    // Explicitly register electron's builtin modules.
    NodeBindings::RegisterBuiltinModules();

    int exec_argc;
    const char** exec_argv;
    node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

    node::Environment* env = node::CreateEnvironment(
        node::CreateIsolateData(gin_env.isolate(), loop, gin_env.platform()),
        gin_env.context(), argc, argv, exec_argc, exec_argv);

    // Enable support for v8 inspector.
    NodeDebugger node_debugger(env);
    node_debugger.Start();

    mate::Dictionary process(gin_env.isolate(), env->process_object());
#if defined(OS_WIN)
    process.SetMethod("log", &AtomBindings::Log);
#endif
    process.SetMethod("crash", &AtomBindings::Crash);

    // Setup process.crashReporter.start in child node processes
    auto reporter = mate::Dictionary::CreateEmpty(gin_env.isolate());
    reporter.SetMethod("start", &crash_reporter::CrashReporter::StartInstance);
    process.Set("crashReporter", reporter);

    node::LoadEnvironment(env);

    bool more;
    do {
      more = uv_run(env->event_loop(), UV_RUN_ONCE);
      gin_env.platform()->DrainTasks(env->isolate());
      if (more == false) {
        node::EmitBeforeExit(env);

        // Emit `beforeExit` if the loop became alive either after emitting
        // event, or after running some callbacks.
        more = uv_loop_alive(env->event_loop());
        if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
          more = true;
      }
    } while (more == true);

    exit_code = node::EmitExit(env);
    node::RunAtExit(env);
    gin_env.platform()->DrainTasks(env->isolate());
    gin_env.platform()->CancelPendingDelayedTasks(env->isolate());

    node::FreeEnvironment(env);
  }

  // According to "src/gin/shell/gin_main.cc":
  //
  // gin::IsolateHolder waits for tasks running in TaskScheduler in its
  // destructor and thus must be destroyed before TaskScheduler starts skipping
  // CONTINUE_ON_SHUTDOWN tasks.
  base::TaskScheduler::GetInstance()->Shutdown();

  v8::V8::Dispose();

  return exit_code;
}

}  // namespace atom
<|endoftext|>


<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan, const coord_t nozzle_size, const coord_t maximum_resolution) : extruder_plan(plan), nozzle_size(nozzle_size), maximum_resolution(maximum_resolution)
    {
        //Just copy the parameters to their fields.
    }

    coord_t MergeInfillLines::calcPathLength(const Point path_start, GCodePath& path) const
    {
        Point previous_point = path_start;
        coord_t result = 0;
        for (const Point point : path.points)
        {
            result += vSize(point - previous_point);
            previous_point = point;
        }
        return result;
    }

    /*
     * first_is_already_merged == false
     *
     *       o     o
     *      /     /
     *     /     /
     *    /  +  /      --->   -(t)-o-----o
     *   /     /
     *  /     /
     * o     o
     *
     * travel (t) to first location is done through first_path_start_changed and new_first_path_start.
     * this gets rid of the tiny "blips". Depending on the merged line distance a small gap may appear, but this is
     * accounted for in the volume.
     *
     * first_is_already_merged == true
     *
     *                   o
     *                  /
     *                 /
     *    o-----o  +  /     --->    o-----------o   or with slight   o-----o-----o
     *   /           /             /                   bend         /
     *  /           /             /                                /
     * o           o             o                                o
     *
     */
    bool MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        Point average_first_path;

        coord_t first_path_length = calcPathLength(first_path_start, first_path);
        coord_t first_path_length_flow = first_path_length * first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.
        const coord_t line_width = first_path.config->getLineWidth();

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length = calcPathLength(second_path_start, second_path);
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            average_second_path += point;
        }
        coord_t second_path_length_flow = second_path_length *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        // predict new length and flow and if the new flow is to big, don't merge. conditions in this part must exactly match the actual merging
        coord_t new_path_length = first_path_length;
        coord_t dist2_from_line = 0;
        coord_t new_error_area = 0;
        coord_t merged_part_length = 0;
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1) {
                dist2_from_line = LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size() - 2], first_path.points[first_path.points.size() - 1]);
                merged_part_length = vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
                new_error_area = sqrt(dist2_from_line) * merged_part_length / 2;
            }
            // The max error margin uses the meshfix_maximum_resolution setting
            if (first_path.points.size() > 1 && error_area + new_error_area < merged_part_length * maximum_resolution)
            {
                new_path_length -= vSize(first_path.points[first_path.points.size() - 2] - first_path.points[first_path.points.size() - 1]);
                new_path_length += vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
            }
            else
            {
                new_path_length += vSize(first_path.points[first_path.points.size() - 1] - average_second_path);
            }
        }
        else
        {
            new_path_length -= vSize(first_path.points.back() - first_path_start);
            new_path_length += vSize(average_second_path - average_first_path);
        }
        double new_flow = ((first_path_length_flow + second_path_length_flow) / static_cast<double>(new_path_length));
        if (new_flow > 2 * nozzle_size / line_width)  // line width becomes too wide
        {
            return false;
        }

        // do the actual merging
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && error_area + new_error_area < line_width * line_width)
            {
                first_path.points[first_path.points.size() - 1] = average_second_path;
                error_area += new_error_area;
            } else {
                first_path.points.push_back(average_second_path);
                error_area = 0;
            }
        }
        else
        {
            new_first_path_start = average_first_path;
            first_path.points.clear();
            first_path.points.push_back(average_second_path);
            error_area = 0;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;

        return true;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const coord_t line_width = first_path.config->getLineWidth();

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged)
        {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (merged_direction.X == 0 && merged_direction.Y == 0)
        {
            return true;  // we can just disregard the second point as it's exactly at the leave point of the first path.
        }

        // Max 1 line width to the side of the merged_direction
        if (LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            //|| abs(dot(normal(merged_direction, 1000), normal(second_path_end - second_path_start, 1000))) > 866000    // 866000 angle of old second_path with new merged direction should not be too small (30 degrees), as it will introduce holes
            )
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        return mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area);
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point& starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = Point(starting_position.X, starting_position.Y);  // this one is not going to be overwritten
        size_t second_path_index = 1;
        coord_t error_area = 0;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();

            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths, we're looking for the first non-travel path.
            }

            bool allow_try_merge = true;
            // see if we meet criteria to merge. should be: travel - path1 not travel - (...) - travel - path2 not travel - travel
            // we're checking the travels here
            if (first_path_index <= 1 || !paths[first_path_index - 1].isTravelPath())  // "<= 1" because we don't want the first travel being changed. That may introduce a hole somewhere
            {
                allow_try_merge = false;
            }
            if (second_path_index + 1 >= paths.size() || !paths[second_path_index + 1].isTravelPath())
            {
                allow_try_merge = false;
            }
            if (first_path.config->isTravelPath()) //Don't merge travel moves.
            {
                allow_try_merge = false;
            }
            if (first_path.config != second_path.config) //Only merge lines that have the same type.
            {
                allow_try_merge = false;
            }
            if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
            {
                allow_try_merge = false;
            }
            const bool first_is_already_merged = is_merged.find(first_path_index) != is_merged.end();
            if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
            {
                // For now we only merge simple lines, not polylines, to keep it simple.
                // If the first line is already a merged line, then allow it.
                allow_try_merge = false;
            }

            Point new_first_path_start;
            if (allow_try_merge && tryMerge(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area))
            {
                if (!first_is_already_merged)
                {
                    paths[first_path_index - 1].points.back().X = new_first_path_start.X;
                    paths[first_path_index - 1].points.back().Y = new_first_path_start.Y;
                }
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<commit_msg>Tuned max flow to make better results. CURA-5535<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan, const coord_t nozzle_size, const coord_t maximum_resolution) : extruder_plan(plan), nozzle_size(nozzle_size), maximum_resolution(maximum_resolution)
    {
        //Just copy the parameters to their fields.
    }

    coord_t MergeInfillLines::calcPathLength(const Point path_start, GCodePath& path) const
    {
        Point previous_point = path_start;
        coord_t result = 0;
        for (const Point point : path.points)
        {
            result += vSize(point - previous_point);
            previous_point = point;
        }
        return result;
    }

    /*
     * first_is_already_merged == false
     *
     *       o     o
     *      /     /
     *     /     /
     *    /  +  /      --->   -(t)-o-----o
     *   /     /
     *  /     /
     * o     o
     *
     * travel (t) to first location is done through first_path_start_changed and new_first_path_start.
     * this gets rid of the tiny "blips". Depending on the merged line distance a small gap may appear, but this is
     * accounted for in the volume.
     *
     * first_is_already_merged == true
     *
     *                   o
     *                  /
     *                 /
     *    o-----o  +  /     --->    o-----------o   or with slight   o-----o-----o
     *   /           /             /                   bend         /
     *  /           /             /                                /
     * o           o             o                                o
     *
     */
    bool MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        Point average_first_path;

        coord_t first_path_length = calcPathLength(first_path_start, first_path);
        coord_t first_path_length_flow = first_path_length * first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.
        const coord_t line_width = first_path.config->getLineWidth();

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length = calcPathLength(second_path_start, second_path);
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            average_second_path += point;
        }
        coord_t second_path_length_flow = second_path_length *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        // predict new length and flow and if the new flow is to big, don't merge. conditions in this part must exactly match the actual merging
        coord_t new_path_length = first_path_length;
        coord_t dist2_from_line = 0;
        coord_t new_error_area = 0;
        coord_t merged_part_length = 0;
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1) {
                dist2_from_line = LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size() - 2], first_path.points[first_path.points.size() - 1]);
                merged_part_length = vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
                new_error_area = sqrt(dist2_from_line) * merged_part_length / 2;
            }
            // The max error margin uses the meshfix_maximum_resolution setting
            if (first_path.points.size() > 1 && error_area + new_error_area < merged_part_length * maximum_resolution)
            {
                new_path_length -= vSize(first_path.points[first_path.points.size() - 2] - first_path.points[first_path.points.size() - 1]);
                new_path_length += vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
            }
            else
            {
                new_path_length += vSize(first_path.points[first_path.points.size() - 1] - average_second_path);
            }
        }
        else
        {
            new_path_length -= vSize(first_path.points.back() - first_path_start);
            new_path_length += vSize(average_second_path - average_first_path);
        }
        double new_flow = ((first_path_length_flow + second_path_length_flow) / static_cast<double>(new_path_length));
        if (new_flow > 3 * nozzle_size / line_width)  // line width becomes too wide. strictly speaking it should not exceed 2 * nozzle_size, but 3* produces better results in practice
        {
            return false;
        }

        // do the actual merging
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && error_area + new_error_area < line_width * line_width)
            {
                first_path.points[first_path.points.size() - 1] = average_second_path;
                error_area += new_error_area;
            } else {
                first_path.points.push_back(average_second_path);
                error_area = 0;
            }
        }
        else
        {
            new_first_path_start = average_first_path;
            first_path.points.clear();
            first_path.points.push_back(average_second_path);
            error_area = 0;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;

        return true;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const coord_t line_width = first_path.config->getLineWidth();

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged)
        {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (merged_direction.X == 0 && merged_direction.Y == 0)
        {
            return true;  // we can just disregard the second point as it's exactly at the leave point of the first path.
        }

        // Max 1 line width to the side of the merged_direction
        if (LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            //|| abs(dot(normal(merged_direction, 1000), normal(second_path_end - second_path_start, 1000))) > 866000    // 866000 angle of old second_path with new merged direction should not be too small (30 degrees), as it will introduce holes
            )
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        return mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area);
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point& starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = Point(starting_position.X, starting_position.Y);  // this one is not going to be overwritten
        size_t second_path_index = 1;
        coord_t error_area = 0;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();

            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths, we're looking for the first non-travel path.
            }

            bool allow_try_merge = true;
            // see if we meet criteria to merge. should be: travel - path1 not travel - (...) - travel - path2 not travel - travel
            // we're checking the travels here
            if (first_path_index <= 1 || !paths[first_path_index - 1].isTravelPath())  // "<= 1" because we don't want the first travel being changed. That may introduce a hole somewhere
            {
                allow_try_merge = false;
            }
            if (second_path_index + 1 >= paths.size() || !paths[second_path_index + 1].isTravelPath())
            {
                allow_try_merge = false;
            }
            if (first_path.config->isTravelPath()) //Don't merge travel moves.
            {
                allow_try_merge = false;
            }
            if (first_path.config != second_path.config) //Only merge lines that have the same type.
            {
                allow_try_merge = false;
            }
            if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
            {
                allow_try_merge = false;
            }
            const bool first_is_already_merged = is_merged.find(first_path_index) != is_merged.end();
            if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
            {
                // For now we only merge simple lines, not polylines, to keep it simple.
                // If the first line is already a merged line, then allow it.
                allow_try_merge = false;
            }

            Point new_first_path_start;
            if (allow_try_merge && tryMerge(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area))
            {
                if (!first_is_already_merged)
                {
                    paths[first_path_index - 1].points.back().X = new_first_path_start.X;
                    paths[first_path_index - 1].points.back().Y = new_first_path_start.Y;
                }
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<|endoftext|>


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

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>

#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"

namespace quic {
namespace test {

// DecoderStreamErrorDelegate implementation that crashes on error.
class CrashingDecoderStreamErrorDelegate
    : public QpackEncoder::DecoderStreamErrorDelegate {
 public:
  ~CrashingDecoderStreamErrorDelegate() override = default;

  void OnDecoderStreamError(QuicStringPiece error_message) override {
    CHECK(false) << error_message;
  }
};

// EncoderStreamErrorDelegate implementation that crashes on error.
class CrashingEncoderStreamErrorDelegate
    : public QpackDecoder::EncoderStreamErrorDelegate {
 public:
  ~CrashingEncoderStreamErrorDelegate() override = default;

  void OnEncoderStreamError(QuicStringPiece error_message) override {
    CHECK(false) << error_message;
  }
};

spdy::SpdyHeaderBlock GenerateHeaderList(QuicFuzzedDataProvider* provider) {
  spdy::SpdyHeaderBlock header_list;
  uint8_t header_count = provider->ConsumeIntegral<uint8_t>();
  for (uint8_t header_index = 0; header_index < header_count; ++header_index) {
    if (provider->remaining_bytes() == 0) {
      // Do not add more headers if there is no more fuzzer data.
      break;
    }

    std::string name;
    std::string value;
    switch (provider->ConsumeIntegral<uint8_t>()) {
      case 0:
        // Static table entry with no header value.
        name = ":authority";
        break;
      case 1:
        // Static table entry with no header value, using non-empty header
        // value.
        name = ":authority";
        value = "www.example.org";
        break;
      case 2:
        // Static table entry with header value, using that header value.
        name = ":accept-encoding";
        value = "gzip, deflate";
        break;
      case 3:
        // Static table entry with header value, using empty header value.
        name = ":accept-encoding";
        break;
      case 4:
        // Static table entry with header value, using different, non-empty
        // header value.
        name = ":accept-encoding";
        value = "brotli";
        break;
      case 5:
        // Header name that has multiple entries in the static table,
        // using header value from one of them.
        name = ":method";
        value = "GET";
        break;
      case 6:
        // Header name that has multiple entries in the static table,
        // using empty header value.
        name = ":method";
        break;
      case 7:
        // Header name that has multiple entries in the static table,
        // using different, non-empty header value.
        name = ":method";
        value = "CONNECT";
        break;
      case 8:
        // Header name not in the static table, empty header value.
        name = "foo";
        value = "";
        break;
      case 9:
        // Header name not in the static table, non-empty fixed header value.
        name = "foo";
        value = "bar";
        break;
      case 10:
        // Header name not in the static table, fuzzed header value.
        name = "foo";
        value = provider->ConsumeRandomLengthString(128);
        break;
      case 11:
        // Another header name not in the static table, empty header value.
        name = "bar";
        value = "";
        break;
      case 12:
        // Another header name not in the static table, non-empty fixed header
        // value.
        name = "bar";
        value = "baz";
        break;
      case 13:
        // Another header name not in the static table, fuzzed header value.
        name = "bar";
        value = provider->ConsumeRandomLengthString(128);
        break;
      default:
        // Fuzzed header name and header value.
        name = provider->ConsumeRandomLengthString(128);
        value = provider->ConsumeRandomLengthString(128);
    }

    header_list.AppendValueOrAddHeader(name, value);
  }

  return header_list;
}

spdy::SpdyHeaderBlock DecodeHeaderBlock(QpackDecoder* decoder,
                                        QuicStreamId stream_id,
                                        const std::string& encoded_header_block,
                                        QuicFuzzedDataProvider* provider) {
  // Process up to 256 bytes at a time.  Such a small size helps test
  // fragmented decoding.
  auto fragment_size_generator =
      std::bind(&QuicFuzzedDataProvider::ConsumeIntegralInRange<uint8_t>,
                provider, 1, std::numeric_limits<uint8_t>::max());

  TestHeadersHandler handler;
  auto progressive_decoder =
      decoder->CreateProgressiveDecoder(stream_id, &handler);
  {
    QuicStringPiece remaining_data = encoded_header_block;
    while (!remaining_data.empty()) {
      size_t fragment_size =
          std::min<size_t>(fragment_size_generator(), remaining_data.size());
      progressive_decoder->Decode(remaining_data.substr(0, fragment_size));
      remaining_data = remaining_data.substr(fragment_size);
    }
  }
  progressive_decoder->EndHeaderBlock();

  // Since header block has been produced by encoding a header list, it must be
  // valid.
  CHECK(handler.decoding_completed());
  CHECK(!handler.decoding_error_detected());

  return handler.ReleaseHeaderList();
}

// Splits |*header_list| header values along '\0' or ';' separators.
spdy::SpdyHeaderBlock SplitHeaderList(
    const spdy::SpdyHeaderBlock& header_list) {
  ValueSplittingHeaderList splitting_header_list(&header_list);
  spdy::SpdyHeaderBlock split_header_list;
  for (const auto& header : splitting_header_list) {
    split_header_list.AppendValueOrAddHeader(header.first, header.second);
  }
  return split_header_list;
}

// This fuzzer exercises QpackEncoder and QpackDecoder.  It should be able to
// cover all possible code paths of QpackEncoder.  However, since the resulting
// header block is always valid and is encoded in a particular way, this fuzzer
// is not expected to cover all code paths of QpackDecoder.  On the other hand,
// encoding then decoding is expected to result in the original header list, and
// this fuzzer checks for that.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  QuicFuzzedDataProvider provider(data, size);

  // Maximum 256 byte dynamic table.  Such a small size helps test draining
  // entries and eviction.
  const uint64_t maximum_dynamic_table_capacity =
      provider.ConsumeIntegral<uint8_t>();
  // Maximum 256 blocked stream.
  const uint64_t maximum_blocked_streams = provider.ConsumeIntegral<uint8_t>();

  // Set up encoder.
  CrashingDecoderStreamErrorDelegate decoder_stream_error_delegate;
  NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
  QpackEncoder encoder(&decoder_stream_error_delegate);
  encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate);
  encoder.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
  encoder.SetMaximumBlockedStreams(maximum_blocked_streams);

  // Set up decoder.
  CrashingEncoderStreamErrorDelegate encoder_stream_error_delegate;
  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
  QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams,
                       &encoder_stream_error_delegate);
  decoder.set_qpack_stream_sender_delegate(&decoder_stream_sender_delegate);

  while (provider.remaining_bytes() > 0) {
    const QuicStreamId stream_id = provider.ConsumeIntegral<uint8_t>();

    // Generate header list.
    spdy::SpdyHeaderBlock header_list = GenerateHeaderList(&provider);

    // Encode header list.
    std::string encoded_header_block =
        encoder.EncodeHeaderList(stream_id, &header_list);

    // Decode resulting header block.
    spdy::SpdyHeaderBlock decoded_header_list =
        DecodeHeaderBlock(&decoder, stream_id, encoded_header_block, &provider);

    // Encoder splits |header_list| header values along '\0' or ';' separators.
    // Do the same here so that we get matching results.
    spdy::SpdyHeaderBlock expected_header_list = SplitHeaderList(header_list);

    // Compare resulting header list to original.
    CHECK(expected_header_list == decoded_header_list);
  }

  return 0;
}

}  // namespace test
}  // namespace quic
<commit_msg>Refactor QPACK roundtrip fuzzer.<commit_after>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>

#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_stream_sender_delegate.h"
#include "net/third_party/quiche/src/quic/core/qpack/qpack_utils.h"
#include "net/third_party/quiche/src/quic/core/qpack/value_splitting_header_list.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_fuzzed_data_provider.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"

namespace quic {
namespace test {

// Class to hold QpackEncoder and its DecoderStreamErrorDelegate.
class EncodingEndpoint {
 public:
  EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,
                   uint64_t maximum_blocked_streams)
      : encoder_(&decoder_stream_error_delegate) {
    encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
    encoder_.SetMaximumBlockedStreams(maximum_blocked_streams);
  }

  void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
    encoder_.set_qpack_stream_sender_delegate(delegate);
  }

  std::string EncodeHeaderList(QuicStreamId stream_id,
                               const spdy::SpdyHeaderBlock* header_list) {
    return encoder_.EncodeHeaderList(stream_id, header_list);
  }

 private:
  // DecoderStreamErrorDelegate implementation that crashes on error.
  class CrashingDecoderStreamErrorDelegate
      : public QpackEncoder::DecoderStreamErrorDelegate {
   public:
    ~CrashingDecoderStreamErrorDelegate() override = default;

    void OnDecoderStreamError(QuicStringPiece error_message) override {
      CHECK(false) << error_message;
    }
  };

  CrashingDecoderStreamErrorDelegate decoder_stream_error_delegate;
  QpackEncoder encoder_;
};

// Class to decode and verify a header block.
class VerifyingDecoder : public QpackDecodedHeadersAccumulator::Visitor {
 public:
  VerifyingDecoder(QuicStreamId stream_id,
                   QpackDecoder* qpack_decoder,
                   QuicHeaderList expected_header_list)
      : accumulator_(
            stream_id,
            qpack_decoder,
            this,
            /* max_header_list_size = */ std::numeric_limits<size_t>::max()),
        expected_header_list_(std::move(expected_header_list)) {}

  VerifyingDecoder(const VerifyingDecoder&) = delete;
  VerifyingDecoder& operator=(const VerifyingDecoder&) = delete;
  // VerifyingDecoder must not be moved because it passes |this| to
  // |accumulator_| upon construction.
  VerifyingDecoder(VerifyingDecoder&&) = delete;
  VerifyingDecoder& operator=(VerifyingDecoder&&) = delete;

  virtual ~VerifyingDecoder() = default;

  // QpackDecodedHeadersAccumulator::Visitor implementation.
  void OnHeadersDecoded(QuicHeaderList /*headers*/) override {}

  void OnHeaderDecodingError() override {
    CHECK(false) << accumulator_.error_message();
  }

  void Decode(QuicStringPiece data) {
    const bool success = accumulator_.Decode(data);
    CHECK(success) << accumulator_.error_message();
  }

  void EndHeaderBlock() {
    QpackDecodedHeadersAccumulator::Status status =
        accumulator_.EndHeaderBlock();

    CHECK(status != QpackDecodedHeadersAccumulator::Status::kError)
        << accumulator_.error_message();

    CHECK(status == QpackDecodedHeadersAccumulator::Status::kSuccess);

    // Compare resulting header list to original.
    CHECK(expected_header_list_ == accumulator_.quic_header_list());
  }

 private:
  QpackDecodedHeadersAccumulator accumulator_;
  QuicHeaderList expected_header_list_;
};

// Class that holds QpackDecoder and its EncoderStreamErrorDelegate, and creates
// and keeps VerifyingDecoders for each received header block until decoding is
// complete.
class DecodingEndpoint {
 public:
  DecodingEndpoint(uint64_t maximum_dynamic_table_capacity,
                   uint64_t maximum_blocked_streams)
      : decoder_(maximum_dynamic_table_capacity,
                 maximum_blocked_streams,
                 &encoder_stream_error_delegate_) {}

  ~DecodingEndpoint() {
    // All decoding must have been completed.
    CHECK(expected_header_lists_.empty());
    CHECK(verifying_decoders_.empty());
  }

  void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
    decoder_.set_qpack_stream_sender_delegate(delegate);
  }

  void AddExpectedHeaderList(QuicStreamId stream_id,
                             QuicHeaderList expected_header_list) {
    auto it = expected_header_lists_.lower_bound(stream_id);
    if (it == expected_header_lists_.end() || it->first != stream_id) {
      it = expected_header_lists_.insert(it, {stream_id, {}});
    }
    CHECK_EQ(stream_id, it->first);
    it->second.push(std::move(expected_header_list));
  }

  void OnHeaderBlockStart(QuicStreamId stream_id) {
    auto it = expected_header_lists_.find(stream_id);
    CHECK(it != expected_header_lists_.end());

    auto& header_list_queue = it->second;
    QuicHeaderList expected_header_list = std::move(header_list_queue.front());

    header_list_queue.pop();
    if (header_list_queue.empty()) {
      expected_header_lists_.erase(it);
    }

    auto verifying_decoder = QuicMakeUnique<VerifyingDecoder>(
        stream_id, &decoder_, std::move(expected_header_list));
    auto result =
        verifying_decoders_.insert({stream_id, std::move(verifying_decoder)});
    CHECK(result.second);
  }

  void OnHeaderBlockFragment(QuicStreamId stream_id, QuicStringPiece data) {
    auto it = verifying_decoders_.find(stream_id);
    CHECK(it != verifying_decoders_.end());
    it->second->Decode(data);
  }

  void OnHeaderBlockEnd(QuicStreamId stream_id) {
    auto it = verifying_decoders_.find(stream_id);
    CHECK(it != verifying_decoders_.end());
    it->second->EndHeaderBlock();
    auto result = verifying_decoders_.erase(stream_id);
    CHECK_EQ(1u, result);
  }

 private:
  // EncoderStreamErrorDelegate implementation that crashes on error.
  class CrashingEncoderStreamErrorDelegate
      : public QpackDecoder::EncoderStreamErrorDelegate {
   public:
    ~CrashingEncoderStreamErrorDelegate() override = default;

    void OnEncoderStreamError(QuicStringPiece error_message) override {
      CHECK(false) << error_message;
    }
  };

  CrashingEncoderStreamErrorDelegate encoder_stream_error_delegate_;
  QpackDecoder decoder_;

  // Expected header lists in order for each stream.
  std::map<QuicStreamId, std::queue<QuicHeaderList>> expected_header_lists_;

  // A VerifyingDecoder object keeps context necessary for asynchronously
  // decoding blocked header blocks.  It is destroyed as soon as it signals that
  // decoding is completed, which might happen synchronously within an
  // EndHeaderBlock() call.
  std::map<QuicStreamId, std::unique_ptr<VerifyingDecoder>> verifying_decoders_;
};

// Generate header list using fuzzer data.
spdy::SpdyHeaderBlock GenerateHeaderList(QuicFuzzedDataProvider* provider) {
  spdy::SpdyHeaderBlock header_list;
  uint8_t header_count = provider->ConsumeIntegral<uint8_t>();
  for (uint8_t header_index = 0; header_index < header_count; ++header_index) {
    if (provider->remaining_bytes() == 0) {
      // Do not add more headers if there is no more fuzzer data.
      break;
    }

    std::string name;
    std::string value;
    switch (provider->ConsumeIntegral<uint8_t>()) {
      case 0:
        // Static table entry with no header value.
        name = ":authority";
        break;
      case 1:
        // Static table entry with no header value, using non-empty header
        // value.
        name = ":authority";
        value = "www.example.org";
        break;
      case 2:
        // Static table entry with header value, using that header value.
        name = ":accept-encoding";
        value = "gzip, deflate";
        break;
      case 3:
        // Static table entry with header value, using empty header value.
        name = ":accept-encoding";
        break;
      case 4:
        // Static table entry with header value, using different, non-empty
        // header value.
        name = ":accept-encoding";
        value = "brotli";
        break;
      case 5:
        // Header name that has multiple entries in the static table,
        // using header value from one of them.
        name = ":method";
        value = "GET";
        break;
      case 6:
        // Header name that has multiple entries in the static table,
        // using empty header value.
        name = ":method";
        break;
      case 7:
        // Header name that has multiple entries in the static table,
        // using different, non-empty header value.
        name = ":method";
        value = "CONNECT";
        break;
      case 8:
        // Header name not in the static table, empty header value.
        name = "foo";
        value = "";
        break;
      case 9:
        // Header name not in the static table, non-empty fixed header value.
        name = "foo";
        value = "bar";
        break;
      case 10:
        // Header name not in the static table, fuzzed header value.
        name = "foo";
        value = provider->ConsumeRandomLengthString(128);
        break;
      case 11:
        // Another header name not in the static table, empty header value.
        name = "bar";
        value = "";
        break;
      case 12:
        // Another header name not in the static table, non-empty fixed header
        // value.
        name = "bar";
        value = "baz";
        break;
      case 13:
        // Another header name not in the static table, fuzzed header value.
        name = "bar";
        value = provider->ConsumeRandomLengthString(128);
        break;
      default:
        // Fuzzed header name and header value.
        name = provider->ConsumeRandomLengthString(128);
        value = provider->ConsumeRandomLengthString(128);
    }

    header_list.AppendValueOrAddHeader(name, value);
  }

  return header_list;
}

// Splits |*header_list| header values along '\0' or ';' separators.
QuicHeaderList SplitHeaderList(const spdy::SpdyHeaderBlock& header_list) {
  QuicHeaderList split_header_list;
  split_header_list.set_max_header_list_size(
      std::numeric_limits<size_t>::max());
  split_header_list.OnHeaderBlockStart();

  size_t total_size = 0;
  ValueSplittingHeaderList splitting_header_list(&header_list);
  for (const auto& header : splitting_header_list) {
    split_header_list.OnHeader(header.first, header.second);
    total_size += header.first.size() + header.second.size();
  }

  split_header_list.OnHeaderBlockEnd(total_size, total_size);

  return split_header_list;
}

// This fuzzer exercises QpackEncoder and QpackDecoder.  It should be able to
// cover all possible code paths of QpackEncoder.  However, since the resulting
// header block is always valid and is encoded in a particular way, this fuzzer
// is not expected to cover all code paths of QpackDecoder.  On the other hand,
// encoding then decoding is expected to result in the original header list, and
// this fuzzer checks for that.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  QuicFuzzedDataProvider provider(data, size);

  // Maximum 256 byte dynamic table.  Such a small size helps test draining
  // entries and eviction.
  const uint64_t maximum_dynamic_table_capacity =
      provider.ConsumeIntegral<uint8_t>();
  // Maximum 256 blocked streams.
  const uint64_t maximum_blocked_streams = provider.ConsumeIntegral<uint8_t>();

  // Set up encoder.
  NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
  EncodingEndpoint encoder(maximum_dynamic_table_capacity,
                           maximum_blocked_streams);
  encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate);

  // Set up decoder.
  NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
  DecodingEndpoint decoder(maximum_dynamic_table_capacity,
                           maximum_blocked_streams);
  decoder.set_qpack_stream_sender_delegate(&decoder_stream_sender_delegate);

  while (provider.remaining_bytes() > 0) {
    const QuicStreamId stream_id = provider.ConsumeIntegral<uint8_t>();

    // Generate header list.
    spdy::SpdyHeaderBlock header_list = GenerateHeaderList(&provider);

    // Encode header list.
    std::string encoded_header_block =
        encoder.EncodeHeaderList(stream_id, &header_list);

    // Encoder splits |header_list| header values along '\0' or ';' separators.
    // Do the same here so that we get matching results.
    QuicHeaderList expected_header_list = SplitHeaderList(header_list);
    decoder.AddExpectedHeaderList(stream_id, std::move(expected_header_list));

    // Decode header block.
    decoder.OnHeaderBlockStart(stream_id);
    decoder.OnHeaderBlockFragment(stream_id, encoded_header_block);
    decoder.OnHeaderBlockEnd(stream_id);
  }

  return 0;
}

}  // namespace test
}  // namespace quic
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: submission_post.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2004-11-16 11:01:13 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __SUBMISSION_POST_HXX
#define __SUBMISSION_POST_HXX

#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#include "submission.hxx"

class CSubmissionPost : public CSubmission
{
private:
    CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory;
public:
    CSubmissionPost(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment);
    virtual SubmissionResult submit();

};
#endif
<commit_msg>INTEGRATION: CWS eforms4 (1.2.6); FILE MERGED 2004/12/14 16:08:30 dvo 1.2.6.1: #i36765# use Interaction Handler for submission warning & submission itself Issue number: Submitted by: Reviewed by:<commit_after>/*************************************************************************
 *
 *  $RCSfile: submission_post.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 11:40:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef __SUBMISSION_POST_HXX
#define __SUBMISSION_POST_HXX

#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#include "submission.hxx"

class CSubmissionPost : public CSubmission
{
private:
    CSS::uno::Reference< CSS::lang::XMultiServiceFactory > m_aFactory;
public:
    CSubmissionPost(const rtl::OUString& aURL, const CSS::uno::Reference< CSS::xml::dom::XDocumentFragment >& aFragment);
    virtual SubmissionResult submit(const CSS::uno::Reference< CSS::task::XInteractionHandler >& aInteractionHandler);

};
#endif
<|endoftext|>


<commit_before>// Copyright 2013-2015 Eric Schkufza, Rahul Sharma, Berkeley Churchill, Stefan Heule
//
// 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.

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <list>
#include <cassert>
#include <initializer_list>

#include "src/state/cpu_state.h"
#include "src/symstate/bitvector.h"
#include "src/validator/validator.h"

using namespace std;
using namespace stoke;
using namespace x64asm;

bool regset_is_supported(x64asm::RegSet rs) {

  /* Check to make sure all liveout are supported. */
  /* Right now we support gps, xmms, ACOPSZ eflags */
  RegSet supported = (RegSet::all_gps() | RegSet::all_ymms()) +
                     eflags_cf + eflags_of +
                     eflags_pf + eflags_sf + eflags_zf;

  // Do the check.
  if((supported & rs) != rs) {
    stringstream tmp;
    tmp << (rs - supported);

    string message =
      string("Validator only supports gps (excluding %ah-%dh), xmms and eflags COPSZ in live out.") +
      string("  Not supported: ") + tmp.str();

    throw VALIDATOR_ERROR(message);
    return false;
  }
  return true;
}

bool Validator::is_supported(Instruction& i) {

  SymState s("");
  try {

    build_circuit(i, s);
    return true;

  } catch (validator_error e) {
    has_error_ = true;
    error_message_ = e.get_message();
    error_file_ = e.get_file();
    error_line_ = e.get_line();
    return false;
  }

  return false;
}

void Validator::generate_constraints(const stoke::Cfg& f1, const stoke::Cfg& f2,
                                     SymState& f1_final, SymState& f2_final,
                                     vector<SymBool>& constraints) const {

  // Check to make sure def-ins/live-outs agree
  if (f1.def_ins() != f2.def_ins()) {
    throw VALIDATOR_ERROR("Def-ins of the two CFGs differ");
  }
  if (f1.live_outs() != f2.live_outs()) {
    throw VALIDATOR_ERROR("Live-outs of the two CFGs differ");
  }
  // Check that the regsets are supported, throw an error otherwise
  regset_is_supported(f1.def_ins());
  regset_is_supported(f1.live_outs());

  // Create starting symbolic states
  SymState init("");

  SymState first("1_INIT");
  SymState second("2_INIT");

  for(auto it : first.equality_constraints(init, f1.def_ins()))
    constraints.push_back(it);

  for(auto it : second.equality_constraints(init, f1.def_ins()))
    constraints.push_back(it);

  // Setup aliasing analyses
  AliasAnalysis first_analysis(f1.get_code());
  AliasAnalysis second_analysis(f2.get_code());

  first.memory.set_analysis(&first_analysis);
  second.memory.set_analysis(&second_analysis);

  // Build the circuits
  build_circuit(f1, first);
  build_circuit(f2, second);

  for(auto it : first.constraints)
    constraints.push_back(it);
  for(auto it : second.constraints)
    constraints.push_back(it);

  // Assert inequality of the final states
  SymBool inequality = SymBool::_false();
  for(auto it : first.equality_constraints(second, f1.live_outs())) {
    inequality = inequality | !it;
  }

  constraints.push_back(inequality);
  f1_final = first;
  f2_final = first;

  // Create states to track the final values on each side
  // (this is to get a counterexample)
  SymState first_outputs("1_FINAL");
  SymState second_outputs("2_FINAL");

  for(auto it : first_outputs.equality_constraints(first, f1.live_outs()))
    constraints.push_back(it);
  for(auto it : second_outputs.equality_constraints(second, f1.live_outs()))
    constraints.push_back(it);

  /*
  cout << endl;
  cout << "============= CONSTRAINTS =====================" << endl;
  for(auto it : constraints)
    cout << it << endl;
  */
}

void Validator::build_circuit(const Instruction& instr, SymState& state) const {

  /* For now, we don't handle any control flow */
  if(instr.is_any_jump() || instr.is_any_call() || instr.is_any_return()) {
    stringstream ss;
    ss << "Control flow unsupported: " << instr;
    throw VALIDATOR_ERROR(ss.str());
  }

  /* Otherwise, run the handler and check for errors */
  handler_.build_circuit(instr, state);

  if(handler_.has_error()) {
    stringstream ss;
    ss << "Error building circuit for: " << instr << ".";
    ss << "Handler says: " << handler_.error();
    throw VALIDATOR_ERROR(ss.str());
  }

  /*
  cout << endl;
  cout << "====== STATE AFTER INSTRUCTION " << instr << endl;
  for(size_t i = 0; i < r64s.size(); ++i) {
    cout << r64s[i] << ": " << state[r64s[i]] << endl;
  }
  */
}

void Validator::build_circuit(const Cfg& cfg, SymState& state) const {

  Code code = cfg.get_code();

  for(size_t i = 0; i < code.size(); ++i) {

    if(code[i].is_any_return())
      break;

    state.set_lineno(i);
    build_circuit(code[i], state);
  }
}

/** Takes a *sorted* list of addresses along with the size of the read/write.
 * Determines the stack/heap bounds if we put the first 'pos' addresses in the
 * heap and the remaining 'count - pos' addresses in the stack.  Also checks
 * that the split is "valid", i.e. no read is both in the stack/heap; this
 * check is needed because the sorting doesn't account for overlapping reads
 * (this is the boolean returned). */
bool compute_split(vector<pair<uint64_t, uint16_t>> addresses, size_t pos,
                   uint64_t& heap_min, uint64_t& heap_size,
                   uint64_t& stack_min, uint64_t& stack_size) {

  size_t count = addresses.size();

  // Compute heap bounds
  if(pos) {
    heap_min = addresses[0].first;
    heap_size = addresses[pos-1].first + addresses[pos-1].second - heap_min;
  } else {
    heap_min = 0;
    heap_size = 0;
  }

  // Compute stack bounds
  if(pos == count) {
    stack_min = 0;
    stack_size = 0;
  } else {
    stack_min = addresses[pos].first;
    stack_size = addresses[count-1].first + addresses[count-1].second - stack_min;
  }

  // Check the bounds work
  for(auto p : addresses) {
    if (p.first >= heap_min && (p.first + p.second) <= (heap_min + heap_size - 1))
      continue;
    if (p.first >= stack_min && (p.first + p.second) <= (stack_min + stack_size - 1))
      continue;

    return false;
  }

  return true;
}

CpuState Validator::state_from_model(SMTSolver& smt, const string& name_suffix,
                                     const SymMemory* memory, const SymMemory* memory2) {

  CpuState cs;

  // Get the values of registers
  for(size_t i = 0; i < r64s.size(); ++i) {
    stringstream name;
    name << r64s[i] << name_suffix;
    cs.gp[r64s[i]] = smt.get_model_bv(name.str(), 1);
  }

  for(size_t i = 0; i < ymms.size(); ++i) {
    stringstream name;
    name << ymms[i] << name_suffix;
    cs.sse[ymms[i]] = smt.get_model_bv(name.str(), 4);
  }

  for(size_t i = 0; i < eflags.size(); ++i) {
    if(!cs.rf.is_status(eflags[i].index()))
      continue;

    stringstream name;
    name << eflags[i] << name_suffix;
    cs.rf.set(eflags[i].index(), smt.get_model_bool(name.str()));
  }

  // Figure out error code
  if(smt.get_model_bool("sigbus" + name_suffix)) {
    cs.code = ErrorCode::SIGBUS_;
  } else if (smt.get_model_bool("sigfpe" + name_suffix)) {
    cs.code = ErrorCode::SIGFPE_;
  } else if (smt.get_model_bool("sigsegv" + name_suffix)) {
    cs.code = ErrorCode::SIGSEGV_;
  } else {
    cs.code = ErrorCode::NORMAL;
  }

  // Figure out memory, if needed (this is the last thing).  We can get a list
  // of concrete addresses accessed, and need to split these addresses into
  // heap/stack.  My goal is to just optimize the size of each of the heap and
  // the stack; the algorithm is to just sort the addresses and try every
  // possible place to split them.  This is O(n^2) where n is the number of
  // addresses.  The sorting O(n*log n) is dominated by the loop where we check
  // the goodness of each split; calculating the goodness costs O(n) and we
  // need to do this O(n) times.

  if(!memory && !memory2) {
    cs.stack.resize(0, 0);
    cs.heap.resize(0, 0);
    return cs;
  }

  auto concrete = vector<pair<uint64_t, uint16_t>>();
  if(memory) {
    for(auto p : memory->get_address_vars()) {
      concrete.push_back(pair<uint64_t, uint16_t>(smt.get_model_bv(p.first, 1).get_fixed_quad(0), p.second));
    }
  }
  if(memory2) {
    for(auto p : memory2->get_address_vars()) {
      concrete.push_back(pair<uint64_t, uint16_t>(smt.get_model_bv(p.first, 1).get_fixed_quad(0), p.second));
    }
  }

  auto compare = [] (const pair<uint64_t, uint16_t>& p1, const pair<uint64_t, uint16_t>& p2) {
    if(p1.first - p2.first == 0)
      return (uint64_t)(p1.second - p2.second);
    return p1.first - p2.first;
  };
  sort(concrete.begin(), concrete.end(), compare);

  uint64_t heap_min, heap_size, stack_min, stack_size;
  bool ok = compute_split(concrete, 0, heap_min, heap_size, stack_min, stack_size);
  assert(ok);

  uint64_t best = heap_size + stack_size;
  size_t best_index = 0;
  for (size_t i = 1; i < concrete.size(); ++i) {
    ok = compute_split(concrete, i, heap_min, heap_size, stack_min, stack_size);
    if(!ok)
      continue;
    uint64_t quality = heap_size + stack_size;
    if(quality < best) {
      best = quality;
      best_index = i;
    }
  }

  ok = compute_split(concrete, best_index, heap_min, heap_size, stack_min, stack_size);
  assert(ok);

  cs.stack.resize(stack_min, stack_size); //base, size
  cs.heap.resize(heap_min, heap_size);  //base, size

  // Now set the defined bits
  for(auto p : concrete) {
    if(cs.stack.in_range(p.first) && cs.stack.in_range(p.first + p.second - 1)) {
      for(size_t i = 0; i < p.second; ++i) {
        cs.stack.set_valid(p.first + i, true);
      }
    }
    if(cs.heap.in_range(p.first) && cs.heap.in_range(p.first + p.second - 1)) {
      for(size_t i = 0; i < p.second; ++i) {
        cs.heap.set_valid(p.first + i, true);
      }
    }
  }

  return cs;

}

bool Validator::validate(const Cfg& target, const Cfg& rewrite, CpuState& counter_example)
{
#ifdef DEBUG_VALIDATOR
  std::cout << "Enter the dragon!" << std::endl;
#endif
  // State
  has_error_ = false;

  try {

    // Generate constraints
    vector<SymBool> constraints;
    SymState target_final;
    SymState rewrite_final;
    generate_constraints(target, rewrite, target_final, rewrite_final, constraints);

    // Run the solver
    bool is_sat = solver_.is_sat(constraints);

    if(solver_.has_error())
      throw VALIDATOR_ERROR("solver: " + solver_.get_error());

    // Do we have a counterexample?
    if (is_sat && solver_.has_model()) {

      counterexample_valid_ = true;
      counterexample_ =      state_from_model(solver_, "_", &target_final.memory, &rewrite_final.memory);
      target_final_state_  = state_from_model(solver_, "_1_FINAL");
      rewrite_final_state_ = state_from_model(solver_, "_2_FINAL");

      counter_example = counterexample_;

    } else {
      counterexample_valid_ = false;
    }

    return !is_sat;

  } catch(validator_error e) {

    has_error_ = true;
    error_message_ = e.get_message();
    error_file_ = e.get_file();
    error_line_ = e.get_line();
    counterexample_valid_ = false;

    return 0;
  }
}

<commit_msg>validator treats mxcsr as supported<commit_after>// Copyright 2013-2015 Eric Schkufza, Rahul Sharma, Berkeley Churchill, Stefan Heule
//
// 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.

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <list>
#include <cassert>
#include <initializer_list>

#include "src/state/cpu_state.h"
#include "src/symstate/bitvector.h"
#include "src/validator/validator.h"

using namespace std;
using namespace stoke;
using namespace x64asm;

bool regset_is_supported(x64asm::RegSet rs) {

  /* Check to make sure all liveout are supported. */
  /* Right now we support gps, xmms, ACOPSZ eflags */
  RegSet supported = (RegSet::all_gps() | RegSet::all_ymms()) +
                     eflags_cf + eflags_of +
                     eflags_pf + eflags_sf + eflags_zf;

  // TODO mxcsr's presense here is a bug.  See #339.
  for(size_t i = 0; i < mxcsr.size(); ++i) {
    supported = supported + mxcsr[i];
  }

  // Do the check.
  if((supported & rs) != rs) {
    stringstream tmp;
    tmp << (rs - supported);

    string message =
      string("Validator only supports gps (excluding %ah-%dh), xmms and eflags COPSZ in live out.") +
      string("  Not supported: ") + tmp.str();

    throw VALIDATOR_ERROR(message);
    return false;
  }
  return true;
}

bool Validator::is_supported(Instruction& i) {

  SymState s("");
  try {

    build_circuit(i, s);
    return true;

  } catch (validator_error e) {
    has_error_ = true;
    error_message_ = e.get_message();
    error_file_ = e.get_file();
    error_line_ = e.get_line();
    return false;
  }

  return false;
}

void Validator::generate_constraints(const stoke::Cfg& f1, const stoke::Cfg& f2,
                                     SymState& f1_final, SymState& f2_final,
                                     vector<SymBool>& constraints) const {

  // Check to make sure def-ins/live-outs agree
  if (f1.def_ins() != f2.def_ins()) {
    throw VALIDATOR_ERROR("Def-ins of the two CFGs differ");
  }
  if (f1.live_outs() != f2.live_outs()) {
    throw VALIDATOR_ERROR("Live-outs of the two CFGs differ");
  }
  // Check that the regsets are supported, throw an error otherwise
  regset_is_supported(f1.def_ins());
  regset_is_supported(f1.live_outs());

  // Create starting symbolic states
  SymState init("");

  SymState first("1_INIT");
  SymState second("2_INIT");

  for(auto it : first.equality_constraints(init, f1.def_ins()))
    constraints.push_back(it);

  for(auto it : second.equality_constraints(init, f1.def_ins()))
    constraints.push_back(it);

  // Setup aliasing analyses
  AliasAnalysis first_analysis(f1.get_code());
  AliasAnalysis second_analysis(f2.get_code());

  first.memory.set_analysis(&first_analysis);
  second.memory.set_analysis(&second_analysis);

  // Build the circuits
  build_circuit(f1, first);
  build_circuit(f2, second);

  for(auto it : first.constraints)
    constraints.push_back(it);
  for(auto it : second.constraints)
    constraints.push_back(it);

  // Assert inequality of the final states
  SymBool inequality = SymBool::_false();
  for(auto it : first.equality_constraints(second, f1.live_outs())) {
    inequality = inequality | !it;
  }

  constraints.push_back(inequality);
  f1_final = first;
  f2_final = first;

  // Create states to track the final values on each side
  // (this is to get a counterexample)
  SymState first_outputs("1_FINAL");
  SymState second_outputs("2_FINAL");

  for(auto it : first_outputs.equality_constraints(first, f1.live_outs()))
    constraints.push_back(it);
  for(auto it : second_outputs.equality_constraints(second, f1.live_outs()))
    constraints.push_back(it);

  /*
  cout << endl;
  cout << "============= CONSTRAINTS =====================" << endl;
  for(auto it : constraints)
    cout << it << endl;
  */
}

void Validator::build_circuit(const Instruction& instr, SymState& state) const {

  /* For now, we don't handle any control flow */
  if(instr.is_any_jump() || instr.is_any_call() || instr.is_any_return()) {
    stringstream ss;
    ss << "Control flow unsupported: " << instr;
    throw VALIDATOR_ERROR(ss.str());
  }

  /* Otherwise, run the handler and check for errors */
  handler_.build_circuit(instr, state);

  if(handler_.has_error()) {
    stringstream ss;
    ss << "Error building circuit for: " << instr << ".";
    ss << "Handler says: " << handler_.error();
    throw VALIDATOR_ERROR(ss.str());
  }

  /*
  cout << endl;
  cout << "====== STATE AFTER INSTRUCTION " << instr << endl;
  for(size_t i = 0; i < r64s.size(); ++i) {
    cout << r64s[i] << ": " << state[r64s[i]] << endl;
  }
  */
}

void Validator::build_circuit(const Cfg& cfg, SymState& state) const {

  Code code = cfg.get_code();

  for(size_t i = 0; i < code.size(); ++i) {

    if(code[i].is_any_return())
      break;

    state.set_lineno(i);
    build_circuit(code[i], state);
  }
}

/** Takes a *sorted* list of addresses along with the size of the read/write.
 * Determines the stack/heap bounds if we put the first 'pos' addresses in the
 * heap and the remaining 'count - pos' addresses in the stack.  Also checks
 * that the split is "valid", i.e. no read is both in the stack/heap; this
 * check is needed because the sorting doesn't account for overlapping reads
 * (this is the boolean returned). */
bool compute_split(vector<pair<uint64_t, uint16_t>> addresses, size_t pos,
                   uint64_t& heap_min, uint64_t& heap_size,
                   uint64_t& stack_min, uint64_t& stack_size) {

  size_t count = addresses.size();

  // Compute heap bounds
  if(pos) {
    heap_min = addresses[0].first;
    heap_size = addresses[pos-1].first + addresses[pos-1].second - heap_min;
  } else {
    heap_min = 0;
    heap_size = 0;
  }

  // Compute stack bounds
  if(pos == count) {
    stack_min = 0;
    stack_size = 0;
  } else {
    stack_min = addresses[pos].first;
    stack_size = addresses[count-1].first + addresses[count-1].second - stack_min;
  }

  // Check the bounds work
  for(auto p : addresses) {
    if (p.first >= heap_min && (p.first + p.second) <= (heap_min + heap_size - 1))
      continue;
    if (p.first >= stack_min && (p.first + p.second) <= (stack_min + stack_size - 1))
      continue;

    return false;
  }

  return true;
}

CpuState Validator::state_from_model(SMTSolver& smt, const string& name_suffix,
                                     const SymMemory* memory, const SymMemory* memory2) {

  CpuState cs;

  // Get the values of registers
  for(size_t i = 0; i < r64s.size(); ++i) {
    stringstream name;
    name << r64s[i] << name_suffix;
    cs.gp[r64s[i]] = smt.get_model_bv(name.str(), 1);
  }

  for(size_t i = 0; i < ymms.size(); ++i) {
    stringstream name;
    name << ymms[i] << name_suffix;
    cs.sse[ymms[i]] = smt.get_model_bv(name.str(), 4);
  }

  for(size_t i = 0; i < eflags.size(); ++i) {
    if(!cs.rf.is_status(eflags[i].index()))
      continue;

    stringstream name;
    name << eflags[i] << name_suffix;
    cs.rf.set(eflags[i].index(), smt.get_model_bool(name.str()));
  }

  // Figure out error code
  if(smt.get_model_bool("sigbus" + name_suffix)) {
    cs.code = ErrorCode::SIGBUS_;
  } else if (smt.get_model_bool("sigfpe" + name_suffix)) {
    cs.code = ErrorCode::SIGFPE_;
  } else if (smt.get_model_bool("sigsegv" + name_suffix)) {
    cs.code = ErrorCode::SIGSEGV_;
  } else {
    cs.code = ErrorCode::NORMAL;
  }

  // Figure out memory, if needed (this is the last thing).  We can get a list
  // of concrete addresses accessed, and need to split these addresses into
  // heap/stack.  My goal is to just optimize the size of each of the heap and
  // the stack; the algorithm is to just sort the addresses and try every
  // possible place to split them.  This is O(n^2) where n is the number of
  // addresses.  The sorting O(n*log n) is dominated by the loop where we check
  // the goodness of each split; calculating the goodness costs O(n) and we
  // need to do this O(n) times.

  if(!memory && !memory2) {
    cs.stack.resize(0, 0);
    cs.heap.resize(0, 0);
    return cs;
  }

  auto concrete = vector<pair<uint64_t, uint16_t>>();
  if(memory) {
    for(auto p : memory->get_address_vars()) {
      concrete.push_back(pair<uint64_t, uint16_t>(smt.get_model_bv(p.first, 1).get_fixed_quad(0), p.second));
    }
  }
  if(memory2) {
    for(auto p : memory2->get_address_vars()) {
      concrete.push_back(pair<uint64_t, uint16_t>(smt.get_model_bv(p.first, 1).get_fixed_quad(0), p.second));
    }
  }

  auto compare = [] (const pair<uint64_t, uint16_t>& p1, const pair<uint64_t, uint16_t>& p2) {
    if(p1.first - p2.first == 0)
      return (uint64_t)(p1.second - p2.second);
    return p1.first - p2.first;
  };
  sort(concrete.begin(), concrete.end(), compare);

  uint64_t heap_min, heap_size, stack_min, stack_size;
  bool ok = compute_split(concrete, 0, heap_min, heap_size, stack_min, stack_size);
  assert(ok);

  uint64_t best = heap_size + stack_size;
  size_t best_index = 0;
  for (size_t i = 1; i < concrete.size(); ++i) {
    ok = compute_split(concrete, i, heap_min, heap_size, stack_min, stack_size);
    if(!ok)
      continue;
    uint64_t quality = heap_size + stack_size;
    if(quality < best) {
      best = quality;
      best_index = i;
    }
  }

  ok = compute_split(concrete, best_index, heap_min, heap_size, stack_min, stack_size);
  assert(ok);

  cs.stack.resize(stack_min, stack_size); //base, size
  cs.heap.resize(heap_min, heap_size);  //base, size

  // Now set the defined bits
  for(auto p : concrete) {
    if(cs.stack.in_range(p.first) && cs.stack.in_range(p.first + p.second - 1)) {
      for(size_t i = 0; i < p.second; ++i) {
        cs.stack.set_valid(p.first + i, true);
      }
    }
    if(cs.heap.in_range(p.first) && cs.heap.in_range(p.first + p.second - 1)) {
      for(size_t i = 0; i < p.second; ++i) {
        cs.heap.set_valid(p.first + i, true);
      }
    }
  }

  return cs;

}

bool Validator::validate(const Cfg& target, const Cfg& rewrite, CpuState& counter_example)
{
#ifdef DEBUG_VALIDATOR
  std::cout << "Enter the dragon!" << std::endl;
#endif
  // State
  has_error_ = false;

  try {

    // Generate constraints
    vector<SymBool> constraints;
    SymState target_final;
    SymState rewrite_final;
    generate_constraints(target, rewrite, target_final, rewrite_final, constraints);

    // Run the solver
    bool is_sat = solver_.is_sat(constraints);

    if(solver_.has_error())
      throw VALIDATOR_ERROR("solver: " + solver_.get_error());

    // Do we have a counterexample?
    if (is_sat && solver_.has_model()) {

      counterexample_valid_ = true;
      counterexample_ =      state_from_model(solver_, "_", &target_final.memory, &rewrite_final.memory);
      target_final_state_  = state_from_model(solver_, "_1_FINAL");
      rewrite_final_state_ = state_from_model(solver_, "_2_FINAL");

      counter_example = counterexample_;

    } else {
      counterexample_valid_ = false;
    }

    return !is_sat;

  } catch(validator_error e) {

    has_error_ = true;
    error_message_ = e.get_message();
    error_file_ = e.get_file();
    error_line_ = e.get_line();
    counterexample_valid_ = false;

    return 0;
  }
}

<|endoftext|>