Prevent segfault when applying cheats before a level has loaded (#161)

This commit is contained in:
jdgleaver 2021-11-05 14:12:05 +00:00 committed by GitHub
parent e8ebfe780f
commit ee17bf3632
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 409 additions and 11 deletions

View File

@ -0,0 +1,120 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rbuf.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_ARRAY_RBUF_H__
#define __LIBRETRO_SDK_ARRAY_RBUF_H__
/*
* This file implements stretchy buffers as invented (?) by Sean Barrett.
* Based on the implementation from the public domain Bitwise project
* by Per Vognsen - https://github.com/pervognsen/bitwise
*
* It's a super simple type safe dynamic array for C with no need
* to predeclare any type or anything.
* The first time an element is added, memory for 16 elements are allocated.
* Then every time length is about to exceed capacity, capacity is doubled.
*
* Be careful not to supply modifying statements to the macro arguments.
* Something like RBUF_REMOVE(buf, i--); would have unintended results.
*
* Sample usage:
*
* mytype_t* buf = NULL;
* RBUF_PUSH(buf, some_element);
* RBUF_PUSH(buf, other_element);
* -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
*
* -- Free allocated memory:
* RBUF_FREE(buf);
* -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0
*
* -- Explicitly increase allocated memory and set capacity:
* RBUF_FIT(buf, 100);
* -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100
*
* -- Resize buffer (does not initialize or zero memory!)
* RBUF_RESIZE(buf, 200);
* -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200
*
* -- To handle running out of memory:
* bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);
* -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
*/
#include <retro_math.h> /* for MAX */
#include <stdlib.h> /* for malloc, realloc */
#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)
#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)->len : 0)
#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)->cap : 0)
#define RBUF_END(b) ((b) + RBUF_LEN(b))
#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)
#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)
#define RBUF_FIT(b, n) ((size_t)(n) <= RBUF_CAP(b) ? 0 : (*(void**)(&(b)) = rbuf__grow((b), (n), sizeof(*(b)))))
#define RBUF_PUSH(b, val) (RBUF_FIT((b), 1 + RBUF_LEN(b)), (b)[RBUF__HDR(b)->len++] = (val))
#define RBUF_POP(b) (b)[--RBUF__HDR(b)->len]
#define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)->len = (sz) : 0))
#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0)
#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n)))
#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b)))
struct rbuf__hdr
{
size_t len;
size_t cap;
};
#ifdef __GNUC__
__attribute__((__unused__))
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) //unreferenced local function has been removed
#endif
static void *rbuf__grow(void *buf,
size_t new_len, size_t elem_size)
{
struct rbuf__hdr *new_hdr;
size_t new_cap = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));
size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;
if (buf)
{
new_hdr = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);
if (!new_hdr)
return buf; /* out of memory, return unchanged */
}
else
{
new_hdr = (struct rbuf__hdr *)malloc(new_size);
if (!new_hdr)
return NULL; /* out of memory */
new_hdr->len = 0;
}
new_hdr->cap = new_cap;
return new_hdr + 1;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif

View File

@ -0,0 +1,190 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_math.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_COMMON_MATH_H
#define _LIBRETRO_COMMON_MATH_H
#include <stdint.h>
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#include <limits.h>
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>
#ifndef M_PI
#if !defined(USE_MATH_DEFINES)
#define M_PI 3.14159265358979323846264338327
#endif
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/**
* next_pow2:
* @v : initial value
*
* Get next power of 2 value based on initial value.
*
* Returns: next power of 2 value (derived from @v).
**/
static INLINE uint32_t next_pow2(uint32_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
/**
* prev_pow2:
* @v : initial value
*
* Get previous power of 2 value based on initial value.
*
* Returns: previous power of 2 value (derived from @v).
**/
static INLINE uint32_t prev_pow2(uint32_t v)
{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v - (v >> 1);
}
/**
* clamp:
* @v : initial value
*
* Get the clamped value based on initial value.
*
* Returns: clamped value (derived from @v).
**/
static INLINE float clamp_value(float v, float min, float max)
{
return v <= min ? min : v >= max ? max : v;
}
/**
* saturate_value:
* @v : initial value
*
* Get the clamped 0.0-1.0 value based on initial value.
*
* Returns: clamped 0.0-1.0 value (derived from @v).
**/
static INLINE float saturate_value(float v)
{
return clamp_value(v, 0.0f, 1.0f);
}
/**
* dot_product:
* @a : left hand vector value
* @b : right hand vector value
*
* Get the dot product of the two passed in vectors.
*
* Returns: dot product value (derived from @a and @b).
**/
static INLINE float dot_product(const float* a, const float* b)
{
return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
}
/**
* convert_rgb_to_yxy:
* @rgb : in RGB colour space value
* @Yxy : out Yxy colour space value
*
* Convert from RGB colour space to Yxy colour space.
*
* Returns: Yxy colour space value (derived from @rgb).
**/
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
{
float inv;
float xyz[3];
float one[3] = {1.0, 1.0, 1.0};
float rgb_xyz[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750},
{0.0193339, 0.1191920, 0.9503041}
};
xyz[0] = dot_product(rgb_xyz[0], rgb);
xyz[1] = dot_product(rgb_xyz[1], rgb);
xyz[2] = dot_product(rgb_xyz[2], rgb);
inv = 1.0f / dot_product(xyz, one);
Yxy[0] = xyz[1];
Yxy[1] = xyz[0] * inv;
Yxy[2] = xyz[1] * inv;
}
/**
* convert_yxy_to_rgb:
* @rgb : in Yxy colour space value
* @Yxy : out rgb colour space value
*
* Convert from Yxy colour space to rgb colour space.
*
* Returns: rgb colour space value (derived from @Yxy).
**/
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
{
float xyz[3];
float xyz_rgb[3][3] = {
{3.2404542, -1.5371385, -0.4985314},
{-0.9692660, 1.8760108, 0.0415560},
{0.0556434, -0.2040259, 1.0572252}
};
xyz[0] = Yxy[0] * Yxy[1] / Yxy[2];
xyz[1] = Yxy[0];
xyz[2] = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
rgb[0] = dot_product(xyz_rgb[0], xyz);
rgb[1] = dot_product(xyz_rgb[1], xyz);
rgb[2] = dot_product(xyz_rgb[2], xyz);
}
#endif

View File

@ -10,6 +10,7 @@
#include <libretro.h>
#include <file/file_path.h>
#include <streams/file_stream.h>
#include <array/rbuf.h>
#if _MSC_VER
#include <compat/msvc.h>
@ -41,6 +42,7 @@
#include "../src/g_game.h"
#include "../src/wi_stuff.h"
#include "../src/p_tick.h"
#include "../src/z_zone.h"
/* Don't include file_stream_transforms.h but instead
just forward declare the prototype */
@ -55,13 +57,18 @@ int SCREENWIDTH = 320;
int SCREENHEIGHT = 200;
//i_video
static unsigned char *screen_buf;
static unsigned char *screen_buf = NULL;
/* libretro */
static char g_wad_dir[1024];
static char g_basename[1024];
static char g_save_dir[1024];
/* Cheat handling */
static bool cheats_enabled = false;
static bool cheats_pending = false;
static char **cheats_pending_list = NULL;
//forward decls
bool D_DoomMainSetup(void);
void D_DoomLoop(void);
@ -277,6 +284,8 @@ void retro_init(void)
enum retro_pixel_format rgb565;
struct retro_log_callback log;
Z_Init(); /* 1/18/98 killough: start up memory stuff first */
if(environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
else
@ -296,6 +305,24 @@ void retro_deinit(void)
{
D_DoomDeinit();
if (screen_buf)
free(screen_buf);
screen_buf = NULL;
cheats_enabled = false;
cheats_pending = false;
if (cheats_pending_list)
{
unsigned i;
for (i = 0; i < RBUF_LEN(cheats_pending_list); i++)
{
if (cheats_pending_list[i])
free(cheats_pending_list[i]);
cheats_pending_list[i] = NULL;
}
RBUF_FREE(cheats_pending_list);
}
libretro_supports_bitmasks = false;
retro_set_rumble_damage(0, 0.0f);
@ -307,6 +334,13 @@ void retro_deinit(void)
rumble_damage_counter = -1;
rumble_touch_strength = 0;
rumble_touch_counter = -1;
/* Z_Close() must be the very last
* function that is called, since
* z_zone.h overrides malloc()/free()/etc.
* (i.e. anything that calls free()
* after Z_Close() will likely segfault) */
Z_Close();
}
unsigned retro_api_version(void)
@ -561,6 +595,27 @@ void retro_run(void)
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
update_variables(false);
/* Check for pending cheats */
if (cheats_pending && (gamestate == GS_LEVEL) && !demoplayback)
{
unsigned i, j;
for (i = 0; i < RBUF_LEN(cheats_pending_list); i++)
{
const char *cheat_code = cheats_pending_list[i];
if (cheat_code)
{
for (j = 0; cheat_code[j] != '\0'; j++)
M_FindCheats(cheat_code[j]);
free(cheats_pending_list[i]);
cheats_pending_list[i] = NULL;
}
}
RBUF_FREE(cheats_pending_list);
cheats_pending = false;
}
if (quit_pressed)
{
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
@ -765,9 +820,6 @@ bool retro_load_game(const struct retro_game_info *info)
myargc = argc;
myargv = (const char **) argv;
if (!Z_Init()) /* 1/18/98 killough: start up memory stuff first */
goto failed;
/* cphipps - call to video specific startup code */
if (!I_PreInitGraphics())
goto failed;
@ -779,6 +831,10 @@ bool retro_load_game(const struct retro_game_info *info)
for (i = 0; i < 3; i++)
D_DoomLoop();
cheats_enabled = true;
cheats_pending = false;
cheats_pending_list = NULL;
return true;
failed:
@ -804,9 +860,6 @@ failed:
void retro_unload_game(void)
{
if (screen_buf)
free(screen_buf);
screen_buf = NULL;
}
unsigned retro_get_region(void)
@ -1020,11 +1073,43 @@ void retro_cheat_reset(void)
void retro_cheat_set(unsigned index, bool enabled, const char *code)
{
int i;
unsigned i;
(void)index;(void)enabled;
if(code)
for (i=0; code[i] != '\0'; i++)
if (!code || !cheats_enabled)
return;
/* Note: it is not currently possible to disable
* cheats once active... */
/* Check if cheat can be applied now */
if ((gamestate == GS_LEVEL) && !demoplayback)
{
for (i = 0; code[i] != '\0'; i++)
M_FindCheats(code[i]);
}
/* Current game state does not support cheat
* activation - add code to pending list */
else
{
bool code_found = false;
for (i = 0; i < RBUF_LEN(cheats_pending_list); i++)
{
const char *existing_code = cheats_pending_list[i];
if (existing_code && !strcmp(existing_code, code))
{
code_found = true;
break;
}
}
if (!code_found)
{
RBUF_PUSH(cheats_pending_list, strdup(code));
cheats_pending = true;
}
}
}
static action_lut_t left_analog_lut[] = {

View File

@ -1494,7 +1494,6 @@ void D_DoomDeinit(void)
V_DestroyUnusedTrueColorPalettes();
R_FlushAllPatches();
P_Deinit();
Z_Close();
}
//

View File

@ -112,6 +112,10 @@ void Z_Close(void)
bool Z_Init(void)
{
unsigned i;
for (i = 0; i < PU_MAX; i++)
blockbytag[i] = NULL;
return true;
}