Skip to content

Commit 01f256f

Browse files
author
Alex Smith
committed
Avoid integer overflow in the save diff encoder
This was producing corrupted saves sometimes.
1 parent 00ed89e commit 01f256f

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

libnethack/src/memfile.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/
2-
/* Last modified by Alex Smith, 2015-11-11 */
2+
/* Last modified by Alex Smith, 2017-06-28 */
33
/* Copyright (c) Daniel Thaler, 2011. */
44
/* NetHack may be freely redistributed. See license for details. */
55

@@ -472,7 +472,7 @@ mdiffcmd_width(const struct memfile *mf, struct mdiff_command_instance *mdci,
472472
static void
473473
mdiffwritecmd(struct memfile *mf, struct mdiff_command_instance *mdci)
474474
{
475-
int widenings, usedbits, usedbytes, i;
475+
int widenings, usedbits, usedbytes, splitbytes, i;
476476

477477
/* Count the number of widenings we need. */
478478
usedbytes = mdiffcmd_width(mf, mdci, &widenings);
@@ -490,15 +490,24 @@ mdiffwritecmd(struct memfile *mf, struct mdiff_command_instance *mdci)
490490
usedbits += mdiff_command_sizes[mdci->command].arg2;
491491
encoding |= mdci->arg2;
492492

493-
/* Add the encoding of arg1. */
493+
/* Add the encoding of arg1.
494+
495+
We have to be careful here: the MRU prefix + arg2 + arg1 might come to
496+
more than 8 bytes (e.g. in the case of an eof_crc32 command with a very
497+
large copy count). As such, we split the largest possible whole number
498+
of bytes off from the end of arg1. */
494499
usedbits = usedbytes * 8 - usedbits;
495-
encoding <<= usedbits;
500+
splitbytes = usedbits / 8;
501+
encoding <<= usedbits % 8;
496502
unsigned long long arg1_2c = mdci->arg1 & ((1ULL << usedbits) - 1);
497-
encoding |= arg1_2c;
503+
encoding |= arg1_2c >> (splitbytes * 8);
498504

499-
i = usedbytes;
505+
i = usedbytes - splitbytes;
500506
while (i--)
501507
mdiffwrite8(mf, encoding >> (i * 8));
508+
i = splitbytes;
509+
while (i--)
510+
mdiffwrite8(mf, arg1_2c >> (i * 8));
502511

503512
if (debuglog) {
504513
fprintf(debuglog, "%s %" PRIdLEAST64 " %" PRIuLEAST64 " (",

0 commit comments

Comments
 (0)