Tracerestrict: Improve program validator
Check all instruction subtypes and valid enum values Return failure instead of asserting for invalid instruction subtypes Identify which instruction triggered validation failure
This commit is contained in:
@@ -450,7 +450,6 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case TRIT_COND_TRAIN_STATUS: {
|
||||
bool has_status = false;
|
||||
switch (static_cast<TraceRestrictTrainStatusValueField>(GetTraceRestrictValue(item))) {
|
||||
@@ -956,11 +955,21 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
TraceRestrictItem item = items[i];
|
||||
TraceRestrictItemType type = GetTraceRestrictType(item);
|
||||
|
||||
auto validation_error = [i](StringID str) -> CommandCost {
|
||||
CommandCost result(str);
|
||||
result.SetResultData((1 << 31) | (uint)i);
|
||||
return result;
|
||||
};
|
||||
|
||||
auto unknown_instruction = [&]() {
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
|
||||
};
|
||||
|
||||
// check multi-word instructions
|
||||
if (IsTraceRestrictDoubleItem(item)) {
|
||||
i++;
|
||||
if (i >= size) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_OFFSET_TOO_LARGE); // instruction ran off end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -969,12 +978,12 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
|
||||
if (type == TRIT_COND_ENDIF) {
|
||||
if (condstack.empty()) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF); // else/endif with no starting if
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_NO_IF); // else/endif with no starting if
|
||||
}
|
||||
if (condflags & TRCF_ELSE) {
|
||||
// else
|
||||
if (condstack.back() & TRCSF_SEEN_ELSE) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // Two else clauses
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // Two else clauses
|
||||
}
|
||||
HandleCondition(condstack, condflags, true);
|
||||
condstack.back() |= TRCSF_SEEN_ELSE;
|
||||
@@ -985,15 +994,221 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
} else {
|
||||
if (condflags & (TRCF_OR | TRCF_ELSE)) { // elif/orif
|
||||
if (condstack.empty()) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF); // Pre-empt assertions in HandleCondition
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_ELIF_NO_IF); // Pre-empt assertions in HandleCondition
|
||||
}
|
||||
if (condstack.back() & TRCSF_SEEN_ELSE) {
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // else clause followed by elif/orif
|
||||
return validation_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_DUP_ELSE); // else clause followed by elif/orif
|
||||
}
|
||||
}
|
||||
HandleCondition(condstack, condflags, true);
|
||||
}
|
||||
|
||||
const TraceRestrictCondOp condop = GetTraceRestrictCondOp(item);
|
||||
auto invalid_condition = [&]() -> bool {
|
||||
switch (condop) {
|
||||
case TRCO_IS:
|
||||
case TRCO_ISNOT:
|
||||
case TRCO_LT:
|
||||
case TRCO_LTE:
|
||||
case TRCO_GT:
|
||||
case TRCO_GTE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
auto invalid_binary_condition = [&]() -> bool {
|
||||
switch (condop) {
|
||||
case TRCO_IS:
|
||||
case TRCO_ISNOT:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
auto invalid_order_condition = [&]() -> bool {
|
||||
if (invalid_binary_condition()) return true;
|
||||
switch (static_cast<TraceRestrictOrderCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TROCAF_STATION:
|
||||
case TROCAF_WAYPOINT:
|
||||
case TROCAF_DEPOT:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* Validation action instruction */
|
||||
switch (GetTraceRestrictType(item)) {
|
||||
case TRIT_COND_ENDIF:
|
||||
case TRIT_COND_UNDEFINED:
|
||||
break;
|
||||
|
||||
case TRIT_COND_TRAIN_LENGTH:
|
||||
case TRIT_COND_MAX_SPEED:
|
||||
case TRIT_COND_LOAD_PERCENT:
|
||||
case TRIT_COND_COUNTER_VALUE:
|
||||
case TRIT_COND_RESERVED_TILES:
|
||||
if (invalid_condition()) return unknown_instruction();
|
||||
break;
|
||||
|
||||
case TRIT_COND_CARGO:
|
||||
case TRIT_COND_TRAIN_GROUP:
|
||||
case TRIT_COND_TRAIN_IN_SLOT:
|
||||
case TRIT_COND_TRAIN_OWNER:
|
||||
case TRIT_COND_RESERVATION_THROUGH:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
break;
|
||||
|
||||
case TRIT_COND_CURRENT_ORDER:
|
||||
case TRIT_COND_NEXT_ORDER:
|
||||
case TRIT_COND_LAST_STATION:
|
||||
if (invalid_order_condition()) return unknown_instruction();
|
||||
break;
|
||||
|
||||
case TRIT_COND_ENTRY_DIRECTION:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
switch (GetTraceRestrictValue(item)) {
|
||||
case TRNTSV_NE:
|
||||
case TRNTSV_SE:
|
||||
case TRNTSV_SW:
|
||||
case TRNTSV_NW:
|
||||
case TRDTSV_FRONT:
|
||||
case TRDTSV_BACK:
|
||||
case TRDTSV_TUNBRIDGE_ENTER:
|
||||
case TRDTSV_TUNBRIDGE_EXIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_PBS_ENTRY_SIGNAL:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictPBSEntrySignalAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRPESAF_VEH_POS:
|
||||
case TRPESAF_RES_END:
|
||||
case TRPESAF_RES_END_TILE:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case TRIT_COND_PHYS_PROP:
|
||||
if (invalid_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictPhysPropCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRPPCAF_WEIGHT:
|
||||
case TRPPCAF_POWER:
|
||||
case TRPPCAF_MAX_TE:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_PHYS_RATIO:
|
||||
if (invalid_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictPhysPropRatioCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRPPRCAF_POWER_WEIGHT:
|
||||
case TRPPRCAF_MAX_TE_WEIGHT:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_TIME_DATE_VALUE:
|
||||
if (invalid_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictTimeDateValueField>(GetTraceRestrictValue(item))) {
|
||||
case TRTDVF_MINUTE:
|
||||
case TRTDVF_HOUR:
|
||||
case TRTDVF_HOUR_MINUTE:
|
||||
case TRTDVF_DAY:
|
||||
case TRTDVF_MONTH:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_CATEGORY:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictCatgeoryCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRCCAF_ENGINE_CLASS:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_TARGET_DIRECTION:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictTargetDirectionCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRTDCAF_CURRENT_ORDER:
|
||||
case TRTDCAF_NEXT_ORDER:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
switch (GetTraceRestrictValue(item)) {
|
||||
case DIAGDIR_NE:
|
||||
case DIAGDIR_SE:
|
||||
case DIAGDIR_SW:
|
||||
case DIAGDIR_NW:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_TRAIN_STATUS:
|
||||
if (invalid_binary_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictTrainStatusValueField>(GetTraceRestrictValue(item))) {
|
||||
case TRTSVF_EMPTY:
|
||||
case TRTSVF_FULL:
|
||||
case TRTSVF_BROKEN_DOWN:
|
||||
case TRTSVF_NEEDS_REPAIR:
|
||||
case TRTSVF_REVERSING:
|
||||
case TRTSVF_HEADING_TO_STATION_WAYPOINT:
|
||||
case TRTSVF_HEADING_TO_DEPOT:
|
||||
case TRTSVF_LOADING:
|
||||
case TRTSVF_WAITING:
|
||||
case TRTSVF_LOST:
|
||||
case TRTSVF_REQUIRES_SERVICE:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COND_SLOT_OCCUPANCY:
|
||||
if (invalid_condition()) return unknown_instruction();
|
||||
switch (static_cast<TraceRestrictSlotOccupancyCondAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRSOCAF_OCCUPANTS:
|
||||
case TRSOCAF_REMAINING:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
|
||||
/* Determine actions_used_flags */
|
||||
switch (GetTraceRestrictType(item)) {
|
||||
case TRIT_COND_ENDIF:
|
||||
case TRIT_COND_UNDEFINED:
|
||||
@@ -1043,13 +1258,29 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
break;
|
||||
|
||||
default:
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
|
||||
/* Validation has already been done, above */
|
||||
NOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
switch (GetTraceRestrictType(item)) {
|
||||
case TRIT_PF_DENY:
|
||||
actions_used_flags |= TRPAUF_PF;
|
||||
break;
|
||||
|
||||
case TRIT_PF_PENALTY:
|
||||
actions_used_flags |= TRPAUF_PF;
|
||||
|
||||
switch (static_cast<TraceRestrictPathfinderPenaltyAuxField>(GetTraceRestrictAuxField(item))) {
|
||||
case TRPPAF_VALUE:
|
||||
break;
|
||||
|
||||
case TRPPAF_PRESET:
|
||||
if (GetTraceRestrictValue(item) >= TRPPPI_END) return unknown_instruction();
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_RESERVE_THROUGH:
|
||||
@@ -1078,8 +1309,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1123,8 +1353,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1139,8 +1368,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1150,26 +1378,72 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
|
||||
|
||||
case TRIT_NEWS_CONTROL:
|
||||
actions_used_flags |= TRPAUF_TRAIN_NOT_STUCK;
|
||||
|
||||
switch (static_cast<TraceRestrictNewsControlField>(GetTraceRestrictValue(item))) {
|
||||
case TRNCF_TRAIN_NOT_STUCK:
|
||||
case TRNCF_CANCEL_TRAIN_NOT_STUCK:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_COUNTER:
|
||||
actions_used_flags |= TRPAUF_CHANGE_COUNTER;
|
||||
|
||||
switch (static_cast<TraceRestrictCounterCondOpField>(GetTraceRestrictCondOp(item))) {
|
||||
case TRCCOF_INCREASE:
|
||||
case TRCCOF_DECREASE:
|
||||
case TRCCOF_SET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_PF_PENALTY_CONTROL:
|
||||
actions_used_flags |= TRPAUF_NO_PBS_BACK_PENALTY;
|
||||
|
||||
switch (static_cast<TraceRestrictPfPenaltyControlField>(GetTraceRestrictValue(item))) {
|
||||
case TRPPCF_NO_PBS_BACK_PENALTY:
|
||||
case TRPPCF_CANCEL_NO_PBS_BACK_PENALTY:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_SPEED_ADAPTATION_CONTROL:
|
||||
actions_used_flags |= TRPAUF_SPEED_ADAPTATION;
|
||||
|
||||
switch (static_cast<TraceRestrictSpeedAdaptationControlField>(GetTraceRestrictValue(item))) {
|
||||
case TRSACF_SPEED_ADAPT_EXEMPT:
|
||||
case TRSACF_REMOVE_SPEED_ADAPT_EXEMPT:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
case TRIT_SIGNAL_MODE_CONTROL:
|
||||
actions_used_flags |= TRPAUF_CMB_SIGNAL_MODE_CTRL;
|
||||
|
||||
switch (static_cast<TraceRestrictSignalModeControlField>(GetTraceRestrictValue(item))) {
|
||||
case TRSMCF_NORMAL_ASPECT:
|
||||
case TRSMCF_SHUNT_ASPECT:
|
||||
break;
|
||||
|
||||
default:
|
||||
return unknown_instruction();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
|
||||
return unknown_instruction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user