diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-10-16 17:41:35 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-10-16 17:41:35 -0300 |
| commit | ec748fcb0a6913a814f106218e9fde3a73ffc014 (patch) | |
| tree | ba0355be86136353a49dd6271e3d757600dc813c | |
| parent | c196348717dfda116726145220e5d1311547980e (diff) | |
| download | lua-ec748fcb0a6913a814f106218e9fde3a73ffc014.tar.gz lua-ec748fcb0a6913a814f106218e9fde3a73ffc014.tar.bz2 lua-ec748fcb0a6913a814f106218e9fde3a73ffc014.zip | |
correct handling of opened files in presence of memory allocation
errors
| -rw-r--r-- | lauxlib.c | 40 | ||||
| -rw-r--r-- | liolib.c | 56 |
2 files changed, 53 insertions, 43 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lauxlib.c,v 1.86 2002/09/16 19:49:45 roberto Exp roberto $ | 2 | ** $Id: lauxlib.c,v 1.87 2002/10/04 14:31:40 roberto Exp roberto $ |
| 3 | ** Auxiliary functions for building Lua libraries | 3 | ** Auxiliary functions for building Lua libraries |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -345,38 +345,42 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { | |||
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | 347 | ||
| 348 | static int errfile (lua_State *L, const char *filename) { | 348 | static int errfile (lua_State *L, int fnameindex) { |
| 349 | if (filename == NULL) filename = "stdin"; | 349 | const char *filename = lua_tostring(L, fnameindex) + 1; |
| 350 | lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); | 350 | lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); |
| 351 | lua_remove(L, fnameindex); | ||
| 351 | return LUA_ERRFILE; | 352 | return LUA_ERRFILE; |
| 352 | } | 353 | } |
| 353 | 354 | ||
| 354 | 355 | ||
| 355 | LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { | 356 | LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { |
| 356 | LoadF lf; | 357 | LoadF lf; |
| 357 | int status; | 358 | int status, readstatus; |
| 358 | int c; | 359 | int c; |
| 359 | int old_top = lua_gettop(L); | 360 | int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ |
| 360 | lf.f = (filename == NULL) ? stdin : fopen(filename, "r"); | 361 | if (filename == NULL) { |
| 361 | if (lf.f == NULL) return errfile(L, filename); /* unable to open file */ | 362 | lua_pushliteral(L, "=stdin"); |
| 363 | lf.f = stdin; | ||
| 364 | } | ||
| 365 | else { | ||
| 366 | lua_pushfstring(L, "@%s", filename); | ||
| 367 | lf.f = fopen(filename, "r"); | ||
| 368 | } | ||
| 369 | if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ | ||
| 362 | c = ungetc(getc(lf.f), lf.f); | 370 | c = ungetc(getc(lf.f), lf.f); |
| 363 | if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ | 371 | if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ |
| 364 | fclose(lf.f); | 372 | fclose(lf.f); |
| 365 | lf.f = fopen(filename, "rb"); /* reopen in binary mode */ | 373 | lf.f = fopen(filename, "rb"); /* reopen in binary mode */ |
| 366 | if (lf.f == NULL) return errfile(L, filename); /* unable to reopen file */ | 374 | if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ |
| 367 | } | 375 | } |
| 368 | if (filename == NULL) | ||
| 369 | lua_pushliteral(L, "=stdin"); | ||
| 370 | else | ||
| 371 | lua_pushfstring(L, "@%s", filename); | ||
| 372 | status = lua_load(L, getF, &lf, lua_tostring(L, -1)); | 376 | status = lua_load(L, getF, &lf, lua_tostring(L, -1)); |
| 373 | lua_remove(L, old_top+1); /* remove filename from stack */ | 377 | readstatus = ferror(lf.f); |
| 374 | if (ferror(lf.f)) { | 378 | if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ |
| 375 | lua_settop(L, old_top); /* ignore results from `lua_load' */ | 379 | if (readstatus) { |
| 376 | return errfile(L, filename); | 380 | lua_settop(L, fnameindex); /* ignore results from `lua_load' */ |
| 381 | return errfile(L, fnameindex); | ||
| 377 | } | 382 | } |
| 378 | if (lf.f != stdin) | 383 | lua_remove(L, fnameindex); |
| 379 | fclose(lf.f); | ||
| 380 | return status; | 384 | return status; |
| 381 | } | 385 | } |
| 382 | 386 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: liolib.c,v 2.19 2002/09/19 20:12:47 roberto Exp roberto $ | 2 | ** $Id: liolib.c,v 2.20 2002/10/11 20:40:32 roberto Exp roberto $ |
| 3 | ** Standard I/O (and system) library | 3 | ** Standard I/O (and system) library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -68,18 +68,25 @@ static FILE *tofile (lua_State *L, int findex) { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | 70 | ||
| 71 | static void newfile (lua_State *L, FILE *f) { | 71 | /* |
| 72 | lua_boxpointer(L, f); | 72 | ** When creating file handles, always creates a `closed' file handle |
| 73 | ** before opening the actual file; so, if there is a memory error, the | ||
| 74 | ** file is not left opened. | ||
| 75 | */ | ||
| 76 | static FILE **newfile (lua_State *L) { | ||
| 77 | FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); | ||
| 78 | *pf = NULL; /* file handle is currently `closed' */ | ||
| 73 | lua_pushliteral(L, FILEHANDLE); | 79 | lua_pushliteral(L, FILEHANDLE); |
| 74 | lua_rawget(L, LUA_REGISTRYINDEX); | 80 | lua_rawget(L, LUA_REGISTRYINDEX); |
| 75 | lua_setmetatable(L, -2); | 81 | lua_setmetatable(L, -2); |
| 82 | return pf; | ||
| 76 | } | 83 | } |
| 77 | 84 | ||
| 78 | 85 | ||
| 79 | static void registerfile (lua_State *L, FILE *f, const char *name, | 86 | static void registerfile (lua_State *L, FILE *f, const char *name, |
| 80 | const char *impname) { | 87 | const char *impname) { |
| 81 | lua_pushstring(L, name); | 88 | lua_pushstring(L, name); |
| 82 | newfile(L, f); | 89 | *newfile(L) = f; |
| 83 | if (impname) { | 90 | if (impname) { |
| 84 | lua_pushstring(L, impname); | 91 | lua_pushstring(L, impname); |
| 85 | lua_pushvalue(L, -2); | 92 | lua_pushvalue(L, -2); |
| @@ -89,16 +96,6 @@ static void registerfile (lua_State *L, FILE *f, const char *name, | |||
| 89 | } | 96 | } |
| 90 | 97 | ||
| 91 | 98 | ||
| 92 | static int setnewfile (lua_State *L, FILE *f) { | ||
| 93 | if (f == NULL) | ||
| 94 | return pushresult(L, 0); | ||
| 95 | else { | ||
| 96 | newfile(L, f); | ||
| 97 | return 1; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | |||
| 102 | static int aux_close (lua_State *L) { | 99 | static int aux_close (lua_State *L) { |
| 103 | FILE *f = tofile(L, 1); | 100 | FILE *f = tofile(L, 1); |
| 104 | if (f == stdin || f == stdout || f == stderr) | 101 | if (f == stdin || f == stdout || f == stderr) |
| @@ -126,8 +123,11 @@ static int io_gc (lua_State *L) { | |||
| 126 | 123 | ||
| 127 | 124 | ||
| 128 | static int io_open (lua_State *L) { | 125 | static int io_open (lua_State *L) { |
| 129 | FILE *f = fopen(luaL_check_string(L, 1), luaL_opt_string(L, 2, "r")); | 126 | const char *filename = luaL_check_string(L, 1); |
| 130 | return setnewfile(L, f); | 127 | const char *mode = luaL_opt_string(L, 2, "r"); |
| 128 | FILE **pf = newfile(L); | ||
| 129 | *pf = fopen(filename, mode); | ||
| 130 | return (*pf == NULL) ? pushresult(L, 0) : 1; | ||
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | 133 | ||
| @@ -136,14 +136,19 @@ static int io_popen (lua_State *L) { | |||
| 136 | luaL_error(L, "`popen' not supported"); | 136 | luaL_error(L, "`popen' not supported"); |
| 137 | return 0; | 137 | return 0; |
| 138 | #else | 138 | #else |
| 139 | FILE *f = popen(luaL_check_string(L, 1), luaL_opt_string(L, 2, "r")); | 139 | const char *filename = luaL_check_string(L, 1); |
| 140 | return setnewfile(L, f); | 140 | const char *mode = luaL_opt_string(L, 2, "r"); |
| 141 | FILE **pf = newfile(L); | ||
| 142 | *pf = popen(filename, mode); | ||
| 143 | return (*pf == NULL) ? pushresult(L, 0) : 1; | ||
| 141 | #endif | 144 | #endif |
| 142 | } | 145 | } |
| 143 | 146 | ||
| 144 | 147 | ||
| 145 | static int io_tmpfile (lua_State *L) { | 148 | static int io_tmpfile (lua_State *L) { |
| 146 | return setnewfile(L, tmpfile()); | 149 | FILE **pf = newfile(L); |
| 150 | *pf = tmpfile(); | ||
| 151 | return (*pf == NULL) ? pushresult(L, 0) : 1; | ||
| 147 | } | 152 | } |
| 148 | 153 | ||
| 149 | 154 | ||
| @@ -168,9 +173,9 @@ static int g_iofile (lua_State *L, const char *name, const char *mode) { | |||
| 168 | const char *filename = lua_tostring(L, 1); | 173 | const char *filename = lua_tostring(L, 1); |
| 169 | lua_pushstring(L, name); | 174 | lua_pushstring(L, name); |
| 170 | if (filename) { | 175 | if (filename) { |
| 171 | FILE *f = fopen(filename, mode); | 176 | FILE **pf = newfile(L); |
| 172 | luaL_arg_check(L, f, 1, strerror(errno)); | 177 | *pf = fopen(filename, mode); |
| 173 | newfile(L, f); | 178 | luaL_arg_check(L, *pf, 1, strerror(errno)); |
| 174 | } | 179 | } |
| 175 | else { | 180 | else { |
| 176 | tofile(L, 1); /* check that it's a valid file handle */ | 181 | tofile(L, 1); /* check that it's a valid file handle */ |
| @@ -218,9 +223,10 @@ static int io_lines (lua_State *L) { | |||
| 218 | return f_lines(L); | 223 | return f_lines(L); |
| 219 | } | 224 | } |
| 220 | else { | 225 | else { |
| 221 | FILE *f = fopen(luaL_check_string(L, 1), "r"); | 226 | const char *filename = luaL_check_string(L, 1); |
| 222 | luaL_arg_check(L, f, 1, strerror(errno)); | 227 | FILE **pf = newfile(L); |
| 223 | newfile(L, f); | 228 | *pf = fopen(filename, "r"); |
| 229 | luaL_arg_check(L, *pf, 1, strerror(errno)); | ||
| 224 | aux_lines(L, lua_gettop(L), 1); | 230 | aux_lines(L, lua_gettop(L), 1); |
| 225 | return 1; | 231 | return 1; |
| 226 | } | 232 | } |
