 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
robif
Joined: 15 Oct 2005 Posts: 6 Location: Maribor
|
Posted: Sun Oct 16, 2005 5:52 am Post subject: libc opendir freezes PSP |
|
|
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 |
|
 |
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Sun Oct 16, 2005 7:43 am Post subject: Re: libc opendir freezes PSP |
|
|
| 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 |
|
 |
robif
Joined: 15 Oct 2005 Posts: 6 Location: Maribor
|
Posted: Sun Oct 16, 2005 4:11 pm Post subject: Re: opendir example |
|
|
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 |
|
 |
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Sun Oct 16, 2005 5:19 pm Post subject: |
|
|
| 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 |
|
 |
robif
Joined: 15 Oct 2005 Posts: 6 Location: Maribor
|
Posted: Sun Oct 16, 2005 9:43 pm Post subject: |
|
|
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 |
|
 |
raf
Joined: 13 Oct 2005 Posts: 57
|
Posted: Thu Oct 20, 2005 3:10 am Post subject: |
|
|
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 |
|
 |
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Thu Oct 20, 2005 7:10 pm Post subject: |
|
|
| 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 |
|
 |
raf
Joined: 13 Oct 2005 Posts: 57
|
Posted: Fri Oct 21, 2005 2:46 pm Post subject: |
|
|
| 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 |
|
 |
|
|
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
|