Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion saltgui/static/scripts/ParseCommandLine.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,16 @@ export class ParseCommandLine {
// jobIds look like numbers but must be strings
return { value: pStr };
} else if (patInteger.test(pStr)) {
return { value: Number.parseInt(pStr, 10) };
const value = Number.parseInt(pStr, 10);
if (!Number.isSafeInteger(value)) {
// JS numbers are IEEE754 doubles, so an integer above 2**53-1 is rounded
// on the way in and salt would receive a different number than was typed.
// The salt command-line keeps the exact value (as an int, or as a string
// once it is long enough), so refusing is the only honest answer here.
// Job-ids are matched as strings before this point, see getPatJid().
return { error: "Integer argument is too large to be sent exactly" };
}
return { value };
} else if (patFloat.test(pStr)) {
const value = Number.parseFloat(pStr);
if (!Number.isFinite(value)) {
Expand Down
62 changes: 36 additions & 26 deletions tests/unit/ParseCommandLine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,32 +242,42 @@ describe("Unittests for ParseCommandLine.js", () => {
assert.equal(args[0], 0);
assert.equal(Object.keys(params).length, 0);

// an integer that almost looks like a jobid, but one digit less
args = [];
params = {};
result = ParseCommandLine.parseCommandLine("2018082000341133831", args, params);
assert.isNull(result);
assert.equal(args.length, 1);
assert.equal(args[0], 2018082000341133831);
assert.equal(Object.keys(params).length, 0);

// an integer that almost looks like a jobid, but one digit more
args = [];
params = {};
result = ParseCommandLine.parseCommandLine("201808200034113383170", args, params);
assert.isNull(result);
assert.equal(args.length, 1);
assert.equal(args[0], 201808200034113383170);
assert.equal(Object.keys(params).length, 0);

// an integer that almost looks like a jobid, just not a true date-time
args = [];
params = {};
result = ParseCommandLine.parseCommandLine("20182820003411338317", args, params);
assert.isNull(result);
assert.equal(args.length, 1);
assert.equal(args[0], 20182820003411338317);
assert.equal(Object.keys(params).length, 0);
// Integers beyond 2**53-1 cannot be sent exactly, so they are refused
// rather than silently rounded. Expectations compare against strings on
// purpose: written as numeric literals they would be rounded by the test
// itself and could not tell a correct value from a wrong one.
const tooLargeIntegers = [
// almost a jobid, but one digit less
"2018082000341133831",
// almost a jobid, but one digit more
"201808200034113383170",
// jobid-shaped, just not a true date-time
"20182820003411338317",
// the first integer that is no longer exact
"9007199254740993"
];
for (const nr of tooLargeIntegers) {
const label = "value " + nr;
args = [];
params = {};
result = ParseCommandLine.parseCommandLine(nr, args, params);
assert.equal(result, "Integer argument is too large to be sent exactly", label);
assert.equal(args.length, 0, label);
}

// The largest exact integer is still accepted, and a real jobid is matched
// as a string before the integer branch, so it round-trips unchanged.
const exactValues = ["9007199254740991", "20180814033130818988"];
for (const nr of exactValues) {
const label = "value " + nr;
args = [];
params = {};
result = ParseCommandLine.parseCommandLine(nr, args, params);
assert.isNull(result, label);
assert.equal(args.length, 1, label);
assert.equal(String(args[0]), nr, label);
assert.equal(Object.keys(params).length, 0, label);
}

// FLOAT

Expand Down