Repository navigation
Refuse input integers outside 32 bits - #413
Merged
jserv merged 2 commits intoOct 21, 2026
Merged
Conversation
A candidate case was typed as an integer whenever Number.isInteger held, but the C, C++ and Java harnesses write every integer into an int, so 3000000000 reached C and C++ as -1294967296 and made javac refuse the whole run with a note blaming the signature. Integers and the integer values of lists, trees and random lists are now bounded to 32 bits when the case is added, the same for every language, and the range is named only when it is the sole fault. Closes sysprog21#387
jserv
reviewed
Oct 21, 2026
nativeLiteral wrote a double as String(value), so 2147483648 came out with no point. javac reads such a numeral as an int literal whatever it is assigned to and refuses one past the int range, so the whole run failed with the signature note. A double whose text has no point or exponent now gets ".0", which C, C++ and Java all read as the same double.
Contributor
|
Thank @hankliuliu for contributing! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A candidate case is checked once, when it is added, and its integers only had to pass
Number.isInteger, but the C, C++ and Java harnesses write everyintegerinto anint. This change refuses a value outside -2147483648 to 2147483647 at that point, the same for every language. Line numbers below are at 7b10c56.Why
[3000000000]failscandidateTypeMatcheschecksintegerwithNumber.isIntegerand nothing else (web/runners.js:142). Python and JavaScript then receive the number unchanged, byJSON.stringifyandjson.loadsand by structured clone (web/runners.js:1175,:1058,:833). C, C++ and Java do not: every harness declaresintegerasint(web/compiler-explorer.js:9,:21,:33), the type vocabulary has no wider integer, andnativeLiteralwrites the value into the source asString(value)(:73), so the harness containsint n = 3000000000;.Each language then applies its own rule to a constant that does not fit in
int:3000000000is alongconstant, and converting an out-of-range value tointis implementation-defined (C17 6.3.1.3p3). The clang on Compiler Explorer (cclang1910) wrapped it modulo 2^32 with only a warning, so the solution received-1294967296; another compiler is free to do otherwise.int n = 3000000000;also gives-1294967296, while list-initialization of anintfrom that constant is narrowing and ill-formed, which g++ reports as an error.intliteral above 2147483647 is a compile-time error (JLS 3.10.1), whatever it is assigned to. The error sits on a harness line, soremapDiagnosticsaddsHARNESS_SIGNATURE_NOTE(web/compiler-explorer.js:252), which blames a signature the candidate did not change.A compile error replaces the whole run with a setup error (
web/runners.js:337-343), so the built-in results are lost as well. The compilers do warn, but a run that compiles returns only its stdout (web/compiler-explorer.js:224), so the candidate never sees the warning.When it fails
From the generators, a candidate case breaks a C, C++ or Java run when it puts an integer outside -2147483648 to 2147483647 at a position the harness writes as an
int: anintegerparameter, every element ofinteger[],integer[][]andlist<list<integer>>, the values of a linked list, a list of linked lists, a binary tree, a next-pointer tree and a random-pointer list, a tree node reference, and a class method or constructor argument, including a tree built for a constructor (web/compiler-explorer.js:868-1083,:625-651,:804-820;inferredCandidateType,web/runners.js:195). Three integer positions are held in range by other checks whatever the values: the cycle position by the list length (web/runners.js:86-94), graph neighbors by the node count (:184-186) and a random pointer by the list length (:170-172). A tree node reference is checked only for membership in the tree (:95-100), so it is in range only once the tree's own values are: at 7b10c56,[[3000000000,1],3000000000,1]passes both checks. The value counts however it is typed:[3e9]is3000000000afterJSON.parse, and[9007199254740993]is already9007199254740992before any check.What the candidate then sees depends on the language and on how the harness writes the value. With the compilers on Compiler Explorer, C wrapped every value measured below, which the standard leaves to the implementation. C++ fails to compile where braces initialize an
intdirectly, which is avector<int>literal (web/compiler-explorer.js:970, also used by the linked-list helpers) or the constructor callinstance{...}(:588), and converts the value elsewhere: a scalar, a method argument (:609), and trees and random lists, whose values pass through theoptional<int>andpair<int, optional<int>>constructors of their helpers (:538,:540,:544). Java always fails to compile. A value JavaScript writes in exponent form, such as1e21, becomes adoubleliteral instead: its conversion tointis undefined in C, and Java reportspossible lossy conversion from double to int.Measurements
Measured at 0fecc33; the inputs are written the same way at 6756678, whose
web/compiler-explorer.jschanges since then only affect how results are printed.runBrowserTestsran in headless Chromium as the page calls it, with Python in the vendored Pyodide, JavaScript in the blob Worker, and C, C++ and Java on Compiler Explorer (cclang1910,g162,java2501). Each case went throughparseCandidateCasefirst, each solution returns the value it was given, and every row also ran with7in place of3000000000as a control, which returned7in all five languages.3000000000integer(robot-stride-plans)integer[](replica-quorum-version)integer[][](batch-health-check-windows)list<list<integer>>(mine-level-descent)firmware-event-chain-ordering)workflow-handoff-loop)shard-result-consolidation)right-to-left-layout)org-chart-row-navigation)shared-approver-lookup)outline-snapshot-duplicator)bounded-event-queue,push)bounded-event-queue)ordered-index-cursor)"wrapped" is
-1294967296with no error; "narrowing" isnarrowing conversion of '3000000000' from 'long int' to 'int'and "too large" isinteger number too large, both followed by the signature note. Both bounds are exact in all five languages,4294967296arrived in C and C++ as0, and inworkflow-handoff-loopthe wrap turned atrueanswer intofalsein C.Change
candidateTypeMatchestakes the integer check as a parameter,isInt32by default, and applies it tointegerand to the integer values of lists, trees and random lists, through the[],list<>and list-of-lists recursion. When a case is refused, the caller asks again withNumber.isInteger: if the value passes then, its only fault is the range, and the refusal readsParameter <i> (<name>) holds an integer outside -2147483648 to 2147483647., orArguments for operation <name> hold ...for a class judge. Any other mistake keeps the message it had before, so a number given for astringparameter still reads "must match string". The cycle position, graph neighbor and random pointer checks are unchanged, and a tree node reference is bounded through its tree.web/compiler-explorer.js, the problem bank anddocs/are unchanged.Tests
tests/browser/runners.test.jsaccepts both bounds and refuses 2147483648 and -2147483649 in every integer-bearing position: aninteger, an element ofinteger[]andinteger[][], alist<list<integer>>value, the values of a linked list, a list of linked lists, a binary tree, a next-pointer tree and a random-pointer list, and a class method argument, constructor argument and constructor-built tree. A second test checks that the cycle position, tree node reference and graph neighbor keep their own refusals, and that a reference into a tree holding 2147483648 is refused at the tree. Both tests fail at 7b10c56 without the change, with "Missing expected exception", and pass with it. Each part of the change was also undone separately in a scratch copy, such as accepting 2147483648 again or showing the range message for every error, and the tests failed for all 14 variants. All 802 built-in cases inweb/judges/are still accepted byparseCandidateCase.Validation
Prettier and ESLint pass on both files, and the commit message passes
scripts/check-commit-log.sh. At 7b10c56 on Windows,npm testran 1,338 browser tests: 1,009 passed, 324 were skipped, and 5 failed, alltoolchain harnessesC++ subtests, because the local g++ (MinGW 8.1.0) rejects-std=c++20. In WSL (Ubuntu 24.04, g++ 13.3, JDK 21), at 6756678, whose harness code and its tests are unchanged at 7b10c56,tests/browser/compiler-explorer.test.jsran all 43 of its tests, those five included, with none failing or skipped. The Rust lane was not run locally, since this change touches no Rust code; CI covers it.Screenshots
Both screenshots are from a live interview on Robot Stride Plans, where I entered
[3000000000]under Add a case. Before, the case is accepted and listed as "Your case 1: [3000000000]" with "1/5 cases ready." After, with this branch'sweb/runners.jsserved in place of the release's copy, the same input is refused with "Parameter 1 (n) holds an integer outside -2147483648 to 2147483647." and nothing is added to the list.before:

after:

Closes #387
Summary by cubic
Refuses candidate integers outside the 32-bit range when a case is added, so a value like
3000000000no longer silently wraps to-1294967296in C and C++ or makes javac fail the whole run with a note blaming the signature.integervalues and the integer values of lists, trees and random lists; cycle position, graph neighbor and random pointer checks are unchanged..0suffix, since javac reads a numeral without a point or exponent as an int literal even when assigned to a double.tests/browser/runners.test.jscovers both bounds in every integer-bearing position, including class method arguments, constructor arguments and constructor-built trees.Closes #387
Written for commit 7b2ce54. Summary will update on new commits.