Skip to content

Refuse a copied random list that loops back - #430

Merged
jserv merged 3 commits into
sysprog21:mainfrom
papaya0112:refuse-cyclic-random-list
Oct 23, 2026
Merged

jserv merged 3 commits into
sysprog21:mainfrom
papaya0112:refuse-cyclic-random-list

Conversation

@papaya0112

@papaya0112 papaya0112 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

A deep copy whose last node links back to the first copy passed Outline Snapshot Duplicator (copy-list-with-random-pointer) in C++, Java, JavaScript and Python, and failed in C with no reason given.

Root cause: checkAnswer compares only the serialized value, so the serializer is the only code that sees the returned structure. The random-list serializers (randomListToJson, randomListJson, randomListToArray, _random_list_to_array) kept a seen set for termination but treated a revisit as the end of the list, so a ring was cut at its first repeated node and printed exactly as a correct copy. #405 fixed this for the ListNode serializers; the random list uses the separate Node type and its own serializers, which kept the old loop from the initial import. A judge case cannot catch it, because an expected value in JSON cannot describe a cycle.

C differed because json_random_list had no seen set, only a 10000-node buffer cap: on the ring it printed 10000 entries per non-empty case with random indices pointing at late repeats, and no error field, so the candidate saw a wrong answer without a reason.

This change reports a revisit as an error in all five serializers with the message #405 already uses, "Returned list must not reach a node twice.", and keeps the seen set so serialization still terminates. C gets the same Floyd check as json_list, run after the deep-copy walk, which is capped at 10000 nodes, so a ring of copies is walked to that cap before the check refuses it. Correct copies and the empty case are unaffected.

The regression test compiles and runs the cyclic copy against the judge in C, C++ and Java and expects that message on every non-empty case; it fails on main and passes with this change. JavaScript and Python get the same source check #405 added for the plain list serializers.

The C serializer also printed its two existing refusals where the answer goes: a shallow copy's "Returned list must be a deep copy." became the actual value, and a stray random pointer's "Returned random pointer must stay inside the copied list." landed inside the array, so both failed with no reason. It now checks every random pointer before the opening [ and reports both through null,"error":, as the cycle check does, which lines C up with C++ and Java; the JavaScript and Python half of #364 stays with #372. json_graph has the same pattern and is left for a separate change.

Closes #417


Summary by cubic

Fixes the random-list serializers so a deep copy whose last node links back to the first is rejected instead of being accepted as a correct acyclic list.

  • The serializers in C, C++, Java, JavaScript, and Python now report Returned list must not reach a node twice. on a revisit, matching the existing plain-list behavior.
  • C also gets the same Floyd cycle check as the plain-list serializer, run before the buffer fills.
  • C now reports a shallow copy and a stray random pointer through the error field instead of embedding them in the answer; a shallow copy that also loops is refused as a shallow copy.
  • Regression tests compile and run a cyclic copy and the C error cases in C, C++, and Java and assert the error messages; JavaScript and Python get source-level checks. The compiled harness tests now share one compile-and-run helper.

Written for commit 7874eb5. Summary will update on new commits.

View guided diff

cubic-dev-ai[bot]

This comment was marked as resolved.

Comment thread web/compiler-explorer.js Outdated

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rebase latest main branch to pick up the CI fixes from #434.

@papaya0112
papaya0112 force-pushed the refuse-cyclic-random-list branch from 098e27f to aa17a99 Compare October 22, 2026 15:15
@papaya0112

Copy link
Copy Markdown
Contributor Author

Already rebased onto main.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove AI attribution from Git commit messages, as it does not help collaboration.

Comment thread web/compiler-explorer.js Outdated
Every random-list serializer stopped at the first revisited node, so a
deep copy whose last node links back to the first printed as the
acyclic list it loops over, and the exact checker accepted it in C++,
Java, JavaScript and Python. C walked the ring until its 10000-node
buffer filled and failed without saying why. Report the revisit with
the message the plain list serializers already use; the seen set stays
so serialization still terminates.
@papaya0112
papaya0112 force-pushed the refuse-cyclic-random-list branch from aa17a99 to 4ed1a15 Compare October 23, 2026 03:52
@papaya0112

Copy link
Copy Markdown
Contributor Author

I removed the AI attribution from the commit message.

@jserv

jserv commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

I removed the AI attribution from the commit message.

You don't have to leave messages like the above as Git always tracks changes.

@papaya0112
papaya0112 requested a review from jserv October 23, 2026 05:10
Comment thread web/compiler-explorer.js Outdated
Comment thread web/compiler-explorer.js Outdated
@papaya0112
papaya0112 force-pushed the refuse-cyclic-random-list branch from 43379d0 to 04d26aa Compare October 23, 2026 05:56
@jserv

jserv commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@papaya0112 Both points from the last review hold at 04d26aa: the cycle check runs after the isOriginalRandomNode walk, and C reports a shallow copy and a stray random pointer through null,"error": before the opening [. One sentence in the description is not true yet: C lines up "with the other four harnesses" for a stray random pointer only once #372 lands, because on main the JavaScript runner still maps a foreign random to -1 and the Python runner raises ValueError. Reword it to say C now matches C++ and Java, and that JavaScript and Python follow with #372 (Closes #364). Both pull requests edit the random-list serializers in web/runners.js, so whichever lands second rebases onto the other.

Comment thread web/runners.js
Comment thread web/runners.js
Comment thread web/compiler-explorer.js
Comment thread tests/browser/compiler-explorer.test.js Outdated
Comment thread tests/browser/runners.test.js
@papaya0112
papaya0112 force-pushed the refuse-cyclic-random-list branch from 04d26aa to 1f5ff3f Compare October 23, 2026 06:37
The C random-list serializer printed a shallow copy's refusal as the
answer itself and put a stray random pointer's refusal inside the
array, so neither case carried an error and C showed a wrong answer
with no reason, while C++ and Java throw both. Check every random
pointer before the opening bracket and report both refusals through
the error field, as the cycle check now does. The cycle check runs
after the deep-copy walk, so a shallow copy that also loops is refused
as a shallow copy, the same answer the other four give.
The cyclic-copy and stray-copy tests repeated the compile-and-run steps
of the flatten tests, with their own compiler flags and timeout. Give
that helper the judge id as a parameter so every harness test builds
and bounds its run in one place. The stray-copy comment also claimed
JavaScript and Python throw a stray random pointer, which they do not
until sysprog21#372 lands.
@papaya0112
papaya0112 force-pushed the refuse-cyclic-random-list branch from 1f5ff3f to 7874eb5 Compare October 23, 2026 06:44
@jserv

jserv commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

The sentence "JavaScript and Python follow once #372 lands, which closes #364" contains a closing keyword, so GitHub lists #364 among this PR's closing references, and merging this first would close #364 before the JavaScript and Python fix in #372 exists. Please reword it so only Closes #417 remains, for example "the JavaScript and Python half of #364 stays with #372".

@ColtenOuO ColtenOuO left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes of the code are looking good to me.

gino1203 pushed a commit to gino1203/codetrial that referenced this pull request Oct 23, 2026
A skipped gates lane passed as green, an approval survived the push
after it, and resolving an outdated thread raised a grade nobody had
earned, as sysprog21#430 showed. The sweep now grades those, names everyone a
PR waits on, and lists stacked prerequisites and PR pairs that change
the same base lines. The review of a low or blocked PR rechecks its
outdated threads, and its findings go out as one review, so the author
gets one notification instead of one per finding.
@papaya0112
papaya0112 requested a review from jserv October 23, 2026 11:07
@jserv
jserv merged commit 380062a into sysprog21:main Oct 23, 2026
10 checks passed
@jserv

jserv commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Thank @papaya0112 for contributing!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copy-with-random tests accept a copied list that loops back into itself

3 participants