From 647a5e7ed42d9c711176bf34a6065823564dfa24 Mon Sep 17 00:00:00 2001 From: Haru Date: Sun, 3 May 2020 23:44:32 +0200 Subject: Sanitize the use of the enum e_skill_flag values, especially SKILL_FLAG_REPLACED_LV_0 This ensures that a negative level is never saved to the database and hopefully helps catching any coding errors that would lead to that. Signed-off-by: Haru --- src/char/char.c | 56 ++++++++++++++++++++++++++++++-------------------------- src/map/pc.c | 33 ++++++++++++++++----------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index aac9ad20c..0406dbecf 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -425,8 +425,6 @@ static struct DBData char_create_charstatus(union DBKey key, va_list args) static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) { - int i = 0; - int count = 0; int diff = 0; char save_status[128]; //For displaying save information. [Skotlex] struct mmo_charstatus *cp; @@ -591,8 +589,9 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) //insert here. StrBuf->Clear(&buf); StrBuf->Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); - for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) - { + + int count = 0; + for (int i = 0; i < MAX_MEMOPOINTS; ++i) { if( p->memo_point[i].map ) { if( count ) @@ -624,24 +623,29 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) StrBuf->Clear(&buf); StrBuf->Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`,`flag`) VALUES ", skill_db); //insert here. - for (i = 0, count = 0; i < MAX_SKILL_DB; ++i) { - if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) { - if( p->skill[i].lv == 0 && ( p->skill[i].flag == SKILL_FLAG_PERM_GRANTED || p->skill[i].flag == SKILL_FLAG_PERMANENT ) ) - continue; - if( p->skill[i].flag != SKILL_FLAG_PERMANENT && p->skill[i].flag != SKILL_FLAG_PERM_GRANTED && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) - continue; - if( count ) - StrBuf->AppendStr(&buf, ","); - StrBuf->Printf(&buf, "('%d','%d','%d','%d')", char_id, p->skill[i].id, - ( (p->skill[i].flag == SKILL_FLAG_PERMANENT || p->skill[i].flag == SKILL_FLAG_PERM_GRANTED) ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0), - p->skill[i].flag == SKILL_FLAG_PERM_GRANTED ? p->skill[i].flag : 0);/* other flags do not need to be saved */ - ++count; - } + int count = 0; + for (int i = 0; i < MAX_SKILL_DB; ++i) { + if (p->skill[i].id == 0) + continue; + if (p->skill[i].flag == SKILL_FLAG_TEMPORARY) + continue; + if (p->skill[i].lv == 0 && (p->skill[i].flag == SKILL_FLAG_PERM_GRANTED || p->skill[i].flag == SKILL_FLAG_PERMANENT)) + continue; + if (p->skill[i].flag == SKILL_FLAG_REPLACED_LV_0) + continue; + + if (Assert_chk(p->skill[i].flag == SKILL_FLAG_PERMANENT || p->skill[i].flag == SKILL_FLAG_PERM_GRANTED || p->skill[i].flag > SKILL_FLAG_REPLACED_LV_0)) + continue; + if (count != 0) + StrBuf->AppendStr(&buf, ","); + int saved_lv = (p->skill[i].flag > SKILL_FLAG_REPLACED_LV_0) ? p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0 : p->skill[i].lv; + int saved_flag = p->skill[i].flag == SKILL_FLAG_PERM_GRANTED ? p->skill[i].flag : 0; // other flags do not need to be saved + StrBuf->Printf(&buf, "('%d','%d','%d','%d')", char_id, p->skill[i].id, saved_lv, saved_flag); + + ++count; } - if( count ) - { - if( SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf)) ) - { + if (count != 0) { + if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) { Sql_ShowDebug(inter->sql_handle); errors++; } @@ -651,7 +655,7 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) } diff = 0; - for(i = 0; i < MAX_FRIENDS; i++){ + for (int i = 0; i < MAX_FRIENDS; i++) { if(p->friends[i].char_id != cp->friends[i].char_id || p->friends[i].account_id != cp->friends[i].account_id){ diff = 1; @@ -669,8 +673,8 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) StrBuf->Clear(&buf); StrBuf->Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); - for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) - { + int count = 0; + for (int i = 0; i < MAX_FRIENDS; ++i) { if( p->friends[i].char_id > 0 ) { if( count ) @@ -695,7 +699,7 @@ static int char_mmo_char_tosql(int char_id, struct mmo_charstatus *p) StrBuf->Clear(&buf); StrBuf->Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); diff = 0; - for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ + for (int i = 0; i < ARRAYLENGTH(p->hotkeys); i++) { if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) { if( diff ) @@ -1369,7 +1373,7 @@ static int char_mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool loa SqlStmt_ShowDebug(stmt); } - if( tmp_skill.flag != SKILL_FLAG_PERM_GRANTED ) + if (tmp_skill.flag != SKILL_FLAG_PERM_GRANTED) tmp_skill.flag = SKILL_FLAG_PERMANENT; for (i = 0; i < MAX_SKILL_DB && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i) { diff --git a/src/map/pc.c b/src/map/pc.c index 599317dee..6934e31b8 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1605,24 +1605,21 @@ static void pc_calc_skilltree_clear(struct map_session_data *sd) *------------------------------------------*/ static int pc_calc_skilltree(struct map_session_data *sd) { - int i,id=0,flag; - int class = 0, classidx = 0; - nullpo_ret(sd); - i = pc->calc_skilltree_normalize_job(sd); - class = pc->mapid2jobid(i, sd->status.sex); + uint32 job = pc->calc_skilltree_normalize_job(sd); + int class = pc->mapid2jobid(job, sd->status.sex); if (class == -1) { //Unable to normalize job?? - ShowError("pc_calc_skilltree: Unable to normalize job %d for character %s (%d:%d)\n", i, sd->status.name, sd->status.account_id, sd->status.char_id); + ShowError("pc_calc_skilltree: Unable to normalize job %u for character %s (%d:%d)\n", job, sd->status.name, sd->status.account_id, sd->status.char_id); return 1; } - classidx = pc->class2idx(class); + int classidx = pc->class2idx(class); pc->calc_skilltree_clear(sd); - for (i = 0; i < MAX_SKILL_DB; i++) { - if( sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED ) - { // Restore original level of skills after deleting earned skills. + for (int i = 0; i < MAX_SKILL_DB; i++) { + if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { + // Restore original level of skills after deleting earned skills. sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } @@ -1657,7 +1654,7 @@ static int pc_calc_skilltree(struct map_session_data *sd) } if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) { - for (i = 0; i < MAX_SKILL_DB; i++) { + for (int i = 0; i < MAX_SKILL_DB; i++) { switch(skill->dbs->db[i].nameid) { /** * Dummy skills must be added here otherwise they'll be displayed in the, @@ -1689,9 +1686,11 @@ static int pc_calc_skilltree(struct map_session_data *sd) return 0; } + bool changed = false; do { - flag = 0; - for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[classidx][i].id) > 0; i++) { + changed = false; + int id; + for (int i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[classidx][i].id) > 0; i++) { int idx = pc->skill_tree[classidx][i].idx; bool satisfied = true; if (sd->status.skill[idx].id > 0) @@ -1741,10 +1740,10 @@ static int pc_calc_skilltree(struct map_session_data *sd) sd->status.skill[idx].lv = 1; // need to manually specify a skill level sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill. } - flag = 1; // skill list has changed, perform another pass + changed = true; // skill list has changed, perform another pass } } - } while(flag); + } while (changed); pc->calc_skilltree_bonus(sd, classidx); @@ -4207,7 +4206,7 @@ static int pc_skill(struct map_session_data *sd, int id, int level, int flag) if( sd->status.skill[index].id == id ) { if( sd->status.skill[index].lv >= level ) return 0; - if( sd->status.skill[index].flag == SKILL_FLAG_PERMANENT ) //Non-granted skill, store it's level. + if (sd->status.skill[index].flag == SKILL_FLAG_PERMANENT) // Non-granted skill, store its level. sd->status.skill[index].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[index].lv; } else { sd->status.skill[index].id = id; @@ -7569,7 +7568,7 @@ static int pc_allskillup(struct map_session_data *sd) nullpo_ret(sd); for (i = 0; i < MAX_SKILL_DB; i++) { - if (sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED) { + if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; if (sd->status.skill[i].lv == 0) -- cgit v1.2.3-70-g09d2