镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Fix out-of-bounds write in dou_dizhu when nobody wins the auction - #1602

Closed
codewithfourtix wants to merge 3 commits into
google-deepmind:masterfrom
codewithfourtix:fix/dou-dizhu-oob-when-auction-all-pass
Closed

codewithfourtix wants to merge 3 commits into
google-deepmind:masterfrom
codewithfourtix:fix/dou-dizhu-oob-when-auction-all-pass

Conversation

@codewithfourtix

Copy link
Copy Markdown
Contributor

If every player passes the auction no dizhu is chosen and dizhu_ stays kInvalidPlayer, but OriginalDeal() still does deal[dizhu_][cards_left_over_[i]]++, writing before the start of the array. ScoreUp() and WriteObservationTensor() already guard this case, this spot was missed.

It's reachable from ToString() on a terminal state — under -fsanitize=address,undefined that's a SEGV in FormatDeal() at dou_dizhu.cc:174, clean with the guard.

Also adds a regression test that plays out an all-pass auction and formats the terminal state. It crashes under sanitizers before the change, passes after.

Discussed in #1358. I couldn't reproduce that issue's segfault directly (macOS/py3.10 only), so I've left GamesWithKnownIssues() alone.

If every player passes during the auction no dizhu is chosen, so dizhu_
stays kInvalidPlayer. OriginalDeal() still gave the three left-over cards
to deal[dizhu_] and so wrote before the start of the array. ScoreUp() and
WriteObservationTensor() already guard the no-dizhu case; OriginalDeal()
did not.

deal is returned by value into FormatDeal()'s frame, so the stray writes
land on FormatDeal()'s own locals. Built with -fsanitize=address,undefined,
formatting a terminal all-pass state crashes:

  array:211:9: runtime error: addition of unsigned offset to 0x... overflowed
  SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior array:211:9
  ==1142==ERROR: AddressSanitizer: SEGV on unknown address
      google-deepmind#4 DouDizhuState::FormatDeal() dou_dizhu.cc:174:21
      google-deepmind#5 DouDizhuState::ToString() dou_dizhu.cc:85:20

The crash is inside ToString(), which is what apply_action_test_clone in
games_sim_test.py compares, so this may be the segfault reported in issue
 google-deepmind#1358 -- but that failure is non-deterministic and macOS-only, and I could
not reproduce it directly to confirm.

Adds a regression test that plays out an all-pass auction and formats the
terminal state. It crashes under sanitizers before this change and passes
after.
@lanctot

lanctot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Thanks, this is great!

Just a quick heads up that our GitHub Actions CI is currently broken and we'll have to import #1599 and update github (hopefully later today) before we can run tests, so once we do that I'll have to ask you to merge changes from master and push the merge, then I will trigger the tests.

@lanctot lanctot 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.

Two things:

  1. Can you remove dou_dizhu from the list returned by GamesWithKnownIssues in spiel.h ? (return an empty list: return {})
  2. Can you take dou_dizhu out of the exemptions list(s) in python/tests/games_sim_test.py

GamesWithKnownIssues() now returns an empty list and dou_dizhu is back in
the general simulation tests. 2000 random sims under
-fsanitize=address,undefined are clean with the OriginalDeal() guard in
place.
@codewithfourtix

Copy link
Copy Markdown
Contributor Author

@lanctot Done now GamesWithKnownIssues() returns {} and dou_dizhu is back in the sim tests, ran 2000 random sims under -fsanitize=address, undefined with the guard in, everything is clean. just ping me when #1599 is in and I'll merge master and push the merge.

@lanctot

lanctot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Great! Can you now pull changes from master and push the merge to this branch? It will fix the Github Actions CI. I will trigger tests after that.

@sylvesterkaczmarek sylvesterkaczmarek 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.

Rechecked the current head after the maintainer follow-up. Guarding the leftover-card assignment on a valid dizhu fixes the OOB without changing normal deals, and the all-pass terminal path now has sanitizer-shaped regression coverage. The requested known-issue and sim-test exemptions are also removed. Looks clean to me.

@jhtschultz jhtschultz added the imported This PR has been imported and awaiting internal review. Please avoid any more local changes, thanks! label Oct 19, 2026
jhtschultz pushed a commit that referenced this pull request Oct 20, 2026
--
b5108c0 by Ali Zulfiqar <codewithfourtix@gmail.com>:

Fix out-of-bounds write in dou_dizhu when nobody wins the auction

If every player passes during the auction no dizhu is chosen, so dizhu_
stays kInvalidPlayer. OriginalDeal() still gave the three left-over cards
to deal[dizhu_] and so wrote before the start of the array. ScoreUp() and
WriteObservationTensor() already guard the no-dizhu case; OriginalDeal()
did not.

deal is returned by value into FormatDeal()'s frame, so the stray writes
land on FormatDeal()'s own locals. Built with -fsanitize=address,undefined,
formatting a terminal all-pass state crashes:

  array:211:9: runtime error: addition of unsigned offset to 0x... overflowed
  SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior array:211:9
  ==1142==ERROR: AddressSanitizer: SEGV on unknown address
      #4 DouDizhuState::FormatDeal() dou_dizhu.cc:174:21
      #5 DouDizhuState::ToString() dou_dizhu.cc:85:20

The crash is inside ToString(), which is what apply_action_test_clone in
games_sim_test.py compares, so this may be the segfault reported in issue
 #1358 -- but that failure is non-deterministic and macOS-only, and I could
not reproduce it directly to confirm.

Adds a regression test that plays out an all-pass auction and formats the
terminal state. It crashes under sanitizers before this change and passes
after.

--
5c6ccf8 by Ali Zulfiqar <codewithfourtix@gmail.com>:

Remove dou_dizhu from the known-issues and sim-test exemption lists

GamesWithKnownIssues() now returns an empty list and dou_dizhu is back in
the general simulation tests. 2000 random sims under
-fsanitize=address,undefined are clean with the OriginalDeal() guard in
place.
COPYBARA_INTEGRATE_REVIEW=#1602 from codewithfourtix:fix/dou-dizhu-oob-when-auction-all-pass 0528c61
PiperOrigin-RevId: 1002639184
Change-Id: I45e2ab46054af4064c1d0f6b8674127940394f5a
@jhtschultz

Copy link
Copy Markdown
Member

Merged into master in 2a662b8

@jhtschultz jhtschultz closed this Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

imported This PR has been imported and awaiting internal review. Please avoid any more local changes, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants