Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crashes on start - malloc(): invalid next size (unsorted) #7496

Closed
heirecka opened this issue Apr 10, 2019 · 9 comments
Closed

Crashes on start - malloc(): invalid next size (unsorted) #7496

heirecka opened this issue Apr 10, 2019 · 9 comments

Comments

@heirecka
Copy link

heirecka commented Apr 10, 2019

Version of OpenTTD

1.9.1, but it also happens with 1.9.0
Compiled on Linux with gcc 8.3.0 and glibc 2.29

Expected result

openttd starts fine

Actual result

malloc(): invalid next size (unsorted)
Crash encountered, generating crash log...
malloc(): invalid next size (unsorted)
zsh: abort (core dumped) openttd

Steps to reproduce

$ openttd

Backtrace (without debug symbols):
#0  0x00007ffff73bb5df in raise () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#1  0x00007ffff73a6541 in abort () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#2  0x00007ffff73fdbc6 in __libc_message () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#3  0x00007ffff740445a in malloc_printerr () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#4  0x00007ffff7407194 in _int_malloc () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#5  0x00007ffff7409626 in calloc () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#6  0x000055555598c23d in stredup(char const*, char const*) ()
#7  0x00005555557c7f6f in DetermineBasePaths(char const*) ()
#8  0x00005555557c81fb in DeterminePaths(char const*) ()
#9  0x00005555558b0230 in openttd_main(int, char**) ()
#10 0x00007ffff73a7c03 in __libc_start_main () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#11 0x000055555570681e in _start ()
@nielsmh
Copy link
Contributor

nielsmh commented Apr 10, 2019

This looks strange, as far as I can tell there is no way for stredup() to attempt a zero byte allocation, since it always adds 1 to the input string length. The only other possibility I can think of would be some kind of buffer overrun causing it to attempt a far too large allocation (say multiple gigabytes).

There are multiple cases of stredup() in DetermineBasePaths(), do you think you can narrow it down?

OpenTTD/src/fileio.cpp

Lines 1053 to 1151 in b61ef7e

/**
* Determine the base (personal dir and game data dir) paths
* @param exe the path to the executable
*/
void DetermineBasePaths(const char *exe)
{
char tmp[MAX_PATH];
#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR)
const char *xdg_data_home = xdgDataHome(NULL);
seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", xdg_data_home,
PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR);
free(xdg_data_home);
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp);
#endif
#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) || !defined(WITH_PERSONAL_DIR)
_searchpaths[SP_PERSONAL_DIR] = NULL;
#else
#ifdef __HAIKU__
BPath path;
find_directory(B_USER_SETTINGS_DIRECTORY, &path);
const char *homedir = stredup(path.Path());
#else
/* getenv is highly unsafe; duplicate it as soon as possible,
* or at least before something else touches the environment
* variables in any way. It can also contain all kinds of
* unvalidated data we rather not want internally. */
const char *homedir = getenv("HOME");
if (homedir != NULL) {
homedir = stredup(homedir);
}
if (homedir == NULL) {
const struct passwd *pw = getpwuid(getuid());
homedir = (pw == NULL) ? NULL : stredup(pw->pw_dir);
}
#endif
if (homedir != NULL) {
ValidateString(homedir);
seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR);
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_PERSONAL_DIR] = stredup(tmp);
free(homedir);
} else {
_searchpaths[SP_PERSONAL_DIR] = NULL;
}
#endif
#if defined(WITH_SHARED_DIR)
seprintf(tmp, lastof(tmp), "%s", SHARED_DIR);
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_SHARED_DIR] = stredup(tmp);
#else
_searchpaths[SP_SHARED_DIR] = NULL;
#endif
#if defined(__MORPHOS__) || defined(__AMIGA__)
_searchpaths[SP_WORKING_DIR] = NULL;
#else
if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0';
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_WORKING_DIR] = stredup(tmp);
#endif
_do_scan_working_directory = DoScanWorkingDirectory();
/* Change the working directory to that one of the executable */
if (ChangeWorkingDirectoryToExecutable(exe)) {
if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0';
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_BINARY_DIR] = stredup(tmp);
} else {
_searchpaths[SP_BINARY_DIR] = NULL;
}
if (_searchpaths[SP_WORKING_DIR] != NULL) {
/* Go back to the current working directory. */
if (chdir(_searchpaths[SP_WORKING_DIR]) != 0) {
DEBUG(misc, 0, "Failed to return to working directory!");
}
}
#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2)
_searchpaths[SP_INSTALLATION_DIR] = NULL;
#else
seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR);
AppendPathSeparator(tmp, lastof(tmp));
_searchpaths[SP_INSTALLATION_DIR] = stredup(tmp);
#endif
#ifdef WITH_COCOA
extern void cocoaSetApplicationBundleDir();
cocoaSetApplicationBundleDir();
#else
_searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
#endif
}

@LordAro
Copy link
Member

LordAro commented Apr 10, 2019

(./configure --enable-debug=2 gets you debugging symbols)

@LordAro LordAro changed the title Crashes on start Crashes on start - malloc(): invalid next size (unsorted) Apr 10, 2019
@heirecka
Copy link
Author

heirecka commented Apr 10, 2019

The one in 1067 apparently

(gdb) bt
#0  0x00007ffff73bb5df in raise () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#1  0x00007ffff73a6541 in abort () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#2  0x00007ffff73fdbc6 in __libc_message () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#3  0x00007ffff740445a in malloc_printerr () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#4  0x00007ffff7407194 in _int_malloc () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#5  0x00007ffff7409626 in calloc () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#6  0x0000555555a84ef3 in CallocT<char> (num_elements=num_elements@entry=34)
    at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/core/alloc_func.hpp:87
#7  0x0000555555a850a5 in stredup (s=s@entry=0x7fffffffac00 "/home/heiko/.local/share/openttd/", last=last@entry=0x0)
    at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/string.cpp:141
#8  0x00005555558c34af in DetermineBasePaths (exe=0x7fffffffe408 "/usr/x86_64-pc-linux-gnu/bin/openttd")
    at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/fileio.cpp:1067
#9  0x00005555558c36e4 in DeterminePaths (exe=<optimized out>)
    at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/fileio.cpp:1164
#10 0x00005555559ad22c in openttd_main (argc=<optimized out>, argv=0x7fffffffe028)
    at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/openttd.cpp:703
#11 0x00007ffff73a7c03 in __libc_start_main () from /usr/x86_64-pc-linux-gnu/lib/libc.so.6
#12 0x0000555555816f9e in _start () at /var/tmp/paludis/build/games-simulation-openttd-1.9.1/work/openttd-1.9.1/src/fileio.cpp:1470

@JGRennison
Copy link
Contributor

JGRennison commented Apr 13, 2019

This sort of error suggests that heap corruption most likely took place before the point where the crash occurred.

CFLAGS="-fno-omit-frame-pointer -fsanitize=address -g" LDFLAGS="-fsanitize=address -g" ./configure
(all on one line)
may give you a clearer indication of where the problem is.
You may need to install libasan first.

@LordAro
Copy link
Member

LordAro commented Jan 2, 2020

@heirecka Have you been able to reproduce this? No one else has seen this particular crash since...

@Yexo
Copy link
Contributor

Yexo commented May 28, 2020

Closing for lack of updates. Feel free to reopen if you experience this bug again or have more information.

@Yexo Yexo closed this as completed May 28, 2020
@newHeiko
Copy link

newHeiko commented Jun 1, 2020

I seem to be having the same problem, with openttd 1.10.1 on Slackware Linux with glibc 2.30 and gcc 9.3.0.

Default output:

heiko@x220:~$ openttd
openttd: malloc.c:2379: sysmalloc: Assertion (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Crash encountered, generating crash log... openttd: malloc.c:2379: sysmalloc: Assertion (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted

Backtrace: (seems to point to a different point)

(gdb) bt
#0 0x00007ffff5358d6b in raise () from /lib64/libc.so.6
#1 0x00007ffff5339548 in abort () from /lib64/libc.so.6
#2 0x00007ffff53a7aa8 in __malloc_assert () from /lib64/libc.so.6
#3 0x00007ffff53aa0bf in sysmalloc () from /lib64/libc.so.6
#4 0x00007ffff53aaf13 in _int_malloc () from /lib64/libc.so.6
#5 0x00007ffff53ac7e4 in malloc () from /lib64/libc.so.6
#6 0x00007ffff5395119 in _IO_file_doallocate () from /lib64/libc.so.6
#7 0x00007ffff53a4760 in _IO_doallocbuf () from /lib64/libc.so.6
#8 0x00007ffff53a1e14 in __GI__IO_file_xsgetn () from /lib64/libc.so.6
#9 0x00007ffff539627f in fread () from /lib64/libc.so.6
#10 0x00000000008143f5 in TarScanner::AddFile(char const*, unsigned long, char const*) ()
#11 0x0000000000812768 in ?? ()
#12 0x0000000000813362 in FileScanner::Scan(char const*, Subdirectory, bool, bool) ()
#13 0x00000000008133b8 in FileScanner::Scan(char const*, Subdirectory, bool, bool) ()
#14 0x00000000008135c5 in TarScanner::DoScan(Subdirectory) ()
#15 0x00000000008136ed in TarScanner::DoScan(TarScanner::Mode) ()
#16 0x0000000000945fcf in openttd_main(int, char**) ()
#17 0x00007ffff533ae5b in __libc_start_main () from /lib64/libc.so.6
#18 0x000000000074e71a in _start ()

Output with address sanitizing: (points back to DetermineBasePaths)

==6870==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000006a78 at pc 0x7ff989ab881b bp 0x7ffe4b603c70 sp 0x7ffe4b603420
READ of size 25 at 0x603000006a78 thread T0
#0 0x7ff989ab881a (/usr/lib64/libasan.so.5+0x9881a)
#1 0x7ff989abb9c5 in __vsnprintf_chk (/usr/lib64/libasan.so.5+0x9b9c5)
#2 0x107419b in vseprintf(char*, char const*, char const*, __va_list_tag*) (/usr/games/openttd+0x107419b)
#3 0x10747e3 in seprintf(char*, char const*, char const*, ...) (/usr/games/openttd+0x10747e3)
#4 0xa772db in DetermineBasePaths(char const*) (/usr/games/openttd+0xa772db)
#5 0xa776aa in DeterminePaths(char const*) (/usr/games/openttd+0xa776aa)
#6 0xdb1edc in openttd_main(int, char**) (/usr/games/openttd+0xdb1edc)
#7 0x7ff986d8de5a in __libc_start_main (/lib64/libc.so.6+0x23e5a)
#8 0x840939 in _start (/usr/games/openttd+0x840939)

0x603000006a78 is located 0 bytes to the right of 24-byte region [0x603000006a60,0x603000006a78)
allocated by thread T0 here:
#0 0x7ff989b27628 in __interceptor_malloc (/usr/lib64/libasan.so.5+0x107628)
#1 0x7ff9893d093f (/usr/lib64/libxdg-basedir.so.1+0x193f)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib64/libasan.so.5+0x9881a)
Shadow bytes around the buggy address:
0x0c067fff8cf0: fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa 00 00
0x0c067fff8d00: 00 fa fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa
0x0c067fff8d10: 00 00 02 fa fa fa 00 00 02 fa fa fa 00 00 00 fa
0x0c067fff8d20: fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa 00 00
0x0c067fff8d30: 00 fa fa fa 00 00 02 fa fa fa 00 00 00 fa fa fa
=>0x0c067fff8d40: 00 00 04 fa fa fa 00 00 04 fa fa fa 00 00 00[fa]
0x0c067fff8d50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fff8d60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fff8d70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fff8d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fff8d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==6870==ABORTING

Hope this help,
Heiko

@LordAro LordAro reopened this Jun 1, 2020
@frosch123
Copy link
Member

@newHeiko @heirecka Please check whether your distributions have this fix for the unmaintained libxdg-basedir:
https://sources.debian.org/patches/libxdg-basedir/1.2.0-2/alloc_buffer.patch/

Possibly try compiling with ./configure --without-xdg-basedir

@newHeiko
Copy link

newHeiko commented Jun 1, 2020

Thanks, that did it (I'm actually the one maintaining libxdg-basedir for Slackware, so I'm doubly thankful for your note...)

Heiko

@LordAro LordAro closed this as completed Jun 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants