Fix U_IDLE asset error from cutscene item pointer aliasing
cutsceneCutsceneResolve and cutsceneSystemLoad could be called with a name/path pointer that aliases into CUTSCENE_SYSTEM.loadedItems (e.g. a CUTSCENE item's own name field). cutsceneLoadParse then overwrites that same buffer while loading the target cutscene, so the subsequent stringCopy into loadedFile read stale, corrupted memory. Copy the name/path into a local buffer before use in both functions.
This commit is contained in:
@@ -128,8 +128,19 @@ void cutsceneSystemInsertCutscene(const cutscene_t *cutscene) {
|
||||
void cutsceneSystemLoad(const char_t *file) {
|
||||
assertNotNull(file, "File cannot be NULL");
|
||||
|
||||
// Copy file out before it can be invalidated - every caller today
|
||||
// passes a string literal, but file could in principle point into
|
||||
// CUTSCENE_SYSTEM.loadedItems (a running item's own name field, if the
|
||||
// running cutscene is loadedScene), which both cutsceneLoadParse and
|
||||
// cutsceneSystemStartCutscene below overwrite/re-enter (see
|
||||
// cutsceneCutsceneResolve's matching comment for the exact bug this
|
||||
// guards against - initial.jsonc's closing CUTSCENE item into
|
||||
// main_menu.jsonc hit it there).
|
||||
char_t fileCopy[ASSET_FILE_NAME_MAX];
|
||||
stringCopy(fileCopy, file, ASSET_FILE_NAME_MAX - 1);
|
||||
|
||||
errorret_t result = cutsceneLoadParse(
|
||||
file, &CUTSCENE_SYSTEM.loadedScene, CUTSCENE_SYSTEM.loadedItems,
|
||||
fileCopy, &CUTSCENE_SYSTEM.loadedScene, CUTSCENE_SYSTEM.loadedItems,
|
||||
CUTSCENE_LOADED_ITEMS_MAX
|
||||
);
|
||||
if(errorIsNotOk(result)) {
|
||||
@@ -139,7 +150,7 @@ void cutsceneSystemLoad(const char_t *file) {
|
||||
}
|
||||
|
||||
cutsceneSystemStartCutscene(&CUTSCENE_SYSTEM.loadedScene);
|
||||
stringCopy(CUTSCENE_SYSTEM.loadedFile, file, ASSET_FILE_NAME_MAX - 1);
|
||||
stringCopy(CUTSCENE_SYSTEM.loadedFile, fileCopy, ASSET_FILE_NAME_MAX - 1);
|
||||
}
|
||||
|
||||
void cutsceneRestart(void) {
|
||||
|
||||
@@ -430,8 +430,19 @@ bool_t cutsceneCutsceneUpdate(
|
||||
}
|
||||
|
||||
cutscene_t * cutsceneCutsceneResolve(const char_t *name) {
|
||||
// Copy name out before it can be invalidated: this is commonly called
|
||||
// with a pointer into CUTSCENE_SYSTEM.loadedItems itself (a running
|
||||
// CUTSCENE/INSERT item's own cutsceneRef.name/insert.name field, when
|
||||
// the running cutscene IS loadedScene, e.g. initial.jsonc's closing
|
||||
// CUTSCENE item into main_menu.jsonc) - cutsceneLoadParse below parses
|
||||
// straight into that same shared loadedItems buffer, overwriting the
|
||||
// very memory name points into with the target cutscene's own first
|
||||
// item before this function is done reading name.
|
||||
char_t nameCopy[ASSET_FILE_NAME_MAX];
|
||||
stringCopy(nameCopy, name, ASSET_FILE_NAME_MAX - 1);
|
||||
|
||||
errorret_t result = cutsceneLoadParse(
|
||||
name, &CUTSCENE_SYSTEM.loadedScene, CUTSCENE_SYSTEM.loadedItems,
|
||||
nameCopy, &CUTSCENE_SYSTEM.loadedScene, CUTSCENE_SYSTEM.loadedItems,
|
||||
CUTSCENE_LOADED_ITEMS_MAX
|
||||
);
|
||||
if(errorIsNotOk(result)) {
|
||||
@@ -444,7 +455,7 @@ cutscene_t * cutsceneCutsceneResolve(const char_t *name) {
|
||||
// source the same way it does - cutsceneGoTo needs this to reload the
|
||||
// untouched original when jumping to a marker behind the current
|
||||
// position (see cutsceneGoTo's doc comment).
|
||||
stringCopy(CUTSCENE_SYSTEM.loadedFile, name, ASSET_FILE_NAME_MAX - 1);
|
||||
stringCopy(CUTSCENE_SYSTEM.loadedFile, nameCopy, ASSET_FILE_NAME_MAX - 1);
|
||||
|
||||
return &CUTSCENE_SYSTEM.loadedScene;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user