Fix missing fclose when resource is closed without being read. Fixes #1685.
PiperOrigin-RevId: 649416747 Change-Id: I05eeb1071868116b6e5be76e26b465788e4d35b1
This commit is contained in:
committed by
Copybara-Service
parent
a5a3c9efc7
commit
f8b944bf7f
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "engine/engine_resource.h"
|
#include "engine/engine_resource.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -41,7 +42,6 @@ static void* _fileToMemory(FILE* fp, const char* filename, size_t* filesize);
|
|||||||
|
|
||||||
// file buffer used internally for the OS filesystem
|
// file buffer used internally for the OS filesystem
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE* fp; // file handle
|
|
||||||
int is_read; // set to nonzero if buffer was read into
|
int is_read; // set to nonzero if buffer was read into
|
||||||
uint8_t* buffer; // raw bytes from file
|
uint8_t* buffer; // raw bytes from file
|
||||||
size_t nbuffer; // size of buffer in bytes
|
size_t nbuffer; // size of buffer in bytes
|
||||||
@@ -100,20 +100,16 @@ mjResource* mju_openResource(const char* name, char* error, size_t error_sz) {
|
|||||||
spec->is_read = 0;
|
spec->is_read = 0;
|
||||||
spec->buffer = NULL;
|
spec->buffer = NULL;
|
||||||
spec->nbuffer = 0;
|
spec->nbuffer = 0;
|
||||||
spec->fp = fopen(name, "rb");
|
|
||||||
if (!spec->fp) {
|
|
||||||
if (error) {
|
|
||||||
snprintf(error, error_sz,
|
|
||||||
"resource not found via provider or OS filesystem: '%s'", name);
|
|
||||||
}
|
|
||||||
mju_closeResource(resource);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
struct stat file_stat;
|
struct stat file_stat;
|
||||||
|
errno = 0;
|
||||||
if (stat(name, &file_stat) == 0) {
|
if (stat(name, &file_stat) == 0) {
|
||||||
memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t));
|
memcpy(&spec->mtime, &file_stat.st_mtime, sizeof(time_t));
|
||||||
} else {
|
} else {
|
||||||
memset(&spec->mtime, 0, sizeof(time_t));
|
if (error) {
|
||||||
|
snprintf(error, error_sz, "Error opening file '%s': %s", name, strerror(errno));
|
||||||
|
}
|
||||||
|
mju_closeResource(resource);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, sizeof(time_t));
|
mju_encodeBase64(resource->timestamp, (uint8_t*) &spec->mtime, sizeof(time_t));
|
||||||
return resource;
|
return resource;
|
||||||
@@ -157,17 +153,12 @@ int mju_readResource(mjResource* resource, const void** buffer) {
|
|||||||
return resource->provider->read(resource, buffer);
|
return resource->provider->read(resource, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if provider is NULL, then OS filesystem is used
|
// if provider is NULL, then OS filesystem is used
|
||||||
file_spec* spec = (file_spec*) resource->data;
|
file_spec* spec = (file_spec*) resource->data;
|
||||||
if (!spec->fp && !spec->is_read) {
|
|
||||||
mjERROR("internal error FILE pointer undefined"); // should not occur
|
|
||||||
}
|
|
||||||
|
|
||||||
// only read once from file
|
// only read once from file
|
||||||
if (!spec->is_read) {
|
if (!spec->is_read) {
|
||||||
spec->buffer = _fileToMemory(spec->fp, resource->name, &(spec->nbuffer));
|
spec->buffer = mju_fileToMemory(resource->name, &(spec->nbuffer));
|
||||||
spec->fp = NULL; // closed by _fileToMemory
|
|
||||||
spec->is_read = 1;
|
spec->is_read = 1;
|
||||||
}
|
}
|
||||||
*buffer = spec->buffer;
|
*buffer = spec->buffer;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ TEST_F(MjCMeshTest, LoadMSHWithVFS) {
|
|||||||
// should fallback to OS filesystem
|
// should fallback to OS filesystem
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ TEST_F(MjCMeshTest, LoadOBJWithVFS) {
|
|||||||
// should fallback to OS filesystem
|
// should fallback to OS filesystem
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ TEST_F(MjCMeshTest, LoadSTLWithVFS) {
|
|||||||
// should fallback to OS filesystem
|
// should fallback to OS filesystem
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ TEST_F(MjCMeshTest, LoadMSHWithContentType) {
|
|||||||
// should try opening the file (not found obviously)
|
// should try opening the file (not found obviously)
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ TEST_F(MjCMeshTest, LoadOBJWithContentType) {
|
|||||||
// should try opening the file (not found obviously)
|
// should try opening the file (not found obviously)
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ TEST_F(MjCMeshTest, LoadSTLWithContentType) {
|
|||||||
// should try opening the file (not found obviously)
|
// should try opening the file (not found obviously)
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ TEST_F(MjCMeshTest, LoadMSHWithContentTypeParam) {
|
|||||||
// should try opening the file (not found obviously)
|
// should try opening the file (not found obviously)
|
||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error, HasSubstr("resource not found via provider or OS"));
|
EXPECT_THAT(error, HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ TEST_F(VfsTest, HFieldPngWithVFS) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ TEST_F(VfsTest, HFieldCustomWithVFS) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ TEST_F(VfsTest, TexturePngWithVFS) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ TEST_F(VfsTest, TextureCustomWithVFS) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ TEST_F(ContentTypeTest, HFieldPngWithContentType) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ TEST_F(ContentTypeTest, HFieldCustomWithContentType) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ TEST_F(ContentTypeTest, TexturePngWithContentType) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ TEST_F(ContentTypeTest, TextureCustomWithContentType) {
|
|||||||
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
mjModel* model = LoadModelFromString(xml, error, error_sz, vfs.get());
|
||||||
EXPECT_THAT(model, IsNull());
|
EXPECT_THAT(model, IsNull());
|
||||||
EXPECT_THAT(error,
|
EXPECT_THAT(error,
|
||||||
HasSubstr("resource not found via provider or OS filesystem"));
|
HasSubstr("Error opening file"));
|
||||||
mj_deleteVFS(vfs.get());
|
mj_deleteVFS(vfs.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user