diff --git a/CHANGELOG.md b/CHANGELOG.md index 358c69248..edbd665e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Crash when input is valid JSON but not an object (#1172) - Capacity array check consistency (#1086) +- Segfault when using the C++ API with empty vehicles (#1187) #### Internals diff --git a/src/structures/vroom/input/input.cpp b/src/structures/vroom/input/input.cpp index f5c9757ff..46c4486d4 100644 --- a/src/structures/vroom/input/input.cpp +++ b/src/structures/vroom/input/input.cpp @@ -172,6 +172,19 @@ void Input::check_job(Job& job) { _all_locations_have_coords && job.location.has_coordinates(); } +void Input::run_basic_checks() const { + if (vehicles.empty()) { + throw InputException("No vehicle defined."); + } + if (jobs.empty()) { + throw InputException("No task defined."); + } + if (_geometry && !_all_locations_have_coords) { + // Early abort when info is required with missing coordinates. + throw InputException("Route geometry request with missing coordinates."); + } +} + void Input::add_job(const Job& job) { if (job.type != JOB_TYPE::SINGLE) { throw InputException("Wrong job type."); @@ -1106,10 +1119,7 @@ Solution Input::solve(unsigned nb_searches, unsigned nb_thread, const Timeout& timeout, const std::vector& h_param) { - if (_geometry && !_all_locations_have_coords) { - // Early abort when info is required with missing coordinates. - throw InputException("Route geometry request with missing coordinates."); - } + run_basic_checks(); if (_has_initial_routes) { set_vehicle_steps_ranks(); @@ -1189,10 +1199,7 @@ Solution Input::solve(unsigned nb_searches, Solution Input::check(unsigned nb_thread) { #if USE_LIBGLPK - if (_geometry && !_all_locations_have_coords) { - // Early abort when info is required with missing coordinates. - throw InputException("Route geometry request with missing coordinates."); - } + run_basic_checks(); set_vehicle_steps_ranks(); diff --git a/src/structures/vroom/input/input.h b/src/structures/vroom/input/input.h index a5bde472c..dfc6b8227 100644 --- a/src/structures/vroom/input/input.h +++ b/src/structures/vroom/input/input.h @@ -94,6 +94,8 @@ class Input { void check_amount_size(const Amount& amount); void check_job(Job& job); + void run_basic_checks() const; + UserCost check_cost_bound(const Matrix& matrix) const; void set_skills_compatibility(); diff --git a/src/utils/input_parser.cpp b/src/utils/input_parser.cpp index ca9da04f7..bdcad24d9 100644 --- a/src/utils/input_parser.cpp +++ b/src/utils/input_parser.cpp @@ -521,19 +521,15 @@ void parse(Input& input, const std::string& input_str, bool geometry) { throw InputException("Input root is not an object."); } - bool has_jobs = json_input.HasMember("jobs") && - json_input["jobs"].IsArray() && !json_input["jobs"].Empty(); - bool has_shipments = json_input.HasMember("shipments") && - json_input["shipments"].IsArray() && - !json_input["shipments"].Empty(); - if (!has_jobs && !has_shipments) { - throw InputException("Invalid jobs or shipments."); - } - - if (!json_input.HasMember("vehicles") || !json_input["vehicles"].IsArray() || - json_input["vehicles"].Empty()) { + if (!json_input.HasMember("vehicles") || !json_input["vehicles"].IsArray()) { throw InputException("Invalid vehicles."); } + if (json_input["vehicles"].Empty()) { + // This is tested upstream upon solving but we still need to do it + // here to access first vehicle and retrieve amount_size. + throw InputException("No vehicle defined."); + } + const auto& first_vehicle = json_input["vehicles"][0]; check_id(first_vehicle, "vehicle"); bool first_vehicle_has_capacity = (first_vehicle.HasMember("capacity") && @@ -551,16 +547,21 @@ void parse(Input& input, const std::string& input_str, bool geometry) { input.add_vehicle(get_vehicle(json_vehicle, amount_size)); } - // Add all tasks. - if (has_jobs) { - // Add the jobs. + if (json_input.HasMember("jobs")) { + if (!json_input["jobs"].IsArray()) { + throw InputException("Invalid jobs."); + } + for (rapidjson::SizeType i = 0; i < json_input["jobs"].Size(); ++i) { input.add_job(get_job(json_input["jobs"][i], amount_size)); } } - if (has_shipments) { - // Add the shipments. + if (json_input.HasMember("shipments")) { + if (!json_input["shipments"].IsArray()) { + throw InputException("Invalid shipments."); + } + for (rapidjson::SizeType i = 0; i < json_input["shipments"].Size(); ++i) { auto& json_shipment = json_input["shipments"][i]; check_shipment(json_shipment);