Fixed many bugs pointed out by cppcheck

This commit is contained in:
MysterD 2022-03-01 20:32:33 -08:00
parent 887d033804
commit d51c82e235
28 changed files with 140 additions and 107 deletions

19
developer/compile.sh Normal file → Executable file
View file

@ -1,5 +1,16 @@
#!/bin/bash
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run' -ex 'quit'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j && ./build/us_pc/sm64.us.f3dex2e.exe --server 27015 --configfile sm64config_server.txt
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j && ./build/us_pc/sm64.us.f3dex2e.exe
set -e
if [ $# -eq 0 ]; then
make DEBUG=1 DEVELOPMENT=1 STRICT=1 -j
else
make DEBUG=1 DEVELOPMENT=1 -j
fi
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
fi
$FILE &

13
developer/cpp-check.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
if [ $# -eq 0 ]; then
EXTRA=""
else
EXTRA="--enable=all --suppress=constStatement --suppress=duplicateCondition --suppress=redundantAssignment --suppress=variableScope --suppress=unusedVariable --suppress=unreadVariable"
fi
INCLUDES="-Iinclude -Isrc -I. -Ilib/lua/include"
DEFINES="-DRAPI_GL=1 -DWAPI_SDL2=1 -DAAPI_SDL2=1 -DCAPI_SDL2=1 -DHAVE_SDL2=1 -DVERSION_US -D_LANGUAGE_C -DNIGHTLY -DNON_MATCHING -DAVOID_UB -DF3DEX_GBI_2E -DCOOP -DIMMEDIATELOAD -DBETTERCAMERA -DNODRAWINGDISTANCE -DDISCORD_SDK -DTEXTURE_FIX -DEXT_OPTIONS_MENU"
PARAMS="--language=c --quiet --platform=unix64 -v src -j8"
cppcheck -DLLONG_MAX $INCLUDES $DEFINES $EXTRA $PARAMS

19
developer/debug.sh Normal file → Executable file
View file

@ -1,3 +1,18 @@
#!/bin/bash
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt'
set -e
if [ $# -eq 0 ]; then
make DEBUG=1 DEVELOPMENT=1 STRICT=1 -j
else
make DEBUG=1 DEVELOPMENT=1 -j
fi
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
WINPTY=winpty
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
WINPTY=
fi
$WINPTY cgdb $FILE -ex 'break debug_breakpoint_here'

View file

@ -1,23 +0,0 @@
#!/bin/bash
set -e
if [ $# -eq 0 ]; then
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j
else
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 -j
fi
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
fi
# no debug, discord
$FILE --discord 2 --configfile sm64config_server.txt &
$FILE --discord 1 --configfile sm64config_client.txt &
exit
#debug discord client
$FILE --discord 2 --configfile sm64config_server.txt &
winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'r --discord 1 --configfile sm64config_client.txt'

12
developer/dummy.sh Normal file → Executable file
View file

@ -1,2 +1,12 @@
#!/bin/bash
make RENDER_API=DUMMY AUDIO_API=DUMMY CONTROLLER_API= DEBUG=1 DEVELOPMENT=1 STRICT=1 -j && ./build/us_pc/sm64.us.f3dex2e.exe --server 7777 --savepath ./build/us_pc/
set -e
make RENDER_API=DUMMY AUDIO_API=DUMMY CONTOLLER_API= -j
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
fi
$FILE --server 7777 --savepath ./build/us_pc/

2
developer/dx.sh Normal file → Executable file
View file

@ -1 +1 @@
make RENDER_API=D3D11 WINDOW_API=DXGI BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 && ./build/us_pc/sm64.us.f3dex2e.exe
make RENDER_API=D3D11 WINDOW_API=DXGI DEBUG=1 DEVELOPMENT=1 && ./build/us_pc/sm64.us.f3dex2e.exe

1
developer/flags.sh Normal file → Executable file
View file

@ -13,6 +13,7 @@ function compiler_no_discord() {
mv ./build ./build_no_discord
}
compiler DUMMY DUMMY DUMMY "" 64 dummy_64
compiler GL_LEGACY SDL1 SDL1 SDL1 64 legacy_1
#compiler GL SDL1 SDL1 SDL1 64 gl_1
#compiler D3D11 DXGI SDL1 SDL1 64 d3d11_1

37
developer/network.sh Normal file → Executable file
View file

@ -1,42 +1,37 @@
#!/bin/bash
set -e
if [ $# -eq 0 ]; then
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 -j
make DEBUG=1 DEVELOPMENT=1 STRICT=1 -j
else
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 -j
make DEBUG=1 DEVELOPMENT=1 -j
fi
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
WINPTY=winpty
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
WINPTY=
fi
# no debug, discord
#$FILE --discord 2 --configfile sm64config_server.txt &
#$FILE --discord 1 --configfile sm64config_client.txt &
#exit
# no debug, direct
$FILE --server 27015 --configfile sm64config_server.txt &
sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
exit
# debug on server
#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & > /dev/null
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
# no debug, discord
#$FILE --discord 2 --configfile sm64config_server.txt &
#$FILE --discord 1 --configfile sm64config_client.txt &
#exit
###################
# debug on client #
###################
# debug on server
#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt & > /dev/null
#$WINPTY cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
#exit
$FILE --server 27015 --configfile sm64config_server.txt &
# debug if cgdb exists
if ! [ -x "$(command -v cgdb)" ]; then
$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
else
winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_client.txt' -ex 'quit'
fi
# debug on client
$FILE --server 27015 --configfile sm64config_server.txt & > /dev/null
$WINPTY cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_client.txt' -ex 'quit'
exit

4
developer/proto-4.sh Normal file → Executable file
View file

@ -19,7 +19,3 @@ sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_p3.txt &
sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_p4.txt &
#sleep 2
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_p1.txt' -ex 'quit'
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_p4.txt' -ex 'quit'

4
developer/proto-8.sh Normal file → Executable file
View file

@ -27,7 +27,3 @@ sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_p7.txt &
sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_p8.txt &
#sleep 2
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_p1.txt' -ex 'quit'
#winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client 127.0.0.1 27015 --configfile sm64config_p4.txt' -ex 'quit'

14
developer/sdl1.sh Normal file → Executable file
View file

@ -1 +1,13 @@
make RENDER_API=GL WINDOW_API=SDL1 AUDIO_API=SDL1 CONTROLLER_API=SDL1 BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 && ./build/us_pc/sm64.us.f3dex2e.exe
#!/bin/bash
set -e
make RENDER_API=GL WINDOW_API=SDL1 AUDIO_API=SDL1 CONTROLLER_API=SDL1 DEBUG=1 DEVELOPMENT=1 -j
# find file
FILE=./build/us_pc/sm64.us.f3dex2e.exe
if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64.us.f3dex2e
fi
$FILE &

0
developer/static-analysis.sh Normal file → Executable file
View file

View file

@ -206,7 +206,7 @@ void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *arg3) {
uintptr_t dmaDevAddr;
u32 transfer;
u32 i;
u32 dmaIndex;
u32 dmaIndex = 0;
ssize_t bufferPos;
UNUSED u32 pad;
@ -518,8 +518,7 @@ void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32
}
}
//! Doesn't affect EU, but required for US/JP
temp = &*mem;
temp = mem;
#ifndef VERSION_EU
if (numInstruments >= 1)
#endif
@ -921,7 +920,7 @@ void audio_init() {
UNUSED s8 pad[16];
#else
UNUSED s8 pad[32];
u8 buf[0x10];
u8 buf[0x10] = { 0 };
#endif
s32 i, UNUSED j, UNUSED k;
UNUSED s32 lim1; // lim1 unused in EU
@ -957,8 +956,6 @@ void audio_init() {
D_EU_802298D0 = 20.03042f;
gRefreshRate = 50;
port_eu_init();
if (k) {
}
#endif
#ifdef TARGET_N64

View file

@ -78,12 +78,11 @@ void bowling_ball_set_waypoints(void) {
void bhv_bowling_ball_roll_loop(void) {
s16 collisionFlags;
s32 sp18;
s32 sp18 = 0;
bowling_ball_set_waypoints();
collisionFlags = object_step();
//! Uninitialzed parameter, but the parameter is unused in the called function
sp18 = cur_obj_follow_path(sp18);
o->oBowlingBallTargetYaw = o->oPathedTargetYaw;
@ -108,11 +107,10 @@ void bhv_bowling_ball_roll_loop(void) {
}
void bhv_bowling_ball_initializeLoop(void) {
s32 sp1c;
s32 sp1c = 0;
bowling_ball_set_waypoints();
//! Uninitialzed parameter, but the parameter is unused in the called function
sp1c = cur_obj_follow_path(sp1c);
o->oMoveAngleYaw = o->oPathedTargetYaw;

View file

@ -114,8 +114,8 @@ static void camera_lakitu_intro_act_show_dialog(void) {
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player);
s16 targetMovePitch;
s16 targetMoveYaw;
s16 targetMovePitch = 0;
s16 targetMoveYaw = 0;
cur_obj_play_sound_1(SOUND_AIR_LAKITU_FLY);

View file

@ -83,7 +83,7 @@ s32 approach_forward_vel(f32 *arr, f32 spC, f32 sp10) {
void chuckya_act_0(void) {
struct Object* player = nearest_player_to_object(o);
int angleToPlayer = obj_angle_to_object(o, player);
s32 sp3C;
s32 sp3C = 0;
UNUSED u8 pad[16];
s32 sp28;
if (o->oTimer == 0)

View file

@ -29,8 +29,8 @@ void dorrie_raise_head(void) {
void dorrie_act_move(void) {
s16 startYaw;
s16 targetYaw;
s16 targetSpeed;
s16 targetYaw = 0;
s16 targetSpeed = 0;
s16 circularTurn;
startYaw = o->oMoveAngleYaw;

View file

@ -46,7 +46,7 @@ void bhv_manta_ray_init(void) {
void manta_ray_move(void) {
s16 sp1E;
s32 sp18;
s32 sp18 = 0;
sp1E = o->header.gfx.animInfo.animFrame;
gCurrentObject->oPathedStartWaypoint = (struct Waypoint *) sMantaRayTraj;

View file

@ -133,7 +133,7 @@ void bhv_mips_act_wait_for_nearby_mario(void) {
*/
void bhv_mips_act_follow_path(void) {
s16 collisionFlags = 0;
s32 followStatus;
s32 followStatus = 0;
struct Waypoint **pathBase;
struct Waypoint *waypoint;

View file

@ -59,7 +59,7 @@ void snowmans_bottom_act_1(void) {
int angleToPlayer = obj_angle_to_object(o, player);
UNUSED s16 sp26;
s32 sp20;
s32 sp20 = 0;
UNUSED s16 sp1E;
o->oPathedStartWaypoint = segmented_to_virtual(&ccm_seg7_trajectory_snowman);

View file

@ -148,7 +148,7 @@ struct Object* spawn_default_star(f32 x, f32 y, f32 z) {
return NULL;
}
struct Object *star;
struct Object *star = NULL;
star = spawn_star(star, x, y, z);
star->oBehParams2ndByte = 0;
network_send_spawn_star(star, 0, x, y, z, behParams);
@ -163,7 +163,7 @@ struct Object* spawn_red_coin_cutscene_star(f32 x, f32 y, f32 z) {
return NULL;
}
struct Object * star;
struct Object * star = NULL;
star = spawn_star(star, x, y, z);
star->oBehParams2ndByte = 1;
network_send_spawn_star(star, 1, x, y, z, behParams);
@ -178,7 +178,7 @@ struct Object* spawn_no_exit_star(f32 x, f32 y, f32 z) {
return NULL;
}
struct Object * star;
struct Object * star = NULL;
star = spawn_star(star, x, y, z);
star->oBehParams2ndByte = 1;
star->oInteractionSubtype |= INT_SUBTYPE_NO_EXIT;

View file

@ -303,12 +303,12 @@ s16 sLakituPitch;
*/
f32 sZoomAmount;
s16 sCSideButtonYaw;
s16 sCSideButtonYaw = 0;
/**
* Sound timer used to space out sounds in behind Mario mode
*/
s16 sBehindMarioSoundTimer;
s16 sBehindMarioSoundTimer = 0;
/**
* Virtually unused aside being set to 0 and compared with gCameraZoomDist (which is never < 0)
@ -322,7 +322,7 @@ s16 sCUpCameraPitch;
/**
* The current mode's yaw, which gets added to the camera's yaw.
*/
s16 sModeOffsetYaw;
s16 sModeOffsetYaw = 0;
/**
* Stores Mario's yaw around the stairs, relative to the camera's position.
@ -355,7 +355,7 @@ f32 sCannonYOffset;
* ones have multiple uses.
* Check the cutscene_start functions for documentation on the cvars used by a specific cutscene.
*/
struct CutsceneVariable sCutsceneVars[10];
struct CutsceneVariable sCutsceneVars[10] = { 0 };
struct ModeTransitionInfo sModeInfo;
/**
* Offset added to sFixedModeBasePosition when Mario is inside, near the castle lobby entrance
@ -1729,7 +1729,7 @@ void mode_boss_fight_camera(struct Camera *c) {
* @see update_parallel_tracking_camera
*/
void mode_parallel_tracking_camera(struct Camera *c) {
s16 dummy;
s16 dummy = 0;
radial_camera_input(c, 0.f);
set_fov_function(CAM_FOV_DEFAULT);
@ -1764,7 +1764,7 @@ s32 update_behind_mario_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
f32 dist;
UNUSED u8 unused3[4];
s16 absPitch;
s16 pitch;
s16 pitch = 0;
s16 yaw;
s16 goalPitch = -sMarioCamState->faceAngle[0];
s16 marioYaw = sMarioCamState->faceAngle[1] + DEGREES(180);
@ -1965,8 +1965,8 @@ s16 update_slide_camera(struct Camera *c) {
f32 distCamToFocus;
f32 maxCamDist;
f32 pitchScale;
s16 camPitch;
s16 camYaw;
s16 camPitch = 0;
s16 camYaw = 0;
UNUSED struct MarioState *marioState = &gMarioStates[0];
s16 goalPitch = 0x1555;
s16 goalYaw = sMarioCamState->faceAngle[1] + DEGREES(180);
@ -2081,7 +2081,7 @@ s16 update_default_camera(struct Camera *c) {
f32 gasHeight;
s16 avoidYaw;
s16 pitch;
s16 yaw;
s16 yaw = 0;
s16 yawGoal = sMarioCamState->faceAngle[1] + DEGREES(180);
f32 posHeight;
f32 focHeight;
@ -2426,7 +2426,7 @@ s32 update_spiral_stairs_camera(struct Camera *c, Vec3f focus, Vec3f pos) {
// unused
s16 posPitch;
/// The camera's yaw around the stairs
s16 posYaw;
s16 posYaw = 0;
UNUSED s32 unused2;
Vec3f cPos;
Vec3f checkPos;
@ -6450,7 +6450,7 @@ struct CameraTrigger sCamBBH[] = {
*
* Each table is terminated with NULL_TRIGGER
*/
struct CameraTrigger *sCameraTriggers[LEVEL_COUNT + 1] = {
struct CameraTrigger *sCameraTriggers[LEVEL_COUNT + 2] = {
NULL,
#include "levels/level_defines.h"
};

View file

@ -1937,16 +1937,18 @@ void render_dialog_entries(void) {
render_dialog_box_type(dialog, dialog->linesPerBox);
#ifdef VERSION_EU
u32 scissorHeight = ensure_nonnegative((240 - dialog->width) + ((dialog->linesPerBox * 80) / DIAG_VAL4) / gDialogBoxScale);
#else
u32 scissorHeight = ensure_nonnegative(240 + ((dialog->linesPerBox * 80) / DIAG_VAL4) - dialog->width);
#endif
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE,
0,
ensure_nonnegative(DIAG_VAL2 - dialog->width),
#ifdef VERSION_EU
SCREEN_WIDTH,
ensure_nonnegative((240 - dialog->width) + ((dialog->linesPerBox * 80) / DIAG_VAL4) / gDialogBoxScale));
#else
SCREEN_WIDTH,
ensure_nonnegative(240 + ((dialog->linesPerBox * 80) / DIAG_VAL4) - dialog->width));
#endif
scissorHeight);
#if defined(VERSION_JP) || defined(VERSION_SH)
handle_dialog_text_and_pages(0, dialog);
#else

View file

@ -103,8 +103,8 @@ void handle_debug_key_sequences(void) {
void unknown_main_func(void) {
// uninitialized
OSTime time;
u32 b;
OSTime time = 0;
u32 b = 0;
osSetTime(time);
osMapTLB(0, b, NULL, 0, 0, 0);
@ -112,7 +112,8 @@ void unknown_main_func(void) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
sprintf(NULL, NULL);
// wtf is this
//sprintf(NULL, NULL);
#pragma GCC diagnostic pop
}

View file

@ -135,8 +135,8 @@ const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors);
void set_player_colors(u8 paletteIndex, const u8 shirt[4], const u8 pants[4]) {
// choose the last color in the table for extra players
if (paletteIndex >= gNumPlayerColors) paletteIndex = gNumPlayerColors - 1;
const u8 pAmb[3] = { pants[0] >> pants[4], pants[1] >> pants[4], pants[2] >> pants[4] };
const u8 sAmb[3] = { shirt[0] >> shirt[4], shirt[1] >> shirt[4], shirt[2] >> shirt[4] };
const u8 pAmb[3] = { pants[0] >> pants[3], pants[1] >> pants[3], pants[2] >> pants[3] };
const u8 sAmb[3] = { shirt[0] >> shirt[3], shirt[1] >> shirt[3], shirt[2] >> shirt[3] };
gPlayerColors[paletteIndex].pants =
(Lights1) gdSPDefLights1(pAmb[0], pAmb[1], pAmb[2], pants[0], pants[1], pants[2], 0x28, 0x28, 0x28);
gPlayerColors[paletteIndex].shirt =

View file

@ -25,7 +25,7 @@ static bool acceptable_file(char* string) {
static void mod_list_delete_tmp(void) {
struct dirent* dir;
DIR* d = opendir(sTmpPath);
if (!d) { closedir(d); return; }
if (!d) { return; }
static char path[SYS_MAX_PATH] = { 0 };
while ((dir = readdir(d)) != NULL) {

View file

@ -15,7 +15,9 @@ void ban_list_add(char* address, bool perm) {
gBanPerm = malloc(sizeof(bool) * gBanCount);
} else {
gBanAddresses = realloc(gBanAddresses, sizeof(char*) * gBanCount);
assert(gBanAddresses != NULL);
gBanPerm = realloc(gBanPerm, sizeof(bool) * gBanCount);
assert(gBanPerm != NULL);
}
if (gBanAddresses == NULL) {
LOG_ERROR("Failed to allocate gBanAddresses");

View file

@ -99,14 +99,21 @@ void network_remember_reliable(struct Packet* p) {
if (tail == NULL) {
// start of the list
SOFT_ASSERT(head == NULL);
if (head != NULL) {
free(node);
SOFT_ASSERT(head == NULL);
}
head = node;
tail = node;
return;
}
// add to end of list
SOFT_ASSERT(tail->next == NULL);
if (tail->next != NULL) {
free(node);
SOFT_ASSERT(tail->next == NULL);
}
tail->next = node;
node->prev = tail;
tail = node;