Skip to content

fix: validate row type byte before enum cast in MPS parser#1491

Open
ramakrishnap-nv wants to merge 1 commit into
mainfrom
fix/mps-parser-rowtype-validation
Open

fix: validate row type byte before enum cast in MPS parser#1491
ramakrishnap-nv wants to merge 1 commit into
mainfrom
fix/mps-parser-rowtype-validation

Conversation

@ramakrishnap-nv

Copy link
Copy Markdown
Collaborator

Replace unvalidated static_cast<RowType>(char) in parse_rows with a convert_to_row_type() helper that checks the input against the four valid values (N/L/G/E) and raises a ValidationError for anything else. Follows the same pattern as the existing convert() (BoundType) and convert_to_obj_sense() helpers.

Test plan

  • Existing MPS parser tests pass
  • Invalid row type byte in a ROWS section produces a ValidationError instead of UB

Replace unvalidated static_cast<RowType>(char) with convert_to_row_type(),
which validates against the four legal values (N/L/G/E) and raises a
ValidationError for anything else.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ramakrishnap-nv ramakrishnap-nv requested a review from a team as a code owner June 30, 2026 15:45
@ramakrishnap-nv ramakrishnap-nv self-assigned this Jun 30, 2026
@ramakrishnap-nv ramakrishnap-nv added non-breaking Introduces a non-breaking change Agentic This label is used to track agentic and skill related issues labels Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A new convert_to_row_type(char) helper is added to mps_parser.cpp that explicitly maps N, L, G, E to their RowType values and calls mps_parser_expects for invalid characters. The free-format path in parse_rows is updated to call this helper instead of using static_cast.

MPS Row-type Validation

Layer / File(s) Summary
convert_to_row_type helper and parse_rows integration
cpp/src/io/mps_parser.cpp
Adds convert_to_row_type with explicit N/L/G/E mapping and validation error; replaces static_cast<RowType> in parse_rows with this helper.

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main MPS parser validation change.
Description check ✅ Passed The description accurately describes the row type validation fix and the intended test behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mps-parser-rowtype-validation

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/src/io/mps_parser.cpp`:
- Around line 809-812: Parse the free-format row type as a full token in the MPS
parser instead of using a single char in the row-type read path. In
mps_parser.cpp, update the logic around std::stringstream ss, read_word, and
convert_to_row_type so it extracts the complete field, validates that exactly
one token was present, and rejects malformed inputs like extra trailing text
rather than accepting the first character only. Also ensure the code does not
use an uninitialized read_word when extraction fails.
- Around line 805-807: Guard the fixed-format ROWS parsing in mps_parser.cpp
before accessing line[1] or calling line.substr(4, 8) inside the
fixed_mps_format branch. Add a length validation in the ROWS handling path used
by convert_to_row_type and trim so malformed short records fail with
ValidationError first, instead of risking undefined behavior or
std::out_of_range.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 75d6b1e8-1bf2-4d31-a13f-4783f161c1c5

📥 Commits

Reviewing files that changed from the base of the PR and between 2ca56e7 and 251a534.

📒 Files selected for processing (1)
  • cpp/src/io/mps_parser.cpp

Comment thread cpp/src/io/mps_parser.cpp
Comment on lines 805 to 807
if (fixed_mps_format) {
type = static_cast<RowType>(line[1]);
type = convert_to_row_type(line[1]);
name = trim(line.substr(4, 8)); // max of 8 chars allowed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard fixed-format ROWS lines before indexing.

line[1] and line.substr(4, 8) run before any validation, so a short malformed ROWS record can still hit undefined behavior or throw std::out_of_range instead of the intended ValidationError.

Suggested fix
   if (fixed_mps_format) {
+    mps_parser_expects(line.size() >= 5,
+                       error_type_t::ValidationError,
+                       "ROWS should have at least a row type and name! line=%s",
+                       std::string(line).c_str());
     type = convert_to_row_type(line[1]);
     name = trim(line.substr(4, 8));  // max of 8 chars allowed
   } else {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (fixed_mps_format) {
type = static_cast<RowType>(line[1]);
type = convert_to_row_type(line[1]);
name = trim(line.substr(4, 8)); // max of 8 chars allowed
if (fixed_mps_format) {
mps_parser_expects(line.size() >= 5,
error_type_t::ValidationError,
"ROWS should have at least a row type and name! line=%s",
std::string(line).c_str());
type = convert_to_row_type(line[1]);
name = trim(line.substr(4, 8)); // max of 8 chars allowed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/src/io/mps_parser.cpp` around lines 805 - 807, Guard the fixed-format
ROWS parsing in mps_parser.cpp before accessing line[1] or calling
line.substr(4, 8) inside the fixed_mps_format branch. Add a length validation in
the ROWS handling path used by convert_to_row_type and trim so malformed short
records fail with ValidationError first, instead of risking undefined behavior
or std::out_of_range.

Comment thread cpp/src/io/mps_parser.cpp
Comment on lines 809 to +812
std::stringstream ss{std::string(line)};
char read_word;
ss >> read_word;
type = static_cast<RowType>(read_word);
type = convert_to_row_type(read_word);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Parse the free-format row type as a token, not a single char.

operator>>(char) only consumes one non-whitespace byte. That means malformed input like NN COST is accepted as row type N, and if extraction fails read_word is used uninitialized. The new validation should reject the whole field, not just its first byte.

Suggested fix
   } else {
     std::stringstream ss{std::string(line)};
-    char read_word;
-    ss >> read_word;
-    type = convert_to_row_type(read_word);
+    std::string row_type_token;
+    ss >> row_type_token;
+    mps_parser_expects(!row_type_token.empty() && row_type_token.size() == 1,
+                       error_type_t::ValidationError,
+                       "Invalid row type '%s' found in ROWS section; expected N, L, G, or E",
+                       row_type_token.c_str());
+    type = convert_to_row_type(row_type_token[0]);
 
     ss >> name;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
std::stringstream ss{std::string(line)};
char read_word;
ss >> read_word;
type = static_cast<RowType>(read_word);
type = convert_to_row_type(read_word);
std::stringstream ss{std::string(line)};
std::string row_type_token;
ss >> row_type_token;
mps_parser_expects(!row_type_token.empty() && row_type_token.size() == 1,
error_type_t::ValidationError,
"Invalid row type '%s' found in ROWS section; expected N, L, G, or E",
row_type_token.c_str());
type = convert_to_row_type(row_type_token[0]);
ss >> name;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/src/io/mps_parser.cpp` around lines 809 - 812, Parse the free-format row
type as a full token in the MPS parser instead of using a single char in the
row-type read path. In mps_parser.cpp, update the logic around std::stringstream
ss, read_word, and convert_to_row_type so it extracts the complete field,
validates that exactly one token was present, and rejects malformed inputs like
extra trailing text rather than accepting the first character only. Also ensure
the code does not use an uninitialized read_word when extraction fails.

@ramakrishnap-nv ramakrishnap-nv added bug Something isn't working and removed Agentic This label is used to track agentic and skill related issues labels Jun 30, 2026
@github-actions

Copy link
Copy Markdown

CI Test Summary

2 failed · 29 passed · 0 skipped

conda-cpp-tests / 13.3.0, 3.13, arm64, ubuntu26.04, l4, latest-driver, latest-deps — 3 failed tests
  • termination_status.feasible_found_test
  • termination_status.timeout_test
  • termination_status.optimality_test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant