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 

libc opendir freezes PSP

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



Joined: 15 Oct 2005
Posts: 6
Location: Maribor

PostPosted: Sun Oct 16, 2005 5:52 am    Post subject: libc opendir freezes PSP Reply with quote

It seems that memory that is allocated for DIR structure in opendir() should be
initialized to zero, as current implementation causes PSP to freeze.

Changing
Code:

      dirp = (DIR *)malloc(sizeof(DIR));


with
Code:

    dirp = (DIR *)calloc(sizeof(DIR), sizeof(char));

in opendir() prevented freezing up, so i suggest this change to libcglue.c in newlib.

Also readdir() is potential for memory leak, because it allocates new dirent structure for each
entry. Caller must release it explicitly and that is not what programs that use this function
do (traditionally this function returns pointer to static structure).

BR,
Robert
Back to top
View user's profile Send private message
jimparis



Joined: 10 Jun 2005
Posts: 1179
Location: Boston

PostPosted: Sun Oct 16, 2005 7:43 am    Post subject: Re: libc opendir freezes PSP Reply with quote

robif wrote:
It seems that memory that is allocated for DIR structure in opendir() should be
initialized to zero, as current implementation causes PSP to freeze.

Do you have an example? It's working fine here. The DIR structure only contains a single element anyway, which clearly gets set in the very next line, so I don't see what initializing it to zero could possibly do.

robif wrote:

Also readdir() is potential for memory leak, because it allocates new dirent structure for each
entry. Caller must release it explicitly and that is not what programs that use this function
do (traditionally this function returns pointer to static structure).


readdir()'s buffer may be overwritten only for the same directory stream, so a single static structure is no good. We probably need to allocate a buffer in struct DIR and use that.
Back to top
View user's profile Send private message
robif



Joined: 15 Oct 2005
Posts: 6
Location: Maribor

PostPosted: Sun Oct 16, 2005 4:11 pm    Post subject: Re: opendir example Reply with quote

Example where call to opendir froze was this function:

Code:

static PyObject* PyPSP_listdir(PyObject *self,
                               PyObject *args)
{
    char *path;
    DIR* dirp;
    struct dirent* ent;
    PyObject* ret;

    if (!PyArg_ParseTuple(args, "s:listdir", &path))
       return NULL;

    dirp = opendir(path);
    if (!dirp) {
        PyErr_Format(PyExc_OSError, "Can't open directory %s",  path);
        return NULL;
    }
    ret = PyList_New(0);
    while(1)
    {
        ent = readdir(dirp);
        if (!ent)
        {
            break;
        }
        PyList_Append(ret, PyString_FromString(ent -> d_name));
        free(ent);
    }
    if (closedir(dirp) < 0) {
        Py_DECREF(ret);
        ret = NULL;
        PyErr_SetFromErrno(PyExc_OSError);
        return NULL;
    }
    return ret;
}


when i replaced malloc with calloc within opendir and readdir, it worked. This was on EU psp.
Of course it might be some other problem as it is called from within interpreter that does
other things...

Idea of storing ptr to dirent or dirent itself in DIR looks good, much better than static
struct.
Back to top
View user's profile Send private message
jimparis



Joined: 10 Jun 2005
Posts: 1179
Location: Boston

PostPosted: Sun Oct 16, 2005 5:19 pm    Post subject: Reply with quote

I still say that there's no possible difference between calloc() and malloc() because the only variable in the DIR structure gets overwritten immediately anyway. If you can provide a small compilable example I'll check it out, but I suspect your problem is hidden elsewhere and is just being triggered by the slightly different call stack.
Back to top
View user's profile Send private message
robif



Joined: 15 Oct 2005
Posts: 6
Location: Maribor

PostPosted: Sun Oct 16, 2005 9:43 pm    Post subject: Reply with quote

It seems, you have been right.
I have created this sample:

Code:

/*
 * PSP Software Development Kit - http://www.pspdev.org
 * -----------------------------------------------------------------------
 * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
 *
 * main.c - Sample to desmonstrate use of opendir/readdir
 *
 * Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
 *
 * $Id: main.c 1095 2005-09-27 21:02:16Z jim $
 */
#include <pspkernel.h>
#include <pspdebug.h>
#include <stdio.h>
#include <string.h>
#include <pspmoduleinfo.h>
#include <dirent.h>

/* Define the module info section */
PSP_MODULE_INFO("Opendir Sample", 0, 1, 0);

/* Define printf, just to make typing easier */
#define printf  pspDebugScreenPrintf

/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
    sceKernelExitGame();

        return 0;
}

/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
    int cbid;
    cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
    sceKernelRegisterExitCallback(cbid);
    sceKernelSleepThreadCB();

        return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
    int thid = 0;
    thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, T
HREAD_ATTR_USER, 0);
    if (thid >= 0)
        sceKernelStartThread(thid, 0, 0);
    return thid;
}

void listdir(const char* path)
{
    DIR* dirp;
    struct dirent* en;
    dirp = opendir(path);
    if (!dirp) {
        printf("Opendir returned NULL, bailing out\n");
        return;
    }
    while(1) {
        en = readdir(dirp);
        if (!en) {
            break;
        }
        printf("Entry: %s\n", en -> d_name);
    }
    printf("Done\n");
}

/* main routine */
int main(int argc, char *argv[])
{
    const char* path = "ms0:/";
   
    //init screen and callbacks
    pspDebugScreenInit();
    pspDebugScreenClear();
   
    SetupCallbacks();

    pspDebugScreenSetXY(0, 0);
    printf("Opendir Sample v1.0 \n\n");
   
    printf("Here we go, list of %s\n", path);
    listdir(path);

    sceKernelSleepThread();
    sceKernelExitGame();

    return 0;
}


and Makefile.sample:
Code:

PSPSDK = $(shell psp-config --pspsdk-path)
PSPLIBSDIR = $(PSPSDK)/..
TARGET = opendsample
OBJS = main.o
LIBS =
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE= Opendir Sample


CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

include $(PSPSDK)/lib/build.mak


There is no problem running this with current version of opendir. There must be some other
problem within Python itself. This thread can be closed.
Back to top
View user's profile Send private message
raf



Joined: 13 Oct 2005
Posts: 57

PostPosted: Thu Oct 20, 2005 3:10 am    Post subject: Reply with quote

Jim,

I also experienced problems when accessing a directory using the native sceIoDread calls. I found the solution in this forum, topic:
http://forums.ps2dev.org/viewtopic.php?t=2623

Quote:

From mrbrown:
Actually, you have to memset() the dirent before calling sceIoDread(). Then it works on stack or global.


So maybe readdir() needs to memset dirent also before calling sceIoDread?

Must be that sceIoDread() tries to free buffers defined in the dirent? I also remember someone saying that sceIoDread() allocates memory and that the user is supposed to free it.. (unusual behaviour, if true, but it may explain the crashes when dirent is not initialized, if Dread tries to free...).

Raf.
Back to top
View user's profile Send private message
jimparis



Joined: 10 Jun 2005
Posts: 1179
Location: Boston

PostPosted: Thu Oct 20, 2005 7:10 pm    Post subject: Reply with quote

OK, rev 1172 has these changes (move dirent inside DIR, zero dirent before calling sceIoDread). Don't free the dirent returned by readdir() anymore. Let me know if it gives you any trouble.
Back to top
View user's profile Send private message
raf



Joined: 13 Oct 2005
Posts: 57

PostPosted: Fri Oct 21, 2005 2:46 pm    Post subject: Reply with quote

jimparis wrote:
OK, rev 1172 has these changes (move dirent inside DIR, zero dirent before calling sceIoDread). Don't free the dirent returned by readdir() anymore. Let me know if it gives you any trouble.


Good deal; thanks Jim.

Raf.
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 -> PSP 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