forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

strings with twin characters

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PS2 Development
View previous topic :: View next topic  
Author Message
ragnarok2040



Joined: 09 Aug 2006
Posts: 230

PostPosted: Sun Aug 19, 2007 5:40 am    Post subject: strings with twin characters Reply with quote

I ran across a bug that kind of worries me, but I haven't been able to reproduce it in a test case. I wrote some browsing code for a larger project, for browsing directories. It had been working, but, all of a sudden, I was unable to use strcat() to append a "/" to a folder with twin characters at the end, e.g. 123466, FOLDRR. I'm not sure if the problem lies in the strcpy() of fio_dirent_t member "name" copying an invalid character at the end or if it's actually strcat()'s fault. Replacing strcat() with sprintf() fixed the problem I was having, though, so it makes me think the strcpy() is fine. I appended the code of what exactly happens when browsing directories. This code works though, so I commented the parts that were giving me the trouble. I used the same optimization flags as well, thinking it might have been an optimization error.

Code:

#include <stdio.h>
#include <string.h>
#include <libmc.h>
#include <sifrpc.h>
#include <sys/stat.h>
#include <loadfile.h>
#include <sbv_patches.h>

typedef struct {
    char nothing[32];
    int dircheck;
    char something[256];
} entries;

void LoadModules(void)
{
    int ret;

    ret = SifLoadModule("rom0:SIO2MAN", 0, NULL);
    if (ret < 0) {
        printf("Failed to load module: SIO2MAN");
    }

    ret = SifLoadModule("rom0:MCMAN", 0, NULL);
    if (ret < 0) {
        printf("Failed to load module: MCMAN");
    }

    ret = SifLoadModule("rom0:MCSERV", 0, NULL);
    if (ret < 0) {
        printf("Failed to load module: MCSERV");
    }
}

static inline char* strzncpy(char *d, char *s, int l) { d[0] = 0; return strncat(d, s, l); }

int main() {

    SifInitRpc(0);

    sbv_patch_enable_lmb();
    sbv_patch_disable_prefix_check();

    LoadModules();

    mcInit(MC_TYPE_MC);

    entries FileEntry[2048];
    char path[4096];

    strcpy(path,"mc0:/");   

    int i,dd;
     
    int n = 0;
    fio_dirent_t buf;

    dd = fioDopen(path);

    while(fioDread(dd,&buf)) { //list entries
        if((FIO_SO_ISDIR(buf.stat.mode)) && (!strcmp(buf.name,".") || !strcmp(buf.name,"..")))
            continue;
        if(FIO_SO_ISDIR(buf.stat.mode)) {
            FileEntry[n].dircheck = 1;
            strcpy(FileEntry[n].something,buf.name); //filename
            strzncpy(FileEntry[n].nothing,FileEntry[n].something,31); //displayname
            n++;
        }
        if(n>2046) break;
    }
    fioDclose(dd);

    for(i=0;i<(n-1);i++) {
        strcpy(path,"mc0:/");

        if(strchr(path,'/') == NULL)  {}; //used for checking if coming from device list in browser

        strcat(path,FileEntry[i].something); //folder "i" selected
        strcat(path,"/"); //append delimiter which wasn't working e.g. "mc0:/FOLDRR" would still be in path afterwards

        if(i>0) //append something else to it which wasn't working
            strcat(path,FileEntry[i-1].something);
        else
            strcat(path,FileEntry[i+1].something);

        strcat(path,"/");

        printf("%s\n",path);
    }

    return 0;
}


Makefile
Code:

# _____     ___ ____     ___ ____
#  ____|   |    ____|   |        | |____|
# |     ___|   |____ ___|    ____| |    \    PS2DEV Open Source Project.
#-----------------------------------------------------------------------
# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.
#
# $Id: Makefile.sample 1150 2005-06-12 11:42:08Z pixel $

EE_BIN = stringy.elf
EE_CFLAGS = -O3 -Winline -ffast-math -finline-functions -fstrict-aliasing -funsigned-char -fomit-frame-pointer -funroll-loops
EE_LIBS = -lmc -lpatches
EE_OBJS = stringy.o

all: $(EE_BIN)

clean:
   rm -f *.elf *.o

include $(PS2SDK)/samples/Makefile.pref
include $(PS2SDK)/samples/Makefile.eeglobal

Back to top
View user's profile Send private message
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sun Aug 19, 2007 9:15 am    Post subject: Reply with quote

Code:

typedef struct {
    char nothing[32];
    int dircheck;
    char something[256];
} entries;

int main() {
...
    entries FileEntry[2048];
...

That's nearly 600Kb of stack - is that OK?

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
ragnarok2040



Joined: 09 Aug 2006
Posts: 230

PostPosted: Sun Aug 19, 2007 9:51 am    Post subject: Reply with quote

It seems to be alright, someone was able to browse more than a thousand or so files on his usb drive with it like that without any problems. I'd originally had it defined as entries *FileEntry = (entries*)malloc(sizeof(entries)*2048); but changed it recently to that as a local variable since malloc wasn't having any trouble allocating the memory, but calling free(FileEntry) kept randomly crashing the program.

Two instances of the function is all that's called at any one time... maybe I should just define it globally so it doesn't take up more than a megabyte of memory... Thanks for the heads up :D.
Back to top
View user's profile Send private message
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sun Aug 19, 2007 10:07 am    Post subject: Reply with quote

The malloc is a much better idea. Just because malloc can allocate it doesn't mean there's enough room on the stack for the same sized object - you probably need to tell the linker or the C runtime startup that you need such a huge stack - I don't know what the default is on PS2SDK, but I bet it's more like 64Kb than 1Mb.
If your stack overflowed, it could easily cause the problem you are having.

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
ragnarok2040



Joined: 09 Aug 2006
Posts: 230

PostPosted: Sun Aug 19, 2007 3:41 pm    Post subject: Reply with quote

Looks like the stack size for ps2sdk is 128 Kb. I am overflowing the stack so I changed my code back, heh.

What I don't understand is why would it only affects double character ending strings only. It doesn't affect directories with 32 characters in the name or browsing multiple levels up or down. Compiling with -fstack-check didn't cause it to exit the program either. But I think that only works on Linux... and if not, I don't think I was browsing enough entries to overflow the stack, heh. Maybe that guy was using an older version :/.

Oh yeah, the bug still happens whether I'm malloc'ing FileEntry or relying on the stack.

I checked the disassembly and I think I came across something strange...
The first one is from the program using strcat with the bug and the second with sprintf().
Code:

error with strcat
 940:   3c040000    lui   a0,0x0
 944:   24840000    addiu   a0,a0,0
 948:   0c000000    jal   0 <RomBrowserInput>

working sprintf
 940:   3c060000    lui   a2,0x0
 944:   24c60000    addiu   a2,a2,0
 948:   00c0202d    move   a0,a2
 94c:   24e70024    addiu   a3,a3,36
 950:   268510c8    addiu   a1,s4,4296
 954:   0c000000    jal   0 <RomBrowserInput>


I think this is the output from a working strcat operation that does something similar...
Code:

  14:   3c030000    lui   v1,0x0
  18:   8c820008    lw   v0,8(a0)
  1c:   24650010    addiu   a1,v1,16
  20:   03a0202d    move   a0,sp
  24:   ffa70000    sd   a3,0(sp)
  28:   0c000000    jal   0 <main>


I don't know assembly at all, but 0x0 would probably be the null terminator and I think the rest would be modification of the strings...
Back to top
View user's profile Send private message
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Mon Aug 20, 2007 10:08 am    Post subject: Reply with quote

You can't tell anything from that.

You can easily check strcat. Right at the beginning of main() just do something like
Code:

char test[2048] = "FOLDRR";
strcat(test, "banana");

and then check the result. If it's wrong, strcat is wrong. If it's right, then something else you are doing is wrong.

Jim
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
ragnarok2040



Joined: 09 Aug 2006
Posts: 230

PostPosted: Mon Aug 20, 2007 5:08 pm    Post subject: Reply with quote

I did post in my first post that I couldn't reproduce it outside of the program. That last copy & paste of assembly was from a program just like the one you posted, except I used a string length of 256. You're right that the assembly code didn't say anything, heh. I'm not sure exactly what else I can be doing with strcpy and strcat that would make it go wrong only on specific strings with double character non-numeral endings, anyway.

The exact behavior of the bug with "1234MM" being the string inside the array of directory names is:

path[4096];

(output from my program is intermixed)
strcpy(path,"mc0:/");
path = mc0:/
strcat(path,"1234MM");
path = mc0:/1234MM
strcat(path,"/");
path = mc0:/1234MM
strcat(path,"filename.fil");
path = mc0:/1234MM
.. selected
there is a /
there is no /
strcpy(path,"path");
path = path

Edit:
It disappears if I use word, doubleword or quadword alignments (pretty much anything 16 bytes and over), so I'm guessing strcat tries to strcpy the second string to the first string at the wrong byte for some reason, maybe the byte after the null terminator... since I think if the position were earlier it would cut into the first string's characters or maybe the strcpy there is incrementing a spot prior to copying the string for some reason.

Edit2:
I am able to reproduce the exact behavior I'm getting by setting the first character of the src string to a null terminator prior to using strcat to append it to the dest string.

Edit3:
Having the dest string aligned to 16 bytes caused my program to start producing random crashes every once in a while when entering those specific directories...
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PS2 Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group