Relys / Project_CTR

Project CTR fork from Applestash last "Vandalized" version before it was taken down
17 stars 4 forks source link

Segmentation fault when using makerom (x64, Ubuntu 14.04) #1

Open chrisfu opened 9 years ago

chrisfu commented 9 years ago

Using head (currently 4fcc4665851c80036e56da5bff5346a788dd4fb5) and building from git, I'm seeing a segfault when trying to build a .cxi using makerom. Interestingly, using a Windows x64 build obtained from an alternate source via wine doesn't have this issue, but then again I can't be sure that it wasn't an earlier build (though it's tagged as makerom 0.13).

Recompiled with debugging symbols and run through gdb so that you can see the back-trace. I'm unsure if the same issue exists when building in Windows with mingw.

This happens consistently regardless of the extracted (and dependant on the source, decrypted) rom that I attempt to rebuild.

$ gdb --args bin/makerom -f cxi -o rom.cxi -rsf tmp/rsf/rom.rsf -target t -desc ecapp:5 -exheader tmp/ctrtool/exheader.bin.out -exefslogo -code tmp/exefs/code.bin -romfs tmp/ctrtool/romfs.bin.out -icon tmp/exefs/icon.bin -banner tmp/exefs/banner.bin
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bin/makerom...done.
(gdb) run
Starting program: /home/user/tmp/3ds/3ds2cia/bin/makerom -f cxi -o rom.cxi -rsf tmp/rsf/rom.rsf -target t -desc ecapp:5 -exheader tmp/ctrtool/exheader.bin.out -exefslogo -code tmp/exefs/code.bin -romfs tmp/ctrtool/romfs.bin.out -icon tmp/exefs/icon.bin -banner tmp/exefs/banner.bin

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff777c54d in _IO_new_fclose (fp=0x6a4140) at iofclose.c:57
57  iofclose.c: No such file or directory.
(gdb) bt
#0  0x00007ffff777c54d in _IO_new_fclose (fp=0x6a4140) at iofclose.c:57
#1  0x0000000000411d4f in FreeNcchSettings (set=0x6a3e60) at ncch.c:130
#2  0x0000000000411c6a in build_NCCH (usrset=0x7ffff7ecc010) at ncch.c:118
#3  0x00000000004019ef in main (argc=22, argv=0x7fffffffe3b8) at makerom.c:68
(gdb)

The line (and owning function) in question that appears to be causing the segfault in ncch.c is as follows:

void FreeNcchSettings(ncch_settings *set)
{
    if(set->componentFilePtrs.elf) fclose(set->componentFilePtrs.elf);
    if(set->componentFilePtrs.banner) fclose(set->componentFilePtrs.banner);
    if(set->componentFilePtrs.icon) fclose(set->componentFilePtrs.icon);
    if(set->componentFilePtrs.logo) fclose(set->componentFilePtrs.logo);
    if(set->componentFilePtrs.code) fclose(set->componentFilePtrs.code);
    if(set->componentFilePtrs.exhdr) fclose(set->componentFilePtrs.exhdr);
    if(set->componentFilePtrs.romfs) fclose(set->componentFilePtrs.romfs); # <---------
    if(set->componentFilePtrs.plainregion) fclose(set->componentFilePtrs.plainregion);

    if(set->exefsSections.code.size) free(set->exefsSections.code.buffer);
    if(set->exefsSections.banner.size) free(set->exefsSections.banner.buffer);
    if(set->exefsSections.icon.size) free(set->exefsSections.icon.buffer);

    if(set->sections.exhdr.size) free(set->sections.exhdr.buffer);
    if(set->sections.logo.size) free(set->sections.logo.buffer);
    if(set->sections.plainRegion.size) free(set->sections.plainRegion.buffer);
    if(set->sections.exeFs.size) free(set->sections.exeFs.buffer);

    memset(set,0,sizeof(ncch_settings));

    free(set);
}

I've suspected that memory could potentially be an issue, but considering I'm running 8GB of memory in my machine and that the makerom.exe (x64) build works fine via Wine, I'm guessing that memory limitations are not the cause here factoring in the overhead of Wine.

$ free -m
             total       used       free     shared    buffers     cached
Mem:          7871       4487       3384         13         41       2690
-/+ buffers/cache:       1754       6116
Swap:         4095        351       3744

Finally, here is the size of the decrypted romfs.bin I've been using in this case:

$ ls -lh tmp/ctrtool/romfs.bin.out 
-rw-rw-r-- 1 user user 1.7G Jan 20 11:17 tmp/ctrtool/romfs.bin.out

If any more information is required, drop me a message.

chrisfu commented 9 years ago

I appear to have fixed this by commenting out the ncch.c:130, which was the line I highlighted earlier. Performing a stack trace highlighted that the romfs.bin.out file had already been closed previously.

stat("tmp/ctrtool/romfs.bin.out", {st_mode=S_IFREG|0664, st_size=1750339584, ...}) = 0
open("tmp/ctrtool/romfs.bin.out", O_RDONLY) = 3
stat("tmp/exefs/banner.bin", {st_mode=S_IFREG|0664, st_size=123144, ...}) = 0
open("tmp/exefs/banner.bin", O_RDONLY)  = 4
stat("tmp/exefs/icon.bin", {st_mode=S_IFREG|0664, st_size=14016, ...}) = 0
open("tmp/exefs/icon.bin", O_RDONLY)    = 5
stat("tmp/exefs/code.bin", {st_mode=S_IFREG|0664, st_size=6037504, ...}) = 0
open("tmp/exefs/code.bin", O_RDONLY)    = 6
stat("tmp/ctrtool/exheader.bin.out", {st_mode=S_IFREG|0664, st_size=2048, ...}) = 0
open("tmp/ctrtool/exheader.bin.out", O_RDONLY) = 7
brk(0x1b09000)                          = 0x1b09000
...snip...
brk(0x1e5b000)                          = 0x1e5b000
fstat(3, {st_mode=S_IFREG|0664, st_size=1750339584, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa8d1bde000
lseek(3, 0, SEEK_SET)                   = 0
read(3, "IVFC\0\0\1\0@\3\0\0\0\0\0\0\0\0\0\0 \236\1\0\0\0\0\0\f\0\0\0"..., 4096) = 4096
mmap(NULL, 1753833472, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa867532000
lseek(3, 4096, SEEK_SET)                = 4096
read(3, "(\0\0\0(\0\0\0\224\3\0\0\274\3\0\0\4\36\0\0\300!\0\0\224x\0\0T\232\0\0"..., 1750335488) = 1750335488
close(3)                                = 0 # <---- tmp/ctrtool/romfs.bin.out being closed
munmap(0x7fa8d1bde000, 4096)            = 0
close(4)                                = 0 <---- tmp/exefs/banner.bin being closed
munmap(0x7fa8d1be2000, 4096)            = 0
close(5)                                = 0 <---- tmp/exefs/icon.bin being closed
munmap(0x7fa8d1be1000, 4096)            = 0
close(6)                                = 0 <---- tmp/exefs/code.bin being closed
munmap(0x7fa8d1be0000, 4096)            = 0
close(7)                                = 0 <---- tmp/ctrtool/exheader.bin.out being closed
munmap(0x7fa8d1bdf000, 4096)            = 0
# It's at this point where according to FreeNcchSettings function in ncch.c, it would again attempt to close romfs.bin.out
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x10} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

Unsure as to the impact of commenting out that line, but I can confirm that it doesn't appear to result in a memory leak of any sort. After some further testing, if I can confirm this to be stable I'll create a pull request.

Just out of curiosity, was anybody else suffering from the same issue?

mid-kid commented 9 years ago

Just out of curiosity, was anybody else suffering from the same issue? Same stuff over here, going to test out your fix.

mid-kid commented 9 years ago

And it worked perfectly, though skipping this kind of check can lead to memory leaks (Which get cleaned later by the kernel anyway, but it's still a bad practice to skip it).

chrisfu commented 9 years ago

It can indeed lead to memory leaks, but at least on Linux x86_64 architectures it doesn't appear to, based on the fact that the file is closed before the file closure on line 130.

The reason I've not submitted that as a pull request is that it's not a particularly viable fix for a cross-platform project, as it would likely lead to memory leaks on Windows and Mac platforms.

For what it's worth, the close appears to be occurring in https://github.com/Relys/Project_CTR/blob/4fcc4665851c80036e56da5bff5346a788dd4fb5/makerom/romfs.c on line 49.

AFAIK I'm aware they'll share the same file descriptor within /proc, being that they relate to the same file. Perhaps that works differently in Windows and MacOS, but I'd need confirmation on that.

One way or another, there'll be a way neater way of fixing it than commenting out ncch.c:130. :) I imagine just checking for either or both's existence should be enough to fix this particular bug (romfsBinary and/or componentFilePtrs.romfs).