From 3a2cd3c331888237ea642043b2118c85eb68914b Mon Sep 17 00:00:00 2001 From: Rot127 <45763064+Rot127@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:19:42 +0000 Subject: [PATCH] Coverity defects (#2469) * Fix CID 508418 - Uninitialized struct * Fix CID 509089 - Fix OOB read and write * Fix CID 509088 - OOB. Also adds tests and to ensure no OOB access. * Fix CID 509085 - Resource leak. * Fix CID 508414 and companions - Using undefined values. * Fix CID 508405 - Use of uninitialized value * Remove unnecessary and badly implemented dev fuzz code. * Fix CID 508396 - Uninitialzied variable. * Fix CID 508393, 508365 -- OOB read. * Fix CID 432207 - OVerlapping memory access. * Remove unused functions * Fix CID 432170 - Overlapping memory access. * Fix CID 166022 - Check for negative index * Let strncat not depend n src operand. * Fix 509083 and 509084 - NULL dereference * Remove duplicated code. * Initialize sysop * Fix resource leak * Remove unreachable code. * Remove duplicate code. * Add assert to check return value of cmoack * Fixed: d should be a signed value, since it is checked against < 0 * Add missing break. * Add NULL check * Fix signs of binary search comparisons. * Add explicit cast of or result * Fix correct scope of case. * Handle invalid integer type. * Return UINT_MAX instead of implicitly casted -1 * Remove dead code * Fix type of im * Fix type of d * Remove duplicated code. * Add returns after CS_ASSERTS * Check for len == 0 case. * Ensure shift operates on uint64 * Replace strcpy with strncpy. * Handle edge cases for 32bit rotate * Fix some out of enum warnings * Replace a strcpy with strncpy. * Fix increment of address * Skip some linting * Fix: set instruction id * Remove unused enum * Replace the last usages of strcpy with SStream functions. * Increase number of allowed AArch64 operands. * Check safety of incrementing t the next operand. * Fix naming of operand * Update python constants * Fix option setup of CS_OPT_DETAIL_REAL * Document DETAIL_REAL has to be used with CS_OPT_ON. * Run Coverity scan every Monday. * Remove dead code * Fix OOB read * Rename macro to reflect it is only used with sstreams * Fix rebase issues --- .github/workflows/coverity.yml | 2 +- MCInstPrinter.c | 4 +- Mapping.c | 12 +- Mapping.h | 16 + MathExtras.h | 12 +- SStream.c | 98 +++++- SStream.h | 10 + arch/AArch64/AArch64AddressingModes.h | 5 +- arch/AArch64/AArch64InstPrinter.c | 10 +- arch/AArch64/AArch64Mapping.c | 54 ++-- arch/ARM/ARMAddressingModes.h | 7 +- arch/ARM/ARMInstPrinter.c | 13 +- arch/ARM/ARMMapping.c | 26 +- arch/Alpha/AlphaGenDisassemblerTables.inc | 1 + arch/HPPA/HPPADisassembler.c | 14 +- arch/M680X/M680XDisassembler.c | 6 +- arch/M68K/M68KDisassembler.c | 7 - arch/MOS65XX/MOS65XXModule.c | 2 +- arch/PowerPC/PPCMapping.c | 7 +- arch/RISCV/RISCVGenAsmWriter.inc | 20 +- arch/RISCV/RISCVGenDisassemblerTables.inc | 3 +- arch/SH/SHDisassembler.c | 17 +- arch/Sparc/SparcInstPrinter.c | 8 +- arch/Sparc/SparcInstPrinter.h | 2 +- arch/TMS320C64x/TMS320C64xDisassembler.c | 8 +- arch/TMS320C64x/TMS320C64xInstPrinter.c | 64 ++-- arch/TMS320C64x/TMS320C64xInstPrinter.h | 2 +- arch/TriCore/TriCoreDisassembler.c | 6 +- arch/TriCore/TriCoreInstPrinter.c | 6 +- arch/WASM/WASMDisassembler.c | 3 - arch/X86/X86ATTInstPrinter.c | 9 +- arch/X86/X86Mapping.c | 2 +- arch/X86/X86Mapping.h | 2 +- arch/XCore/XCoreInstPrinter.c | 13 +- arch/XCore/XCoreInstPrinter.h | 2 +- bindings/python/capstone/__init__.py | 4 +- bindings/python/capstone/arm_const.py | 2 + bindings/python/capstone/hppa_const.py | 1 - bindings/python/capstone/sh_const.py | 3 - bindings/python/capstone/systemz_const.py | 1 + bindings/python/capstone/tricore_const.py | 1 - cs.c | 64 +--- cs_priv.h | 2 +- cstool/cstool.c | 60 +--- cstool/cstool_aarch64.c | 1 + cstool/cstool_arm.c | 3 +- cstool/cstool_systemz.c | 6 +- cstool/cstool_x86.c | 4 + docs/cs_v6_release_guide.md | 2 +- include/capstone/aarch64.h | 4 +- include/capstone/alpha.h | 4 +- include/capstone/arm.h | 5 +- include/capstone/hppa.h | 4 +- include/capstone/loongarch.h | 4 +- include/capstone/mips.h | 4 +- include/capstone/riscv.h | 4 +- include/capstone/sh.h | 9 +- include/capstone/tricore.h | 4 +- .../src/autosync/Tests/test_aarch64_header.h | 4 +- suite/cstest/src/test_case.c | 15 +- suite/cstest/src/test_detail_x86.c | 4 +- suite/cstest/src/test_run.c | 8 +- suite/fuzz/platform.c | 6 +- tests/issues/issues.yaml | 74 +++++ tests/unit/CMakeLists.txt | 20 +- tests/unit/include/unit_test.h | 44 +++ tests/unit/sstream.c | 303 ++++++++++++++---- tests/unit/utils.c | 76 +++++ utils.c | 23 +- utils.h | 2 +- 70 files changed, 843 insertions(+), 405 deletions(-) create mode 100644 tests/unit/include/unit_test.h create mode 100644 tests/unit/utils.c diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 75810e2ee..9c54620b2 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -2,7 +2,7 @@ name: Coverity Scan on: workflow_dispatch: schedule: - - cron: '0 0 01 * *' # On the 1st every month at midnight UTC + - cron: '0 0 * * 1' # On every Monday at midnight UTC # Automatically cancel any previous workflow on new push. diff --git a/MCInstPrinter.c b/MCInstPrinter.c index 4e509c6ee..687fbf359 100644 --- a/MCInstPrinter.c +++ b/MCInstPrinter.c @@ -232,8 +232,8 @@ unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index, si right = size - 1; - size_t str_left_cmp = strcmp(name, index[0].name); - size_t str_right_cmp = strcmp(name, index[right].name); + int str_left_cmp = strcmp(name, index[0].name); + int str_right_cmp = strcmp(name, index[right].name); if (str_left_cmp < 0 || str_right_cmp > 0) // not found return -1; diff --git a/Mapping.c b/Mapping.c index d2ef694d5..c39ae7f85 100644 --- a/Mapping.c +++ b/Mapping.c @@ -150,7 +150,10 @@ void map_implicit_reads(MCInst *MI, const insn_map *imap) return; } detail->regs_read[detail->regs_read_count++] = reg; - reg = imap[Opcode].regs_use[++i]; + if (i + 1 < MAX_IMPL_R_REGS) { + // Select next one + reg = imap[Opcode].regs_use[++i]; + } } #endif // CAPSTONE_DIET } @@ -175,7 +178,10 @@ void map_implicit_writes(MCInst *MI, const insn_map *imap) return; } detail->regs_write[detail->regs_write_count++] = reg; - reg = imap[Opcode].regs_mod[++i]; + if (i + 1 < MAX_IMPL_W_REGS) { + // Select next one + reg = imap[Opcode].regs_mod[++i]; + } } #endif // CAPSTONE_DIET } @@ -348,7 +354,7 @@ DEFINE_get_detail_op(systemz, SystemZ); /// So it can be toggled between disas() calls. bool map_use_alias_details(const MCInst *MI) { assert(MI); - return !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL); + return (MI->csh->detail_opt & CS_OPT_ON) && !(MI->csh->detail_opt & CS_OPT_DETAIL_REAL); } /// Sets the setDetailOps flag to @p Val. diff --git a/Mapping.h b/Mapping.h index 473075ea2..790f1cb1a 100644 --- a/Mapping.h +++ b/Mapping.h @@ -209,6 +209,22 @@ DEFINE_get_arch_detail(mips, Mips); DEFINE_get_arch_detail(riscv, RISCV); DEFINE_get_arch_detail(systemz, SystemZ); +#define DEFINE_check_safe_inc(Arch, ARCH) \ + static inline void Arch##_check_safe_inc() { \ + CS_ASSERT(Arch##_get_detail(MI)->op_count + 1 < NUM_##ARCH##_OPS); \ + } + +DEFINE_check_safe_inc(ARM, ARM); +DEFINE_check_safe_inc(PPC, PPC); +DEFINE_check_safe_inc(TriCore, TRICORE); +DEFINE_check_safe_inc(AArch64, AARCH64); +DEFINE_check_safe_inc(Alpha, ALPHA); +DEFINE_check_safe_inc(HPPA, HPPA); +DEFINE_check_safe_inc(LoongArch, LOONGARCH); +DEFINE_check_safe_inc(RISCV, RISCV); +DEFINE_check_safe_inc(SystemZ, SYSTEMZ); +DEFINE_check_safe_inc(Mips, MIPS); + static inline bool detail_is_set(const MCInst *MI) { assert(MI && MI->flat_insn); diff --git a/MathExtras.h b/MathExtras.h index eb3b98971..19dfba4f6 100644 --- a/MathExtras.h +++ b/MathExtras.h @@ -29,6 +29,8 @@ #endif #endif +#include + // NOTE: The following support functions use the _32/_64 extensions instead of // type overloading so that signed and unsigned integers can be used without // ambiguity. @@ -280,15 +282,21 @@ static inline unsigned CountPopulation_64(uint64_t Value) { } /// Log2_32 - This function returns the floor log base 2 of the specified value, -/// -1 if the value is zero. (32 bit edition.) +/// UINT_MAX if the value is zero. (32 bit edition.) /// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 static inline unsigned Log2_32(uint32_t Value) { + if (Value == 0) { + return UINT_MAX; + } return 31 - CountLeadingZeros_32(Value); } /// Log2_64 - This function returns the floor log base 2 of the specified value, -/// -1 if the value is zero. (64 bit edition.) +/// UINT_MAX if the value is zero. (64 bit edition.) static inline unsigned Log2_64(uint64_t Value) { + if (Value == 0) { + return UINT32_MAX; + } return 63 - CountLeadingZeros_64(Value); } diff --git a/SStream.c b/SStream.c index 68c685c05..a69150710 100644 --- a/SStream.c +++ b/SStream.c @@ -18,20 +18,108 @@ #include "cs_priv.h" #include "utils.h" -#ifdef _MSC_VER -#pragma warning(disable: 4996) // disable MSVC's warning on strcpy() -#endif - void SStream_Init(SStream *ss) { assert(ss); ss->index = 0; - ss->buffer[0] = '\0'; + memset(ss->buffer, 0, sizeof(ss->buffer)); ss->is_closed = false; ss->markup_stream = false; ss->prefixed_by_markup = false; } +/// Returns the a pointer to the internal string buffer of the stream. +/// For reading only. +const char *SStream_rbuf(const SStream *ss) { + assert(ss); + return ss->buffer; +} + +/// Searches in the stream for the first (from the left) occurrence of @elem and replaces +/// it with @repl. It returns the pointer *after* the replaced character +/// or NULL if no character was replaced. +/// +/// It will never replace the final \0 byte in the stream buffer. +const char *SStream_replc(const SStream *ss, char elem, char repl) { + assert(ss); + char *found = strchr(ss->buffer, elem); + if (!found || found == ss->buffer + (SSTREAM_BUF_LEN - 1)) { + return NULL; + } + *found = repl; + found++; + return found; +} + +/// Searches in the stream for the first (from the left) occurrence of @chr and replaces +/// it with @rstr. +void SStream_replc_str(SStream *ss, char chr, const char *rstr) { + assert(ss && rstr); + char *found = strchr(ss->buffer, chr); + if (!found || found == ss->buffer + (SSTREAM_BUF_LEN - 1)) { + return; + } + size_t post_len = strlen(found + 1); + size_t buf_str_len = strlen(ss->buffer); + size_t repl_len = strlen(rstr); + if (repl_len - 1 + buf_str_len >= SSTREAM_BUF_LEN) { + return; + } + memmove(found + repl_len, found + 1, post_len); + memcpy(found, rstr, repl_len); + ss->index = strlen(ss->buffer); +} + +/// Removes the space characters '\t' and ' ' from the beginning of the stream buffer. +void SStream_trimls(SStream *ss) { + assert(ss); + size_t buf_off = 0; + /// Remove leading spaces + while (ss->buffer[buf_off] == ' ' || ss->buffer[buf_off] == '\t') { + buf_off++; + } + if (buf_off > 0) { + memmove(ss->buffer, ss->buffer + buf_off, SSTREAM_BUF_LEN - buf_off); + ss->index -= buf_off; + } +} + +/// Extract the mnemonic to @mnem_buf and the operand string into @op_str_buf from the stream buffer. +/// The mnemonic is everything up until the first ' ' or '\t' character. +/// The operand string is everything after the first ' ' or '\t' sequence. +void SStream_extract_mnem_opstr(const SStream *ss, char *mnem_buf, size_t mnem_buf_size, char *op_str_buf, size_t op_str_buf_size) { + assert(ss && mnem_buf && mnem_buf_size > 0 && op_str_buf && op_str_buf_size > 0); + size_t off = 0; + // Copy all non space chars to as mnemonic. + while (ss->buffer[off] && ss->buffer[off] != ' ' && ss->buffer[off] != '\t') { + if (off < mnem_buf_size - 1) { + // Only copy if there is space left. + mnem_buf[off] = ss->buffer[off]; + } + off++; + } + if (!ss->buffer[off]) { + return; + } + + // Iterate until next non space char. + do { + off++; + } while (ss->buffer[off] && (ss->buffer[off] == ' ' || ss->buffer[off] == '\t')); + + if (!ss->buffer[off]) { + return; + } + + // Copy all follow up characters as op_str + const char *ss_op_str = ss->buffer + off; + off = 0; + while (ss_op_str[off] && off < op_str_buf_size - 1) { + op_str_buf[off] = ss_op_str[off]; + off++; + } +} + /// Empty the stream @ss to given @file (stdin/stderr). /// @file can be NULL. Then the buffer content is not emitted. void SStream_Flush(SStream *ss, FILE *file) diff --git a/SStream.h b/SStream.h index 35c90738d..8789ea6cc 100644 --- a/SStream.h +++ b/SStream.h @@ -40,6 +40,16 @@ do { \ void SStream_Init(SStream *ss); +const char *SStream_replc(const SStream *ss, char elem, char repl); + +void SStream_replc_str(SStream *ss, char chr, const char *rstr); + +const char *SStream_rbuf(const SStream *ss); + +void SStream_extract_mnem_opstr(const SStream *ss, char *mnem_buf, size_t mnem_buf_size, char *op_str_buf, size_t op_str_buf_size); + +void SStream_trimls(SStream *ss); + void SStream_Flush(SStream *ss, FILE *file); void SStream_Open(SStream *ss); diff --git a/arch/AArch64/AArch64AddressingModes.h b/arch/AArch64/AArch64AddressingModes.h index e77378d6e..273b3eaa5 100644 --- a/arch/AArch64/AArch64AddressingModes.h +++ b/arch/AArch64/AArch64AddressingModes.h @@ -390,7 +390,10 @@ static inline uint64_t AArch64_AM_decodeLogicalImmediate(uint64_t val, unsigned imms = val & 0x3f; int len = 31 - countLeadingZeros((N << 6) | (~imms & 0x3f)); - assert(len >= 1); + if (len < 1) { + assert(len >= 1 && "Unhandled integer type"); + return 0; + } unsigned size = (1 << len); unsigned R = immr & (size - 1); diff --git a/arch/AArch64/AArch64InstPrinter.c b/arch/AArch64/AArch64InstPrinter.c index 4db25f2ab..9d7f2bd7b 100644 --- a/arch/AArch64/AArch64InstPrinter.c +++ b/arch/AArch64/AArch64InstPrinter.c @@ -727,7 +727,7 @@ Search_IC: { !AArch64_testFeatureList(MI->csh->mode, IC->FeaturesRequired)) return false; if (detail_is_set(MI)) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.reg = IC->SysReg; sysop.sub_type = AARCH64_OP_IC; AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG; @@ -754,7 +754,7 @@ Search_IC: { MI->csh->mode, DC->FeaturesRequired)) return false; if (detail_is_set(MI)) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias = DC->SysAlias; sysop.sub_type = AARCH64_OP_DC; AArch64_get_detail_op(MI, 0)->type = @@ -777,7 +777,7 @@ Search_IC: { return false; if (detail_is_set(MI)) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias = AT->SysAlias; sysop.sub_type = AARCH64_OP_AT; AArch64_get_detail_op(MI, 0)->type = @@ -799,7 +799,7 @@ Search_IC: { return false; if (detail_is_set(MI)) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.reg = TLBI->SysReg; sysop.sub_type = AARCH64_OP_TLBI; AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG; @@ -868,7 +868,7 @@ bool printSyspAlias(MCInst *MI, SStream *O) return false; if (detail_is_set(MI)) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.reg = TLBI->SysReg; sysop.sub_type = AARCH64_OP_TLBI; AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SYSREG; diff --git a/arch/AArch64/AArch64Mapping.c b/arch/AArch64/AArch64Mapping.c index 68d588c19..bf2be7aa9 100644 --- a/arch/AArch64/AArch64Mapping.c +++ b/arch/AArch64/AArch64Mapping.c @@ -595,7 +595,7 @@ static void AArch64_add_not_defined_ops(MCInst *MI, const SStream *OS) const char *disp_off = NULL; disp_off = strstr(OS->buffer, " za"); if (disp_off) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias.svcr = AARCH64_SVCR_SVCRZA; sysop.sub_type = AARCH64_OP_SVCR; AArch64_insert_detail_op_sys(MI, -1, sysop, @@ -604,7 +604,7 @@ static void AArch64_add_not_defined_ops(MCInst *MI, const SStream *OS) } disp_off = strstr(OS->buffer, " sm"); if (disp_off) { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias.svcr = AARCH64_SVCR_SVCRSM; sysop.sub_type = AARCH64_OP_SVCR; AArch64_insert_detail_op_sys(MI, -1, sysop, @@ -1384,7 +1384,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, } case AArch64_OP_GROUP_BarriernXSOption: { unsigned Val = MCInst_getOpVal(MI, OpNum); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; const AArch64DBnXS_DBnXS *DB = AArch64DBnXS_lookupDBnXSByEncoding(Val); if (DB) @@ -1398,7 +1398,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, case AArch64_OP_GROUP_BarrierOption: { unsigned Val = MCOperand_getImm(MCInst_getOperand(MI, OpNum)); unsigned Opcode = MCInst_getOpcode(MI); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; if (Opcode == AArch64_ISB) { const AArch64ISB_ISB *ISB = @@ -1434,7 +1434,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, break; } case AArch64_OP_GROUP_BTIHintOp: { - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; unsigned btihintop = MCInst_getOpVal(MI, OpNum) ^ 32; const AArch64BTIHint_BTI *BTI = AArch64BTIHint_lookupBTIByEncoding(btihintop); @@ -1523,6 +1523,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, (int) (AARCH64_REG_ZAD0 + I)); AArch64_inc_op_count(MI); } + AArch64_get_detail(MI)->is_doing_sme = false; break; } case AArch64_OP_GROUP_MRSSystemRegister: @@ -1541,7 +1542,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, if (Reg && !isValidSysReg) Reg = AArch64SysReg_lookupSysRegByName(Reg->AltName); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; // If Reg is NULL it is a generic system register. if (Reg) sysop.reg = Reg->SysReg; @@ -1560,7 +1561,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, unsigned psbhintop = MCInst_getOpVal(MI, OpNum); const AArch64PSBHint_PSB *PSB = AArch64PSBHint_lookupPSBByEncoding(psbhintop); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; if (PSB) sysop.alias = PSB->SysAlias; else @@ -1574,7 +1575,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, unsigned prfop = MCInst_getOpVal(MI, OpNum); const AArch64PRFM_PRFM *PRFM = AArch64PRFM_lookupPRFMByEncoding(prfop); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; if (PRFM) sysop.alias = PRFM->SysAlias; else @@ -1611,7 +1612,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, unsigned svcrop = MCInst_getOpVal(MI, OpNum); const AArch64SVCR_SVCR *SVCR = AArch64SVCR_lookupSVCRByEncoding(svcrop); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; if (SVCR) sysop.alias = SVCR->SysAlias; else @@ -1629,7 +1630,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, AArch64_set_detail_op_imm(MI, OpNum, AARCH64_OP_IMM, Val); break; } - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias = Pat->SysAlias; sysop.sub_type = AARCH64_OP_SVEPREDPAT; AArch64_set_detail_op_sys(MI, OpNum, sysop, @@ -1646,7 +1647,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, Val); if (!Pat) break; - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.alias = Pat->SysAlias; sysop.sub_type = AARCH64_OP_SVEVECLENSPECIFIER; AArch64_set_detail_op_sys(MI, OpNum, sysop, @@ -1667,7 +1668,7 @@ static void add_cs_detail_general(MCInst *MI, aarch64_op_group op_group, case AArch64_OP_GROUP_SystemPStateField: { unsigned Val = MCInst_getOpVal(MI, OpNum); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; const AArch64PState_PStateImm0_15 *PStateImm15 = AArch64PState_lookupPStateImm0_15ByEncoding(Val); const AArch64PState_PStateImm0_1 *PStateImm1 = @@ -1881,7 +1882,7 @@ static void add_cs_detail_template_1(MCInst *MI, aarch64_op_group op_group, case AArch64_OP_GROUP_PrefetchOp_1: { bool IsSVEPrefetch = (bool)temp_arg_0; unsigned prfop = MCInst_getOpVal(MI, (OpNum)); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; if (IsSVEPrefetch) { const AArch64SVEPRFM_SVEPRFM *PRFM = AArch64SVEPRFM_lookupSVEPRFMByEncoding(prfop); @@ -2036,7 +2037,7 @@ static void add_cs_detail_template_2(MCInst *MI, aarch64_op_group op_group, const AArch64ExactFPImm_ExactFPImm *Imm1Desc = AArch64ExactFPImm_lookupExactFPImmByEnum(ImmIs1); unsigned Val = MCInst_getOpVal(MI, (OpNum)); - aarch64_sysop sysop; + aarch64_sysop sysop = { 0 }; sysop.imm = Val ? Imm1Desc->SysImm : Imm0Desc->SysImm; sysop.sub_type = AARCH64_OP_EXACTFPIMM; AArch64_set_detail_op_sys(MI, OpNum, sysop, AARCH64_OP_SYSIMM); @@ -2474,6 +2475,8 @@ void AArch64_set_detail_op_reg(MCInst *MI, unsigned OpNum, aarch64_reg Reg) { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); + if (Reg == AARCH64_REG_ZA || (Reg >= AARCH64_REG_ZAB0 && Reg < AARCH64_REG_ZT0)) { // A tile register should be treated as SME operand. @@ -2519,6 +2522,7 @@ void AArch64_set_detail_op_imm(MCInst *MI, unsigned OpNum, { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); if (AArch64_get_detail(MI)->is_doing_sme) { assert(map_get_op_type(MI, OpNum) & CS_OP_BOUND); @@ -2553,6 +2557,7 @@ void AArch64_set_detail_op_imm_range(MCInst *MI, unsigned OpNum, { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); if (AArch64_get_detail(MI)->is_doing_sme) { assert(map_get_op_type(MI, OpNum) & CS_OP_BOUND); @@ -2585,6 +2590,7 @@ void AArch64_set_detail_op_mem(MCInst *MI, unsigned OpNum, uint64_t Val) { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); assert(map_get_op_type(MI, OpNum) & CS_OP_MEM); AArch64_set_mem_access(MI, true); @@ -2670,6 +2676,8 @@ void AArch64_set_detail_op_float(MCInst *MI, unsigned OpNum, float Val) { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); + AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_FP; AArch64_get_detail_op(MI, 0)->fp = Val; AArch64_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); @@ -2683,6 +2691,8 @@ void AArch64_set_detail_op_sys(MCInst *MI, unsigned OpNum, aarch64_sysop sys_op, { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); + AArch64_get_detail_op(MI, 0)->type = type; AArch64_get_detail_op(MI, 0)->sysop = sys_op; AArch64_inc_op_count(MI); @@ -2691,6 +2701,7 @@ void AArch64_set_detail_op_sys(MCInst *MI, unsigned OpNum, aarch64_sysop sys_op, void AArch64_set_detail_op_pred(MCInst *MI, unsigned OpNum) { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); if (AArch64_get_detail_op(MI, 0)->type == AARCH64_OP_INVALID) { setup_pred_operand(MI); @@ -2718,6 +2729,8 @@ void AArch64_set_detail_op_sme(MCInst *MI, unsigned OpNum, { if (!detail_is_set(MI)) return; + AArch64_check_safe_inc(); + AArch64_get_detail_op(MI, 0)->type = AARCH64_OP_SME; switch (part) { default: @@ -2794,9 +2807,9 @@ static void insert_op(MCInst *MI, unsigned index, cs_aarch64_op op) return; } + AArch64_check_safe_inc(); cs_aarch64_op *ops = AArch64_get_detail(MI)->operands; int i = AArch64_get_detail(MI)->op_count; - assert(i < MAX_AARCH64_OPS); if (index == -1) { ops[i] = op; AArch64_inc_op_count(MI); @@ -2818,7 +2831,7 @@ void AArch64_insert_detail_op_float_at(MCInst *MI, unsigned index, double val, if (!detail_is_set(MI)) return; - assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS); + AArch64_check_safe_inc(); cs_aarch64_op op; AArch64_setup_op(&op); @@ -2838,7 +2851,7 @@ void AArch64_insert_detail_op_reg_at(MCInst *MI, unsigned index, if (!detail_is_set(MI)) return; - assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS); + AArch64_check_safe_inc(); cs_aarch64_op op; AArch64_setup_op(&op); @@ -2856,8 +2869,7 @@ void AArch64_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Imm) { if (!detail_is_set(MI)) return; - - assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS); + AArch64_check_safe_inc(); cs_aarch64_op op; AArch64_setup_op(&op); @@ -2873,7 +2885,7 @@ void AArch64_insert_detail_op_sys(MCInst *MI, unsigned index, aarch64_sysop sys_ { if (!detail_is_set(MI)) return; - assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS); + AArch64_check_safe_inc(); cs_aarch64_op op; AArch64_setup_op(&op); @@ -2887,7 +2899,7 @@ void AArch64_insert_detail_op_sme(MCInst *MI, unsigned index, aarch64_op_sme sme { if (!detail_is_set(MI)) return; - assert(AArch64_get_detail(MI)->op_count < MAX_AARCH64_OPS); + AArch64_check_safe_inc(); cs_aarch64_op op; AArch64_setup_op(&op); diff --git a/arch/ARM/ARMAddressingModes.h b/arch/ARM/ARMAddressingModes.h index 16d4b1433..bcfa89c96 100644 --- a/arch/ARM/ARMAddressingModes.h +++ b/arch/ARM/ARMAddressingModes.h @@ -28,6 +28,7 @@ #define CS_ARM_ADDRESSINGMODES_H #include +#include "../../cs_priv.h" #include #include #include @@ -120,7 +121,11 @@ static inline const char *ARM_AM_getAMSubModeStr(ARM_AM_SubMode Mode) /// static inline unsigned ARM_AM_rotr32(unsigned Val, unsigned Amt) { - return (Val >> Amt) | (Val << ((32 - Amt) & 31)); + CS_ASSERT(Amt >= 32); + if (Amt == 32) { + return Val; + } + return (Val >> Amt) | (Val << ((32 - Amt) & 31)); // NOLINT(clang-analyzer-core.BitwiseShift) } /// rotl32 - Rotate a 32-bit unsigned value left by a specified # bits. diff --git a/arch/ARM/ARMInstPrinter.c b/arch/ARM/ARMInstPrinter.c index 4dfbfc016..0457952ba 100644 --- a/arch/ARM/ARMInstPrinter.c +++ b/arch/ARM/ARMInstPrinter.c @@ -490,20 +490,13 @@ void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNum, SStream *O) SStream_concat0(O, "[pc, "); int32_t OffImm = (int32_t)MCOperand_getImm(MO1); - bool isSub = OffImm < 0; // Special value for #-0. All others are normal. if (OffImm == INT32_MIN) OffImm = 0; - if (isSub) { - SStream_concat(O, "%s", markup("")); - } else { - SStream_concat(O, "%s", markup("")); - } + SStream_concat(O, "%s", markup("")); SStream_concat(O, "%s", "]"); SStream_concat0(O, markup(">")); } diff --git a/arch/ARM/ARMMapping.c b/arch/ARM/ARMMapping.c index 22ba146d3..7e8f5407e 100644 --- a/arch/ARM/ARMMapping.c +++ b/arch/ARM/ARMMapping.c @@ -935,6 +935,7 @@ static void ARM_set_mem_access(MCInst *MI, bool status) #endif } else { // done, select the next operand slot + ARM_check_safe_inc(); ARM_inc_op_count(MI); } } @@ -1160,6 +1161,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group, unsigned Reg = MCOperand_getReg(MCInst_getOperand(MI, i)); + ARM_check_safe_inc(); ARM_get_detail_op(MI, 0)->type = ARM_OP_REG; ARM_get_detail_op(MI, 0)->reg = Reg; ARM_get_detail_op(MI, 0)->access = access; @@ -1173,7 +1175,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group, unsigned CondBit0 = Firstcond & 1; unsigned NumTZ = CountTrailingZeros_32(Mask); unsigned Pos, e; - ARM_PredBlockMask PredMask = 0; + ARM_PredBlockMask PredMask = ARM_PredBlockMaskInvalid; // Check the documentation of ARM_PredBlockMask how the bits are set. for (Pos = 3, e = NumTZ; Pos > e; --Pos) { @@ -1192,7 +1194,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group, case ARM_OP_GROUP_VPTMask: { unsigned Mask = MCInst_getOpVal(MI, OpNum); unsigned NumTZ = CountTrailingZeros_32(Mask); - ARM_PredBlockMask PredMask = 0; + ARM_PredBlockMask PredMask = ARM_PredBlockMaskInvalid; // Check the documentation of ARM_PredBlockMask how the bits are set. for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { @@ -1661,6 +1663,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group, int32_t OffImm = MCInst_getOpVal(MI, OpNum); if (OffImm == INT32_MIN) OffImm = 0; + ARM_check_safe_inc(); ARM_get_detail_op(MI, 0)->type = ARM_OP_MEM; ARM_get_detail_op(MI, 0)->mem.base = ARM_REG_PC; ARM_get_detail_op(MI, 0)->mem.index = ARM_REG_INVALID; @@ -1683,6 +1686,7 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group, } case ARM_OP_GROUP_SetendOperand: { bool be = MCInst_getOpVal(MI, OpNum) != 0; + ARM_check_safe_inc(); if (be) { ARM_get_detail_op(MI, 0)->type = ARM_OP_SETEND; ARM_get_detail_op(MI, 0)->setend = ARM_SETEND_BE; @@ -1793,6 +1797,7 @@ static void add_cs_detail_template_1(MCInst *MI, arm_op_group op_group, if (AlwaysPrintImm0) map_add_implicit_write(MI, MCInst_getOpVal(MI, OpNum)); + ARM_check_safe_inc(); cs_arm_op *Op = ARM_get_detail_op(MI, 0); Op->type = ARM_OP_MEM; Op->mem.base = MCInst_getOpVal(MI, OpNum); @@ -1932,7 +1937,7 @@ void ARM_insert_detail_op_reg_at(MCInst *MI, unsigned index, arm_reg Reg, if (!detail_is_set(MI)) return; - assert(ARM_get_detail(MI)->op_count < MAX_ARM_OPS); + ARM_check_safe_inc(); cs_arm_op op; ARM_setup_op(&op); @@ -1942,7 +1947,6 @@ void ARM_insert_detail_op_reg_at(MCInst *MI, unsigned index, arm_reg Reg, cs_arm_op *ops = ARM_get_detail(MI)->operands; int i = ARM_get_detail(MI)->op_count; - assert(i < MAX_ARM_OPS); for (; i > 0 && i > index; --i) { ops[i] = ops[i - 1]; } @@ -1957,8 +1961,7 @@ void ARM_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val, { if (!detail_is_set(MI)) return; - - assert(ARM_get_detail(MI)->op_count < MAX_ARM_OPS); + ARM_check_safe_inc(); cs_arm_op op; ARM_setup_op(&op); @@ -1968,7 +1971,6 @@ void ARM_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val, cs_arm_op *ops = ARM_get_detail(MI)->operands; int i = ARM_get_detail(MI)->op_count; - assert(i < MAX_ARM_OPS); for (; i > 0 && i > index; --i) { ops[i] = ops[i - 1]; } @@ -1982,6 +1984,7 @@ void ARM_set_detail_op_reg(MCInst *MI, unsigned OpNum, arm_reg Reg) { if (!detail_is_set(MI)) return; + ARM_check_safe_inc(); assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); assert(map_get_op_type(MI, OpNum) == CS_OP_REG); @@ -1998,6 +2001,7 @@ void ARM_set_detail_op_imm(MCInst *MI, unsigned OpNum, arm_op_type ImmType, { if (!detail_is_set(MI)) return; + ARM_check_safe_inc(); assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); assert(map_get_op_type(MI, OpNum) == CS_OP_IMM); assert(ImmType == ARM_OP_IMM || ImmType == ARM_OP_PIMM || @@ -2107,12 +2111,14 @@ void ARM_set_detail_op_sysop(MCInst *MI, int Val, arm_op_type type, { if (!detail_is_set(MI)) return; + ARM_check_safe_inc(); + ARM_get_detail_op(MI, 0)->type = type; switch (type) { default: assert(0 && "Unknown system operand type."); case ARM_OP_SYSREG: - ARM_get_detail_op(MI, 0)->sysop.reg.mclasssysreg = Val; + ARM_get_detail_op(MI, 0)->sysop.reg.mclasssysreg = Val; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange) break; case ARM_OP_BANKEDREG: ARM_get_detail_op(MI, 0)->sysop.reg.bankedreg = Val; @@ -2121,7 +2127,7 @@ void ARM_set_detail_op_sysop(MCInst *MI, int Val, arm_op_type type, case ARM_OP_CPSR: ARM_get_detail_op(MI, 0)->reg = type == ARM_OP_SPSR ? ARM_REG_SPSR : ARM_REG_CPSR; - ARM_get_detail_op(MI, 0)->sysop.psr_bits = Val; + ARM_get_detail_op(MI, 0)->sysop.psr_bits = Val; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange) break; } ARM_get_detail_op(MI, 0)->sysop.sysm = Sysm; @@ -2136,6 +2142,8 @@ void ARM_set_detail_op_float(MCInst *MI, unsigned OpNum, uint64_t Imm) { if (!detail_is_set(MI)) return; + ARM_check_safe_inc(); + ARM_get_detail_op(MI, 0)->type = ARM_OP_FP; ARM_get_detail_op(MI, 0)->fp = ARM_AM_getFPImmFloat(Imm); ARM_inc_op_count(MI); diff --git a/arch/Alpha/AlphaGenDisassemblerTables.inc b/arch/Alpha/AlphaGenDisassemblerTables.inc index a67ae33cb..b00fb1cbf 100644 --- a/arch/Alpha/AlphaGenDisassemblerTables.inc +++ b/arch/Alpha/AlphaGenDisassemblerTables.inc @@ -718,6 +718,7 @@ static bool checkDecoderPredicate(MCInst *Inst, unsigned Idx) { static DecodeStatus fname(DecodeStatus S, unsigned Idx, InsnType insn, MCInst *MI, \ uint64_t Address, const void *Decoder, bool *DecodeComplete) \ { \ + *DecodeComplete = true; \ InsnType tmp; \ switch (Idx) { \ default: /* llvm_unreachable("Invalid index!"); */ \ diff --git a/arch/HPPA/HPPADisassembler.c b/arch/HPPA/HPPADisassembler.c index 7db01d7e9..48a2805a8 100644 --- a/arch/HPPA/HPPADisassembler.c +++ b/arch/HPPA/HPPADisassembler.c @@ -221,8 +221,8 @@ static void push_str_modifier(hppa_ext *hppa, const char *modifier) hppa_modifier *mod = &hppa->modifiers[hppa->mod_num++]; assert(hppa->mod_num <= HPPA_MAX_MODIFIERS_LEN); mod->type = HPPA_MOD_STR; - assert(strlen(modifier) <= HPPA_STR_MODIFIER_LEN); - strcpy(mod->str_mod, modifier); + assert(strlen(modifier) < HPPA_STR_MODIFIER_LEN); + strncpy(mod->str_mod, modifier, HPPA_STR_MODIFIER_LEN - 1); } } @@ -1457,7 +1457,7 @@ static void fill_ldst_w_insn_name(MCInst *MI, uint32_t insn) } } -static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, uint32_t im) +static void fill_ldst_w_mods(uint32_t insn, hppa_ext *hppa_ext, int32_t im) { if (im >= 0) { push_str_modifier(hppa_ext, "mb"); @@ -1470,7 +1470,7 @@ static bool decode_ldst_w(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; uint32_t ext = get_insn_bit(insn, 29); - uint32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); + int32_t im = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); im &= ~3; uint32_t r = get_insn_field(insn, 11, 15); uint32_t b = get_insn_field(insn, 6, 10); @@ -3621,7 +3621,7 @@ static bool decode_load(const cs_struct *ud, MCInst *MI, uint32_t insn) { uint32_t opcode = insn >> 26; if (MODE_IS_HPPA_20(ud->mode)) { - uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); + int32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); if (opcode == HPPA_OP_TYPE_LDWM) { if (d < 0) { push_str_modifier(HPPA_EXT_REF(MI), "mb"); @@ -3644,7 +3644,7 @@ static bool decode_store(const cs_struct *ud, MCInst *MI, uint32_t insn) uint32_t opcode = insn >> 26; CREATE_GR_REG(MI, get_insn_field(insn, 11, 15)); if (MODE_IS_HPPA_20(ud->mode)) { - uint32_t d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); + int d = extract_16(insn, MODE_IS_HPPA_20W(ud->mode)); if (opcode == HPPA_OP_TYPE_STWM) { if (d < 0) { push_str_modifier(HPPA_EXT_REF(MI), "mb"); @@ -3834,4 +3834,4 @@ bool HPPA_getInstruction(csh ud, const uint8_t *code, size_t code_len, return true; } -#endif \ No newline at end of file +#endif diff --git a/arch/M680X/M680XDisassembler.c b/arch/M680X/M680XDisassembler.c index 6e71c465f..92bf5d58c 100644 --- a/arch/M680X/M680XDisassembler.c +++ b/arch/M680X/M680XDisassembler.c @@ -1125,7 +1125,7 @@ static void reg_bits_hdlr(MCInst *MI, m680x_info *info, uint16_t *address) add_insn_group(MI->flat_insn->detail, M680X_GRP_RET); for (bit_index = 0; bit_index < 8; ++bit_index) { - if (reg_bits & (1 << bit_index)) + if (reg_bits & (1 << bit_index) && reg_to_reg_ids) add_reg_operand(info, reg_to_reg_ids[bit_index]); } } @@ -1680,7 +1680,7 @@ static void indexedS16_hdlr(MCInst *MI, m680x_info *info, uint16_t *address) uint16_t offset = 0; read_word(info, &offset, *address); - address += 2; + *address += 2; add_indexed_operand(info, M680X_REG_S, false, 0, M680X_OFFSET_BITS_16, offset, false); @@ -1774,7 +1774,7 @@ static void loop_hdlr(MCInst *MI, m680x_info *info, uint16_t *address) op->type = M680X_OP_RELATIVE; - op->rel.offset = (post_byte & 0x10) ? 0xff00 | rel : rel; + op->rel.offset = (post_byte & 0x10) ? (int16_t) (0xff00 | rel) : rel; op->rel.address = *address + op->rel.offset; diff --git a/arch/M68K/M68KDisassembler.c b/arch/M68K/M68KDisassembler.c index 61d8b3dbf..51c29d465 100644 --- a/arch/M68K/M68KDisassembler.c +++ b/arch/M68K/M68KDisassembler.c @@ -321,13 +321,6 @@ static void get_with_index_address_mode(m68k_info *info, cs_m68k_op* op, uint32_ op->mem.base_reg = M68K_REG_INVALID; op->mem.index_reg = M68K_REG_INVALID; - /* Not sure how to deal with this? - if (EXT_EFFECTIVE_ZERO(extension)) { - strcpy(mode, "0"); - break; - } - */ - op->mem.in_disp = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32(info) : read_imm_16(info)) : 0; op->mem.out_disp = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32(info) : read_imm_16(info)) : 0; diff --git a/arch/MOS65XX/MOS65XXModule.c b/arch/MOS65XX/MOS65XXModule.c index ec89e94c9..841fe3545 100644 --- a/arch/MOS65XX/MOS65XXModule.c +++ b/arch/MOS65XX/MOS65XXModule.c @@ -55,7 +55,7 @@ cs_err MOS65XX_option(cs_struct *handle, cs_opt_type type, size_t value) info->long_m = value & CS_MODE_MOS65XX_65816_LONG_M ? 1 : 0; info->long_x = value & CS_MODE_MOS65XX_65816_LONG_X ? 1 : 0; - handle->mode = (cs_mode)value; + handle->mode = (cs_mode)value; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange) break; case CS_OPT_SYNTAX: switch(value) { diff --git a/arch/PowerPC/PPCMapping.c b/arch/PowerPC/PPCMapping.c index 888db80bc..83e0ed54c 100644 --- a/arch/PowerPC/PPCMapping.c +++ b/arch/PowerPC/PPCMapping.c @@ -401,6 +401,7 @@ static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, return; unsigned Val = MCInst_getOpVal(MI, OpNum) << 2; int32_t Imm = SignExtend32(Val, 32); + PPC_check_safe_inc(); PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; PPC_get_detail_op(MI, 0)->imm = Imm; PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); @@ -424,6 +425,7 @@ static void add_cs_detail_general(MCInst *MI, ppc_op_group op_group, uint64_t Address = MI->address + Imm; if (IS_32BIT(MI->csh->mode)) Address &= 0xffffffff; + PPC_check_safe_inc(); PPC_get_detail_op(MI, 0)->type = PPC_OP_IMM; PPC_get_detail_op(MI, 0)->imm = Address; PPC_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum); @@ -566,6 +568,7 @@ void PPC_set_detail_op_reg(MCInst *MI, unsigned OpNum, ppc_reg Reg) { if (!detail_is_set(MI)) return; + PPC_check_safe_inc(); assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); assert(map_get_op_type(MI, OpNum) == CS_OP_REG); @@ -581,6 +584,7 @@ void PPC_set_detail_op_imm(MCInst *MI, unsigned OpNum, int64_t Imm) { if (!detail_is_set(MI)) return; + PPC_check_safe_inc(); assert(!(map_get_op_type(MI, OpNum) & CS_OP_MEM)); assert(map_get_op_type(MI, OpNum) == CS_OP_IMM); @@ -594,6 +598,7 @@ void PPC_set_mem_access(MCInst *MI, bool status) { if (!detail_is_set(MI)) return; + PPC_check_safe_inc(); if ((!status && !doing_mem(MI)) || (status && doing_mem(MI))) return; // Nothing to do @@ -629,7 +634,7 @@ void PPC_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val, if (!detail_is_set(MI) || !map_fill_detail_ops(MI)) return; - assert(PPC_get_detail(MI)->op_count < PPC_NUM_OPS); + PPC_check_safe_inc(); cs_ppc_op op; PPC_setup_op(&op); diff --git a/arch/RISCV/RISCVGenAsmWriter.inc b/arch/RISCV/RISCVGenAsmWriter.inc index b4dde7583..c8a6aac64 100644 --- a/arch/RISCV/RISCVGenAsmWriter.inc +++ b/arch/RISCV/RISCVGenAsmWriter.inc @@ -1198,7 +1198,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI) // Fragment 0 encoded into 2 bits for 4 unique commands. switch ((uint32_t)((Bits >> 12) & 3)) { - default: CS_ASSERT(0 && "Invalid command number."); + default: + CS_ASSERT(0 && "Invalid command number."); + return; case 0: // DBG_VALUE, DBG_LABEL, BUNDLE, LIFETIME_START, LIFETIME_END, FENTRY_CAL... return; @@ -1226,7 +1228,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI) // Fragment 1 encoded into 2 bits for 3 unique commands. switch ((uint32_t)((Bits >> 14) & 3)) { - default: CS_ASSERT(0 && "Invalid command number."); + default: + CS_ASSERT(0 && "Invalid command number."); + return; case 0: // PseudoCALL, PseudoTAIL, C_J, C_JAL, C_JALR, C_JR return; @@ -1247,7 +1251,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI) // Fragment 2 encoded into 2 bits for 3 unique commands. switch ((uint32_t)((Bits >> 16) & 3)) { - default: CS_ASSERT(0 && "Invalid command number."); + default: + CS_ASSERT(0 && "Invalid command number."); + return; case 0: // PseudoLA, PseudoLI, PseudoLLA, ADD, ADDI, ADDIW, ADDW, AND, ANDI, AUIP... printOperand(MI, 1, O); @@ -1268,7 +1274,9 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI) // Fragment 3 encoded into 2 bits for 4 unique commands. switch ((uint32_t)((Bits >> 18) & 3)) { - default: CS_ASSERT(0 && "Invalid command number."); + default: + CS_ASSERT(0 && "Invalid command number."); + return; case 0: // PseudoLA, PseudoLI, PseudoLLA, AUIPC, C_BEQZ, C_BNEZ, C_LI, C_LUI, C_M... return; @@ -1468,7 +1476,9 @@ getRegisterName(unsigned RegNo, unsigned AltIdx) }; switch(AltIdx) { - default: CS_ASSERT(0 && "Invalid register alt name index!"); + default: + CS_ASSERT(0 && "Invalid register alt name index!"); + return 0; case RISCV_ABIRegAltName: CS_ASSERT(*(AsmStrsABIRegAltName+RegAsmOffsetABIRegAltName[RegNo-1]) && "Invalid alt name index for register!"); diff --git a/arch/RISCV/RISCVGenDisassemblerTables.inc b/arch/RISCV/RISCVGenDisassemblerTables.inc index 2efe6960a..c06f18d65 100644 --- a/arch/RISCV/RISCVGenDisassemblerTables.inc +++ b/arch/RISCV/RISCVGenDisassemblerTables.inc @@ -1736,7 +1736,8 @@ static DecodeStatus fname(const uint8_t DecodeTable[], MCInst *MI,\ NumToSkip |= (*Ptr++) << 8;\ NumToSkip |= (*Ptr++) << 16;\ \ - MCInst TmpMI;\ + MCInst TmpMI = { 0 }; \ + MCInst_Init(&TmpMI, CS_ARCH_RISCV); \ MCInst_setOpcode(&TmpMI, Opc);\ bool DecodeComplete = false;\ S = decoder(S, DecodeIdx, insn, &TmpMI, Address, DisAsm, &DecodeComplete);\ diff --git a/arch/SH/SHDisassembler.c b/arch/SH/SHDisassembler.c index 8f788096b..76d5e4c02 100644 --- a/arch/SH/SHDisassembler.c +++ b/arch/SH/SHDisassembler.c @@ -99,7 +99,7 @@ static void set_groups(cs_detail *detail, int n, ...) va_start(g, n); while (n > 0) { sh_insn_group grp; - grp = va_arg(g, sh_insn_group); + grp = va_arg(g, sh_insn_group); // NOLINT(clang-analyzer-valist.Uninitialized) if (detail) { detail->groups[detail->groups_count] = grp; detail->groups_count++; @@ -934,7 +934,7 @@ static bool op4xxb(uint16_t code, uint64_t address, MCInst *MI, cs_mode mode, rw = write; break; case 2: - insn = SH_INS_JMP; + MCInst_setOpcode(MI, SH_INS_JMP); grp = SH_GRP_JUMP; break; case 8: @@ -1605,6 +1605,9 @@ static bool set_dsp_move_d(sh_info *info, int xy, uint16_t code, cs_mode mode, c int op; static const sh_reg base[] = {SH_REG_DSP_A0, SH_REG_DSP_X0}; switch (xy) { + default: + printf("Invalid xy value %" PRId32 "\n", xy); + return MCDisassembler_Fail; case 0: op = (code >> 2) & 3; dir = 1 - ((code >> 5) & 1); @@ -1762,14 +1765,14 @@ static void set_reg_dsp_write_z(sh_info *info, int pos, int r, } static bool dsp_op_cc_3opr(uint32_t code, sh_info *info, sh_dsp_insn insn, - sh_dsp_insn_type insn2, cs_detail *detail) + sh_dsp_insn insn2, cs_detail *detail) { info->op.operands[2].dsp.cc = (code >> 8) & 3; if (info->op.operands[2].dsp.cc > 0) { info->op.operands[2].dsp.insn = insn; } else { if (insn2 != SH_INS_DSP_INVALID) - info->op.operands[2].dsp.insn = (sh_dsp_insn) insn2; + info->op.operands[2].dsp.insn = insn2; else return MCDisassembler_Fail; } @@ -1914,11 +1917,11 @@ static bool decode_dsp_3op(const uint32_t code, sh_info *info, } case 0x08: return dsp_op_cc_3opr(code, info, - SH_INS_DSP_PSUB, (sh_dsp_insn_type) SH_INS_DSP_PSUBC, + SH_INS_DSP_PSUB, SH_INS_DSP_PSUBC, detail); case 0x09: return dsp_op_cc_3opr(code, info, - SH_INS_DSP_PXOR, (sh_dsp_insn_type) SH_INS_DSP_PWSB, + SH_INS_DSP_PXOR, SH_INS_DSP_PWSB, detail); case 0x0a: switch(sx) { @@ -1958,7 +1961,7 @@ static bool decode_dsp_3op(const uint32_t code, sh_info *info, case 0x0d: return dsp_op_cc_3opr(code, info, SH_INS_DSP_POR, - (sh_dsp_insn_type) SH_INS_DSP_PWAD, + SH_INS_DSP_PWAD, detail); case 0x0e: if (cc == 0) { diff --git a/arch/Sparc/SparcInstPrinter.c b/arch/Sparc/SparcInstPrinter.c index 9ea8129ec..c7d13d4ef 100644 --- a/arch/Sparc/SparcInstPrinter.c +++ b/arch/Sparc/SparcInstPrinter.c @@ -73,7 +73,7 @@ static void set_mem_access(MCInst *MI, bool status) } } -void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) +void Sparc_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci) { if (((cs_struct *)ud)->detail_opt != CS_OPT_ON) return; @@ -81,8 +81,10 @@ void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) // fix up some instructions if (insn->id == SPARC_INS_CASX) { // first op is actually a memop, not regop + uint8_t base = (uint8_t)insn->detail->sparc.operands[0].reg; + memset(&insn->detail->sparc.operands[0], 0, sizeof(cs_sparc_op)); insn->detail->sparc.operands[0].type = SPARC_OP_MEM; - insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg; + insn->detail->sparc.operands[0].mem.base = base; insn->detail->sparc.operands[0].mem.disp = 0; } } @@ -333,7 +335,7 @@ static void printCCOperand(MCInst *MI, int opNum, SStream *O) SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC)); if (MI->csh->detail_opt) - MI->flat_insn->detail->sparc.cc = (sparc_cc)CC; + MI->flat_insn->detail->sparc.cc = (sparc_cc)CC; // NOLINT(clang-analyzer-optin.core.EnumCastOutOfRange) } diff --git a/arch/Sparc/SparcInstPrinter.h b/arch/Sparc/SparcInstPrinter.h index 4cd891ee4..eefc8a584 100644 --- a/arch/Sparc/SparcInstPrinter.h +++ b/arch/Sparc/SparcInstPrinter.h @@ -10,7 +10,7 @@ void Sparc_printInst(MCInst *MI, SStream *O, void *Info); -void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci); +void Sparc_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci); void Sparc_addReg(MCInst *MI, int reg); diff --git a/arch/TMS320C64x/TMS320C64xDisassembler.c b/arch/TMS320C64x/TMS320C64xDisassembler.c index 282918783..fe265a7ac 100644 --- a/arch/TMS320C64x/TMS320C64xDisassembler.c +++ b/arch/TMS320C64x/TMS320C64xDisassembler.c @@ -269,8 +269,8 @@ static DecodeStatus DecodeMemOperandSc(MCInst *Inst, unsigned Val, if((base >= TMS320C64X_REG_A0) && (base <= TMS320C64X_REG_A31)) base = (base - TMS320C64X_REG_A0 + TMS320C64X_REG_B0); - else if((base >= TMS320C64X_REG_B0) && (base <= TMS320C64X_REG_B31)) - base = (base - TMS320C64X_REG_B0 + TMS320C64X_REG_A0); + // base cannot be a B register, because it was ANDed above with 0x1f. + // And the TMS320C64X_REG_B0 > 31 basereg = getReg(GPRegsDecoderTable, base); if (basereg == ~0U) return MCDisassembler_Fail; @@ -292,8 +292,8 @@ static DecodeStatus DecodeMemOperandSc(MCInst *Inst, unsigned Val, case 15: if((offset >= TMS320C64X_REG_A0) && (offset <= TMS320C64X_REG_A31)) offset = (offset - TMS320C64X_REG_A0 + TMS320C64X_REG_B0); - else if((offset >= TMS320C64X_REG_B0) && (offset <= TMS320C64X_REG_B31)) - offset = (offset - TMS320C64X_REG_B0 + TMS320C64X_REG_A0); + // offset cannot be a B register, because it was ANDed above with 0x1f. + // And the TMS320C64X_REG_B0 > 31 offsetreg = getReg(GPRegsDecoderTable, offset); if (offsetreg == ~0U) return MCDisassembler_Fail; diff --git a/arch/TMS320C64x/TMS320C64xInstPrinter.c b/arch/TMS320C64x/TMS320C64xInstPrinter.c index 3e20e2b36..e4b807eb4 100644 --- a/arch/TMS320C64x/TMS320C64xInstPrinter.c +++ b/arch/TMS320C64x/TMS320C64xInstPrinter.c @@ -3,17 +3,6 @@ #ifdef CAPSTONE_HAS_TMS320C64X -#ifdef _MSC_VER -// Disable security warnings for strcpy -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -// Banned API Usage : strcpy is a Banned API as listed in dontuse.h for -// security purposes. -#pragma warning(disable:28719) -#endif - #include #include @@ -33,10 +22,11 @@ static void printMemOperand(MCInst *MI, unsigned OpNo, SStream *O); static void printMemOperand2(MCInst *MI, unsigned OpNo, SStream *O); static void printRegPair(MCInst *MI, unsigned OpNo, SStream *O); -void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) +void TMS320C64x_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci) { SStream ss; - char *p, *p2, tmp[8]; + const char *op_str_ptr, *p2; + char tmp[8] = { 0 }; unsigned int unit = 0; int i; cs_tms320c64x *tms320c64x; @@ -71,50 +61,56 @@ void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) if (tms320c64x->condition.reg != TMS320C64X_REG_INVALID) SStream_concat(&ss, "[%c%s]|", (tms320c64x->condition.zero == 1) ? '!' : '|', cs_reg_name(ud, tms320c64x->condition.reg)); - p = strchr(insn_asm, '\t'); - if (p != NULL) - *p++ = '\0'; + // Sorry for all the fixes below. I don't have time to add more helper SStream functions. + // Before that they messed around with the private buffer of th stream. + // So it is better now. But still not effecient. + op_str_ptr = strchr(SStream_rbuf(insn_asm), '\t'); - SStream_concat0(&ss, insn_asm); - if ((p != NULL) && (((p2 = strchr(p, '[')) != NULL) || ((p2 = strchr(p, '(')) != NULL))) { - while ((p2 > p) && ((*p2 != 'a') && (*p2 != 'b'))) + if ((op_str_ptr != NULL) && (((p2 = strchr(op_str_ptr, '[')) != NULL) || ((p2 = strchr(op_str_ptr, '(')) != NULL))) { + while ((p2 > op_str_ptr) && ((*p2 != 'a') && (*p2 != 'b'))) p2--; - if (p2 == p) { - strcpy(insn_asm, "Invalid!"); + if (p2 == op_str_ptr) { + SStream_Flush(insn_asm, NULL); + SStream_concat0(insn_asm, "Invalid!"); return; } if (*p2 == 'a') - strcpy(tmp, "1T"); + strncpy(tmp, "1T", sizeof(tmp)); else - strcpy(tmp, "2T"); + strncpy(tmp, "2T", sizeof(tmp)); } else { tmp[0] = '\0'; } + SStream mnem_post = { 0 }; + SStream_Init(&mnem_post); switch(tms320c64x->funit.unit) { case TMS320C64X_FUNIT_D: - SStream_concat(&ss, ".D%s%u", tmp, tms320c64x->funit.side); + SStream_concat(&mnem_post, ".D%s%u", tmp, tms320c64x->funit.side); break; case TMS320C64X_FUNIT_L: - SStream_concat(&ss, ".L%s%u", tmp, tms320c64x->funit.side); + SStream_concat(&mnem_post, ".L%s%u", tmp, tms320c64x->funit.side); break; case TMS320C64X_FUNIT_M: - SStream_concat(&ss, ".M%s%u", tmp, tms320c64x->funit.side); + SStream_concat(&mnem_post, ".M%s%u", tmp, tms320c64x->funit.side); break; case TMS320C64X_FUNIT_S: - SStream_concat(&ss, ".S%s%u", tmp, tms320c64x->funit.side); + SStream_concat(&mnem_post, ".S%s%u", tmp, tms320c64x->funit.side); break; } if (tms320c64x->funit.crosspath > 0) - SStream_concat0(&ss, "X"); + SStream_concat0(&mnem_post, "X"); - if (p != NULL) - SStream_concat(&ss, "\t%s", p); + if (op_str_ptr != NULL) { + // There is an op_str + SStream_concat1(&mnem_post, '\t'); + SStream_replc_str(insn_asm, '\t', SStream_rbuf(&mnem_post)); + } if (tms320c64x->parallel != 0) - SStream_concat0(&ss, "\t||"); - - /* insn_asm is a buffer from an SStream, so there should be enough space */ - strcpy(insn_asm, ss.buffer); + SStream_concat0(insn_asm, "\t||"); + SStream_concat0(&ss, SStream_rbuf(insn_asm)); + SStream_Flush(insn_asm, NULL); + SStream_concat0(insn_asm, SStream_rbuf(&ss)); } } diff --git a/arch/TMS320C64x/TMS320C64xInstPrinter.h b/arch/TMS320C64x/TMS320C64xInstPrinter.h index 3a79139e8..bf8318e28 100644 --- a/arch/TMS320C64x/TMS320C64xInstPrinter.h +++ b/arch/TMS320C64x/TMS320C64xInstPrinter.h @@ -10,6 +10,6 @@ void TMS320C64x_printInst(MCInst *MI, SStream *O, void *Info); -void TMS320C64x_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci); +void TMS320C64x_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci); #endif diff --git a/arch/TriCore/TriCoreDisassembler.c b/arch/TriCore/TriCoreDisassembler.c index 40aad5e68..3a06c26d5 100644 --- a/arch/TriCore/TriCoreDisassembler.c +++ b/arch/TriCore/TriCoreDisassembler.c @@ -766,13 +766,13 @@ static DecodeStatus DecodeRRInstruction(MCInst *Inst, unsigned Insn, status = DecodeRegisterClass(Inst, s2, &desc->OpInfo[1], Decoder); break; + } default: status = DecodeRegisterClass(Inst, s1, &desc->OpInfo[1], Decoder); } - if (status != MCDisassembler_Success) - return status; - } + if (status != MCDisassembler_Success) + return status; } } diff --git a/arch/TriCore/TriCoreInstPrinter.c b/arch/TriCore/TriCoreInstPrinter.c index 342ee8956..225d9b611 100644 --- a/arch/TriCore/TriCoreInstPrinter.c +++ b/arch/TriCore/TriCoreInstPrinter.c @@ -277,8 +277,8 @@ static void printDisp24Imm(MCInst *MI, int OpNum, SStream *O) case TRICORE_JA_b: case TRICORE_JLA_b: // = {disp24[23:20], 7’b0000000, disp24[19:0], 1’b0}; - res = ((wrapping_u32(disp) & 0xf00000) << 28) | - ((wrapping_u32(disp) & 0xfffff) << 1); + res = ((wrapping_u32(disp) & 0xf00000ULL) << 28) | + ((wrapping_u32(disp) & 0xfffffULL) << 1); break; case TRICORE_J_b: case TRICORE_JL_b: @@ -346,7 +346,7 @@ static void printDisp8Imm(MCInst *MI, int OpNum, SStream *O) int64_t res = 0; switch (MCInst_getOpcode(MI)) { case TRICORE_CALL_sb: - disp = DISP1(8); + res = DISP1(8); break; case TRICORE_J_sb: case TRICORE_JNZ_sb: diff --git a/arch/WASM/WASMDisassembler.c b/arch/WASM/WASMDisassembler.c index a05ee0c75..e04297dac 100644 --- a/arch/WASM/WASMDisassembler.c +++ b/arch/WASM/WASMDisassembler.c @@ -459,9 +459,6 @@ static bool read_memoryimmediate(const uint8_t *code, size_t code_len, uint16_t len = tmp; data[1] = get_varuint32(&code[len], code_len - len, &tmp); - if (len == -1) { - return false; - } if (MI->flat_insn->detail) { MI->flat_insn->detail->wasm.operands[1].type = WASM_OP_VARUINT32; diff --git a/arch/X86/X86ATTInstPrinter.c b/arch/X86/X86ATTInstPrinter.c index 6bff62062..9840ed0bd 100644 --- a/arch/X86/X86ATTInstPrinter.c +++ b/arch/X86/X86ATTInstPrinter.c @@ -582,8 +582,9 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) int64_t imm = MCOperand_getImm(Op); uint8_t opsize = X86_immediate_size(MCInst_getOpcode(MI), &encsize); - if (opsize == 1) // print 1 byte immediate in positive form + if (opsize == 1) { // print 1 byte immediate in positive form imm = imm & 0xff; + } switch(MI->flat_insn->id) { default: @@ -598,9 +599,9 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O) switch(opsize) { default: break; - case 1: - imm &= 0xff; - break; + // case 1 cannot occur because above imm was ANDed with 0xff, + // making it effectively always positive. + // So this switch is never reached. case 2: imm &= 0xffff; break; diff --git a/arch/X86/X86Mapping.c b/arch/X86/X86Mapping.c index 46ecfcb77..b0935892c 100644 --- a/arch/X86/X86Mapping.c +++ b/arch/X86/X86Mapping.c @@ -2246,7 +2246,7 @@ unsigned short X86_register_map(unsigned short id) /// The post-printer function. Used to fixup flaws in the disassembly information /// of certain instructions. -void X86_postprinter(csh handle, cs_insn *insn, char *mnem, MCInst *mci) { +void X86_postprinter(csh handle, cs_insn *insn, SStream *mnem, MCInst *mci) { if (!insn || !insn->detail) { return; } diff --git a/arch/X86/X86Mapping.h b/arch/X86/X86Mapping.h index 933f208df..f9a50513a 100644 --- a/arch/X86/X86Mapping.h +++ b/arch/X86/X86Mapping.h @@ -91,6 +91,6 @@ unsigned short X86_register_map(unsigned short id); unsigned int find_insn(unsigned int id); -void X86_postprinter(csh handle, cs_insn *insn, char *mnem, MCInst *mci); +void X86_postprinter(csh handle, cs_insn *insn, SStream *mnem, MCInst *mci); #endif diff --git a/arch/XCore/XCoreInstPrinter.c b/arch/XCore/XCoreInstPrinter.c index 4a02c2bed..4a1e4ed18 100644 --- a/arch/XCore/XCoreInstPrinter.c +++ b/arch/XCore/XCoreInstPrinter.c @@ -16,11 +16,6 @@ #ifdef CAPSTONE_HAS_XCORE -#ifdef _MSC_VER -#pragma warning(disable : 4996) // disable MSVC's warning on strcpy() -#pragma warning(disable : 28719) // disable MSVC's warning on strcpy() -#endif - #include #include #include @@ -36,7 +31,7 @@ static const char *getRegisterName(unsigned RegNo); -void XCore_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) +void XCore_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci) { /* if (((cs_struct *)ud)->detail != CS_OPT_ON) @@ -51,7 +46,7 @@ void XCore_insn_extract(MCInst *MI, const char *code) char *p, *p2; char tmp[128]; - strcpy(tmp, code); // safe because code is way shorter than 128 bytes + strncpy(tmp, code, sizeof(tmp) - 1); // safe because code is way shorter than 128 bytes // find the first space p = strchr(tmp, ' '); @@ -167,8 +162,10 @@ static void set_mem_access(MCInst *MI, bool status, int reg) } else { // the last op should be the memory base MI->flat_insn->detail->xcore.op_count--; + uint8_t base = MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].reg; + memset(&MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count], 0, sizeof(cs_xcore_op)); MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].type = XCORE_OP_MEM; - MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.base = (uint8_t)MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].reg; + MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.base = base; MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.index = XCORE_REG_INVALID; MI->flat_insn->detail->xcore.operands[MI->flat_insn->detail->xcore.op_count].mem.disp = 0; if (reg > 0) diff --git a/arch/XCore/XCoreInstPrinter.h b/arch/XCore/XCoreInstPrinter.h index f9d000131..4d5a5e0a0 100644 --- a/arch/XCore/XCoreInstPrinter.h +++ b/arch/XCore/XCoreInstPrinter.h @@ -10,7 +10,7 @@ void XCore_printInst(MCInst *MI, SStream *O, void *Info); -void XCore_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci); +void XCore_post_printer(csh ud, cs_insn *insn, SStream *insn_asm, MCInst *mci); // extract details from assembly code @code void XCore_insn_extract(MCInst *MI, const char *code); diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py index ce3d02694..4e2f765ac 100755 --- a/bindings/python/capstone/__init__.py +++ b/bindings/python/capstone/__init__.py @@ -1129,8 +1129,8 @@ class Cs(object): status = _cs.cs_option(self.csh, opt_type, opt_value) if status != CS_ERR_OK: raise CsError(status) - if opt_type == CS_OPT_DETAIL: - self._detail = opt_value == CS_OPT_ON + if opt_type == CS_OPT_DETAIL or opt_type == CS_OPT_DETAIL_REAL: + self._detail = (opt_value & CS_OPT_ON) != 0 elif opt_type == CS_OPT_SKIPDATA: self._skipdata = opt_value == CS_OPT_ON elif opt_type == CS_OPT_UNSIGNED: diff --git a/bindings/python/capstone/arm_const.py b/bindings/python/capstone/arm_const.py index dbc09e3bd..cd5da0b6c 100644 --- a/bindings/python/capstone/arm_const.py +++ b/bindings/python/capstone/arm_const.py @@ -21,6 +21,8 @@ ARMCC_UNDEF = 15 ARMVCC_None = 0 ARMVCC_Then = 1 ARMVCC_Else = 2 + +ARM_PredBlockMaskInvalid = 0 ARM_T = 0x8 ARM_TT = 0x4 ARM_TE = 0xc diff --git a/bindings/python/capstone/hppa_const.py b/bindings/python/capstone/hppa_const.py index e5bca1544..789a99a97 100644 --- a/bindings/python/capstone/hppa_const.py +++ b/bindings/python/capstone/hppa_const.py @@ -1,6 +1,5 @@ from . import CS_OP_INVALID, CS_OP_REG, CS_OP_IMM, CS_OP_FP, CS_OP_PRED, CS_OP_SPECIAL, CS_OP_MEM, CS_OP_MEM_REG, CS_OP_MEM_IMM, UINT16_MAX, UINT8_MAX # For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [hppa_const.py] -HPPA_MAX_OPS = 5 HPPA_STR_MODIFIER_LEN = 8 HPPA_MAX_MODIFIERS_LEN = 5 diff --git a/bindings/python/capstone/sh_const.py b/bindings/python/capstone/sh_const.py index 3d7faf4e3..d604f5c1b 100644 --- a/bindings/python/capstone/sh_const.py +++ b/bindings/python/capstone/sh_const.py @@ -142,9 +142,6 @@ SH_OP_MEM_PCR = 8 SH_OP_MEM_TBR_DISP = 9 SH_INS_DSP_INVALID = 0 -SH_INS_DSP_DOUBLE = 1 -SH_INS_DSP_SINGLE = 2 -SH_INS_DSP_PARALLEL = 3 SH_INS_DSP_NOP = 1 SH_INS_DSP_MOV = 2 SH_INS_DSP_PSHL = 3 diff --git a/bindings/python/capstone/systemz_const.py b/bindings/python/capstone/systemz_const.py index 5a72b5878..8ce8c230d 100644 --- a/bindings/python/capstone/systemz_const.py +++ b/bindings/python/capstone/systemz_const.py @@ -15,6 +15,7 @@ SYSTEMZ_CC_NL = 10 SYSTEMZ_CC_LE = 11 SYSTEMZ_CC_NH = 12 SYSTEMZ_CC_NO = 13 +SYSTEMZ_CC_INVALID = 14 SYSTEMZ_OP_INVALID = CS_OP_INVALID SYSTEMZ_OP_REG = CS_OP_REG SYSTEMZ_OP_IMM = CS_OP_IMM diff --git a/bindings/python/capstone/tricore_const.py b/bindings/python/capstone/tricore_const.py index cb0fdf709..d0672f075 100644 --- a/bindings/python/capstone/tricore_const.py +++ b/bindings/python/capstone/tricore_const.py @@ -4,7 +4,6 @@ TRICORE_OP_INVALID = CS_OP_INVALID TRICORE_OP_REG = CS_OP_REG TRICORE_OP_IMM = CS_OP_IMM TRICORE_OP_MEM = CS_OP_MEM -TRICORE_OP_COUNT = 8 TRICORE_REG_INVALID = 0 TRICORE_REG_FCX = 1 diff --git a/cs.c b/cs.c index 3ebe39007..405f6aed1 100644 --- a/cs.c +++ b/cs.c @@ -1,9 +1,7 @@ /* Capstone Disassembly Engine */ /* By Nguyen Anh Quynh , 2013-2019 */ -#ifdef _MSC_VER -#pragma warning(disable:4996) // disable MSVC's warning on strcpy() -#pragma warning(disable:28719) // disable MSVC's warning on strcpy() -#endif + +#include "SStream.h" #if defined(CAPSTONE_HAS_OSXKERNEL) #include #include @@ -866,35 +864,14 @@ static int str_replace(char *result, char *target, const char *str1, char *str2) } #endif -/// The asm string sometimes has a leading space or tab. -/// Here we remove it. -static void fixup_asm_string(char *asm_str) { - if (!asm_str) { - return; - } - int i = 0; - int k = 0; - bool text_reached = (asm_str[0] != ' ' && asm_str[0] != '\t'); - while (asm_str[i]) { - if (!text_reached && (asm_str[i] == ' ' || asm_str[i] == '\t')) { - ++i; - text_reached = true; - continue; - } - asm_str[k] = asm_str[i]; - ++k, ++i; - } - asm_str[k] = '\0'; -} - // fill insn with mnemonic & operands info -static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci, +static void fill_insn(struct cs_struct *handle, cs_insn *insn, SStream *OS, MCInst *mci, PostPrinter_t postprinter, const uint8_t *code) { #ifndef CAPSTONE_DIET - char *sp, *mnem; + char *sp; #endif - fixup_asm_string(buffer); + SStream_trimls(OS); uint16_t copy_size = MIN(sizeof(insn->bytes), insn->size); // fill the instruction bytes. @@ -909,23 +886,17 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI // post printer handles some corner cases (hacky) if (postprinter) - postprinter((csh)handle, insn, buffer, mci); + postprinter((csh)handle, insn, OS, mci); #ifndef CAPSTONE_DIET - mnem = insn->mnemonic; - // memset(mnem, 0, CS_MNEMONIC_SIZE); - for (sp = buffer; *sp; sp++) { - if (*sp == ' '|| *sp == '\t') - break; + memset(insn->mnemonic, '\0', sizeof(insn->mnemonic)); + memset(insn->op_str, '\0', sizeof(insn->op_str)); + SStream_extract_mnem_opstr(OS, insn->mnemonic, sizeof(insn->mnemonic), insn->op_str, sizeof(insn->op_str)); + for (sp = insn->mnemonic; *sp; sp++) { if (*sp == '|') // lock|rep prefix for x86 *sp = ' '; - // copy to @mnemonic - *mnem = *sp; - mnem++; } - *mnem = '\0'; - // we might have customized mnemonic if (handle->mnem_list) { struct insn_mnem *tmp = handle->mnem_list; @@ -944,17 +915,6 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI tmp = tmp->next; } } - - // copy @op_str - if (*sp) { - // find the next non-space char - sp++; - for (; ((*sp == ' ') || (*sp == '\t')); sp++); - strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1); - insn->op_str[sizeof(insn->op_str) - 1] = '\0'; - } else - insn->op_str[0] = '\0'; - #endif } @@ -1279,7 +1239,7 @@ size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64 handle->insn_id(handle, insn_cache, mci.Opcode); handle->printer(&mci, &ss, handle->printer_info); - fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer); + fill_insn(handle, insn_cache, &ss, &mci, handle->post_printer, buffer); // adjust for pseudo opcode (X86) if (handle->arch == CS_ARCH_X86 && insn_cache->id != X86_INS_VCMP) @@ -1485,7 +1445,7 @@ bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size, handle->printer(&mci, &ss, handle->printer_info); - fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, *code); + fill_insn(handle, insn, &ss, &mci, handle->post_printer, *code); // adjust for pseudo opcode (X86) if (handle->arch == CS_ARCH_X86) diff --git a/cs_priv.h b/cs_priv.h index c4866ddfd..954acaed9 100644 --- a/cs_priv.h +++ b/cs_priv.h @@ -16,7 +16,7 @@ typedef void (*Printer_t)(MCInst *MI, SStream *OS, void *info); // function to be called after Printer_t // this is the best time to gather insn's characteristics -typedef void (*PostPrinter_t)(csh handle, cs_insn *, char *mnem, MCInst *mci); +typedef void (*PostPrinter_t)(csh handle, cs_insn *, SStream *mnem, MCInst *mci); typedef bool (*Disasm_t)(csh handle, const uint8_t *code, size_t code_len, MCInst *instr, uint16_t *size, uint64_t address, void *info); diff --git a/cstool/cstool.c b/cstool/cstool.c index 48327d9d2..78312b99d 100644 --- a/cstool/cstool.c +++ b/cstool/cstool.c @@ -347,7 +347,6 @@ static void usage(char *prog) printf(" -a Print Capstone register alias (if any). Otherwise LLVM register names are emitted.\n"); printf(" -s decode in SKIPDATA mode\n"); printf(" -u show immediates as unsigned\n"); - printf(" -f Dev fuzzing: Disassembles to 0xffffffff.\n\n"); printf(" -v show version & Capstone core build info\n\n"); } @@ -439,53 +438,6 @@ static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins) printf("\n"); } -static uint32_t read_le(uint8_t *buf, size_t size) { - uint32_t res = 0; - for (size_t i = 0, j = size - 1; i < size; ++i, --j) { - res |= buf[i] << j * 8; - } - return res; -} - -static void to_buf(uint32_t num, uint8_t *buf) { - for (size_t i = 0, j = 3; i < 4; ++i, --j) { - buf[i] = (num >> j) & 0xff; - } -} - -static void run_dev_fuzz(csh handle, uint8_t *bytes, uint32_t size) { - uint8_t buf[4] = {0}; - uint32_t bytes_as_num = read_le(bytes, size); - uint32_t address = 0xffffffff; - - printf("Run dev fuzz\n"); - printf("Start: 0x%" PRIx32 "\n", bytes_as_num); - printf("End: 0xffffffff\n" - "Address: 0x%" PRIx32 "\n", address); - - cs_insn *insn; - while (true) { - printf("\rProgress: 0x%08x\t\t", bytes_as_num); - fflush(stdout); - cs_disasm(handle, buf, 4, address, 0, &insn); - if (insn && insn->detail) - free(insn->detail); - free(insn); - bytes_as_num++; - to_buf(bytes_as_num, buf); - if (bytes_as_num == 0xffffffff) { - printf("\rProgress: 0x%08x\t\t", bytes_as_num); - fflush(stdout); - cs_disasm(handle, (uint8_t*)&buf, 4, address, 0, &insn); - if (insn && insn->detail) - free(insn->detail); - free(insn); - printf("\n"); - return; - } - } -} - static cs_mode find_additional_modes(const char *input, cs_arch arch) { if (!input) { return 0; @@ -541,7 +493,6 @@ int main(int argc, char **argv) bool skipdata = false; bool custom_reg_alias = false; bool set_real_detail = false; - bool dev_fuzz = false; int args_left; while ((c = getopt (argc, argv, "rasudhvf")) != -1) { @@ -659,9 +610,6 @@ int main(int argc, char **argv) printf("\n"); return 0; - case 'f': - dev_fuzz = true; - break; case 'h': usage(argv[0]); return 0; @@ -745,13 +693,7 @@ int main(int argc, char **argv) } if (set_real_detail) { - cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL); - } - - if (dev_fuzz) { - run_dev_fuzz(handle, assembly, size); - cs_close(&handle); - return 0; + cs_option(handle, CS_OPT_DETAIL, (CS_OPT_DETAIL_REAL | CS_OPT_ON)); } count = cs_disasm(handle, assembly, size, address, 0, &insn); diff --git a/cstool/cstool_aarch64.c b/cstool/cstool_aarch64.c index 294193a58..3b6f194c1 100644 --- a/cstool/cstool_aarch64.c +++ b/cstool/cstool_aarch64.c @@ -28,6 +28,7 @@ void print_insn_detail_aarch64(csh handle, cs_insn *ins) cs_aarch64_op *op = &(aarch64->operands[i]); switch(op->type) { default: + printf("\t\tOperand type %" PRId32 " not handled\n", op->type); break; case AARCH64_OP_REG: printf("\t\toperands[%u].type: REG = %s%s\n", i, cs_reg_name(handle, op->reg), op->is_vreg ? " (vreg)" : ""); diff --git a/cstool/cstool_arm.c b/cstool/cstool_arm.c index 439d11063..134a36398 100644 --- a/cstool/cstool_arm.c +++ b/cstool/cstool_arm.c @@ -82,11 +82,12 @@ void print_insn_detail_arm(csh handle, cs_insn *ins) printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask); break; case ARM_OP_BANKEDREG: - // FIXME: Printing the name is currenliy not supported if the encodings overlap + // FIXME: Printing the name is currently not supported if the encodings overlap // with system registers. printf("\t\toperands[%u].type: BANKEDREG = %" PRIu32 "\n", i, (uint32_t) op->sysop.reg.bankedreg); if (op->sysop.msr_mask != UINT8_MAX) printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask); + break; case ARM_OP_SPSR: case ARM_OP_CPSR: { const char type = op->type == ARM_OP_SPSR ? 'S' : 'C'; diff --git a/cstool/cstool_systemz.c b/cstool/cstool_systemz.c index 90ed79877..0aae05cce 100644 --- a/cstool/cstool_systemz.c +++ b/cstool/cstool_systemz.c @@ -39,11 +39,7 @@ void print_insn_detail_systemz(csh handle, cs_insn *ins) printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); if (op->mem.length != 0) { - if (op->mem.am == SYSTEMZ_AM_BDL) { - printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length); - } else { - printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length); - } + printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length); } printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); switch(op->mem.am) { diff --git a/cstool/cstool_x86.c b/cstool/cstool_x86.c index bba46d848..fa1ded3b5 100644 --- a/cstool/cstool_x86.c +++ b/cstool/cstool_x86.c @@ -240,6 +240,10 @@ void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins) printf("\timm_count: %u\n", count); for (i = 1; i < count + 1; i++) { int index = cs_op_index(ud, ins, X86_OP_IMM, i); + if (index < 0) { + printf("Operand was not found!\n"); + break; + } printf("\t\timms[%u]: 0x%" PRIx64 "\n", i, x86->operands[index].imm); } } diff --git a/docs/cs_v6_release_guide.md b/docs/cs_v6_release_guide.md index 7d1e732c8..24df9a6e1 100644 --- a/docs/cs_v6_release_guide.md +++ b/docs/cs_v6_release_guide.md @@ -338,7 +338,7 @@ Additionally, you can now choose between the alias details and the real details. If you always want the real instruction detail decoded (also for alias instructions), you can enable the option with ``` -cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL); +cs_option(handle, CS_OPT_DETAIL, CS_OPT_DETAIL_REAL | CS_OPT_ON); ``` For the `cstool` you can enable it with the `-r` flag. diff --git a/include/capstone/aarch64.h b/include/capstone/aarch64.h index 83fc7faf3..cae337a80 100644 --- a/include/capstone/aarch64.h +++ b/include/capstone/aarch64.h @@ -2852,7 +2852,7 @@ typedef struct { cs_ac_type mem_acc; ///< CGI memory access according to mayLoad and mayStore } aarch64_suppl_info; -#define MAX_AARCH64_OPS 8 +#define NUM_AARCH64_OPS 16 /// Instruction structure typedef struct cs_aarch64 { @@ -2865,7 +2865,7 @@ typedef struct cs_aarch64 { /// or 0 when instruction has no operand. uint8_t op_count; - cs_aarch64_op operands[MAX_AARCH64_OPS]; ///< operands for this instruction. + cs_aarch64_op operands[NUM_AARCH64_OPS]; ///< operands for this instruction. } cs_aarch64; /// AArch64 instruction diff --git a/include/capstone/alpha.h b/include/capstone/alpha.h index 839ce02b4..3d36cba38 100644 --- a/include/capstone/alpha.h +++ b/include/capstone/alpha.h @@ -19,7 +19,7 @@ extern "C" { #pragma warning(disable : 4201) #endif -#define MAX_ALPHA_OPS 3 +#define NUM_ALPHA_OPS 3 //> Operand type for instruction's operands typedef enum alpha_op_type { @@ -43,7 +43,7 @@ typedef struct cs_alpha { // Number of operands of this instruction, // or 0 when instruction has no operand. uint8_t op_count; - cs_alpha_op operands[MAX_ALPHA_OPS]; // operands for this instruction. + cs_alpha_op operands[NUM_ALPHA_OPS]; // operands for this instruction. } cs_alpha; diff --git a/include/capstone/arm.h b/include/capstone/arm.h index 3824da447..24430c271 100644 --- a/include/capstone/arm.h +++ b/include/capstone/arm.h @@ -125,6 +125,7 @@ typedef enum VPTCodes { /// Txy = xy10 /// Txyz = xyz1 typedef enum PredBlockMask { + ARM_PredBlockMaskInvalid = 0, ARM_T = 0x8, // 0b1000 ARM_TT = 0x4, // 0b0100 ARM_TE = 0xc, // 0b1100 @@ -890,7 +891,7 @@ typedef struct cs_arm_op { int8_t neon_lane; } cs_arm_op; -#define MAX_ARM_OPS 36 +#define NUM_ARM_OPS 36 /// Instruction structure typedef struct cs_arm { @@ -910,7 +911,7 @@ typedef struct cs_arm { /// or 0 when instruction has no operand. uint8_t op_count; - cs_arm_op operands[MAX_ARM_OPS]; ///< operands for this instruction. + cs_arm_op operands[NUM_ARM_OPS]; ///< operands for this instruction. } cs_arm; /// ARM instruction diff --git a/include/capstone/hppa.h b/include/capstone/hppa.h index fffb6ef73..097126d91 100644 --- a/include/capstone/hppa.h +++ b/include/capstone/hppa.h @@ -8,7 +8,7 @@ extern "C" { #include "cs_operand.h" #include "platform.h" -#define HPPA_MAX_OPS 5 +#define NUM_HPPA_OPS 5 #define HPPA_STR_MODIFIER_LEN 8 #define HPPA_MAX_MODIFIERS_LEN 5 @@ -492,7 +492,7 @@ typedef struct cs_hppa { // Number of operands of this instruction, // or 0 when instruction has no operand. uint8_t op_count; - cs_hppa_op operands[HPPA_MAX_OPS]; ///< operands for hppa instruction. + cs_hppa_op operands[NUM_HPPA_OPS]; ///< operands for hppa instruction. } cs_hppa; /// HPPA modifiers type. Can be string (most of them) or int (uid, sop) diff --git a/include/capstone/loongarch.h b/include/capstone/loongarch.h index f75e5ca18..6eb977adf 100644 --- a/include/capstone/loongarch.h +++ b/include/capstone/loongarch.h @@ -177,6 +177,8 @@ typedef struct { memory_access; ///< Memory access (none/read/write/read+write) } loongarch_suppl_info; +#define NUM_LOONGARCH_OPS 8 + /// Instruction structure typedef struct cs_loongarch { /// The instruction format. Can be use to determine the bit encoding of the instruction. @@ -185,7 +187,7 @@ typedef struct cs_loongarch { /// Number of operands of this instruction, /// or 0 when instruction has no operand. uint8_t op_count; - cs_loongarch_op operands[8]; ///< operands for this instruction. + cs_loongarch_op operands[NUM_LOONGARCH_OPS]; ///< operands for this instruction. } cs_loongarch; /// LoongArch registers diff --git a/include/capstone/mips.h b/include/capstone/mips.h index 5ab203c7d..c776d3ac1 100644 --- a/include/capstone/mips.h +++ b/include/capstone/mips.h @@ -696,12 +696,14 @@ typedef struct cs_mips_op { uint8_t access; } cs_mips_op; +#define NUM_MIPS_OPS 10 + /// Instruction structure typedef struct cs_mips { /// Number of operands of this instruction, /// or 0 when instruction has no operand. uint8_t op_count; - cs_mips_op operands[10]; ///< operands for this instruction. + cs_mips_op operands[NUM_MIPS_OPS]; ///< operands for this instruction. } cs_mips; /// MIPS instruction diff --git a/include/capstone/riscv.h b/include/capstone/riscv.h index bd8d563b3..09b8fedd3 100644 --- a/include/capstone/riscv.h +++ b/include/capstone/riscv.h @@ -49,6 +49,8 @@ typedef struct cs_riscv_op { uint8_t access; ///< How is this operand accessed? (READ, WRITE or READ|WRITE) } cs_riscv_op; +#define NUM_RISCV_OPS 8 + // Instruction structure typedef struct cs_riscv { // Does this instruction need effective address or not. @@ -56,7 +58,7 @@ typedef struct cs_riscv { // Number of operands of this instruction, // or 0 when instruction has no operand. uint8_t op_count; - cs_riscv_op operands[8]; // operands for this instruction. + cs_riscv_op operands[NUM_RISCV_OPS]; // operands for this instruction. } cs_riscv; //> RISCV registers diff --git a/include/capstone/sh.h b/include/capstone/sh.h index 688de0715..7f81313f1 100644 --- a/include/capstone/sh.h +++ b/include/capstone/sh.h @@ -182,15 +182,8 @@ typedef struct sh_op_mem { uint32_t disp; /// <= displacement } sh_op_mem; -// SH-DSP instcutions define -typedef enum sh_dsp_insn_type { - SH_INS_DSP_INVALID, - SH_INS_DSP_DOUBLE, - SH_INS_DSP_SINGLE, - SH_INS_DSP_PARALLEL, -} sh_dsp_insn_type; - typedef enum sh_dsp_insn { + SH_INS_DSP_INVALID = 0, SH_INS_DSP_NOP = 1, SH_INS_DSP_MOV, SH_INS_DSP_PSHL, diff --git a/include/capstone/tricore.h b/include/capstone/tricore.h index 4cf22f59d..0e9c9daac 100644 --- a/include/capstone/tricore.h +++ b/include/capstone/tricore.h @@ -47,13 +47,13 @@ typedef struct cs_tricore_op { uint8_t access; ///< How is this operand accessed? (READ, WRITE or READ|WRITE) } cs_tricore_op; -#define TRICORE_OP_COUNT 8 +#define NUM_TRICORE_OPS 8 /// Instruction structure typedef struct cs_tricore { uint8_t op_count; ///< number of operands of this instruction. cs_tricore_op - operands[TRICORE_OP_COUNT]; ///< operands for this instruction. + operands[NUM_TRICORE_OPS]; ///< operands for this instruction. /// TODO: Mark the modified flags register in td files and regenerate inc files bool update_flags; ///< whether the flags register is updated. } cs_tricore; diff --git a/suite/auto-sync/src/autosync/Tests/test_aarch64_header.h b/suite/auto-sync/src/autosync/Tests/test_aarch64_header.h index a98b290d7..2f223ec5e 100644 --- a/suite/auto-sync/src/autosync/Tests/test_aarch64_header.h +++ b/suite/auto-sync/src/autosync/Tests/test_aarch64_header.h @@ -37,7 +37,7 @@ typedef enum aarch64_op_type_upper { AARCH64_OP_SYSALIASIII, // Comment } aarch64_op_type_upper; -#define MAX_AARCH64_OPS 8 +#define NUM_AARCH64_OPS 8 /// Instruction structure typedef struct cs_aarch64 { @@ -50,7 +50,7 @@ typedef struct cs_aarch64 { /// or 0 when instruction has no operand. uint8_t op_count; - cs_aarch64_op operands[MAX_AARCH64_OPS]; ///< operands for this instruction. + cs_aarch64_op operands[NUM_AARCH64_OPS]; ///< operands for this instruction. } cs_aarch64; #endif diff --git a/suite/cstest/src/test_case.c b/suite/cstest/src/test_case.c index cd1ece6bb..61d4a0823 100644 --- a/suite/cstest/src/test_case.c +++ b/suite/cstest/src/test_case.c @@ -61,17 +61,18 @@ char *test_input_stringify(const TestInput *test_input, const char *postfix) char *byte_seq = byte_seq_to_str(test_input->bytes, test_input->bytes_count); if (!msg) { + cs_mem_free(byte_seq); return NULL; } char opt_seq[128] = { 0 }; - append_to_str(opt_seq, sizeof(opt_seq), "["); + str_append_no_realloc(opt_seq, sizeof(opt_seq), "["); for (size_t i = 0; i < test_input->options_count; ++i) { - append_to_str(opt_seq, sizeof(opt_seq), test_input->options[i]); + str_append_no_realloc(opt_seq, sizeof(opt_seq), test_input->options[i]); if (i < test_input->options_count - 1) { - append_to_str(opt_seq, sizeof(opt_seq), ", "); + str_append_no_realloc(opt_seq, sizeof(opt_seq), ", "); } } - append_to_str(opt_seq, sizeof(opt_seq), "]"); + str_append_no_realloc(opt_seq, sizeof(opt_seq), "]"); cs_snprintf(msg, msg_len, "%sTestInput { arch: %s, options: %s, addr: 0x%" PRIx64 ", bytes: %s }", @@ -210,12 +211,12 @@ void test_expected_compare(csh *handle, TestExpected *expected, cs_insn *insns, // Either all in op_str or split in mnemonic and op_str char asm_text[256] = { 0 }; if (insns[i].mnemonic[0] != '\0') { - append_to_str(asm_text, sizeof(asm_text), + str_append_no_realloc(asm_text, sizeof(asm_text), insns[i].mnemonic); - append_to_str(asm_text, sizeof(asm_text), " "); + str_append_no_realloc(asm_text, sizeof(asm_text), " "); } if (insns[i].op_str[0] != '\0') { - append_to_str(asm_text, sizeof(asm_text), + str_append_no_realloc(asm_text, sizeof(asm_text), insns[i].op_str); } if (!compare_asm_text(asm_text, expec_data->asm_text, diff --git a/suite/cstest/src/test_detail_x86.c b/suite/cstest/src/test_detail_x86.c index b7a383651..1b66f1c05 100644 --- a/suite/cstest/src/test_detail_x86.c +++ b/suite/cstest/src/test_detail_x86.c @@ -79,7 +79,7 @@ TestDetailX86 *test_detail_x86_clone(TestDetailX86 *detail) clone->eflags = detail->eflags ? cs_mem_calloc(sizeof(char *), detail->eflags_count) : NULL; - for (size_t i = 0; i < detail->eflags_count; ++i) { + for (size_t i = 0; clone->eflags && i < detail->eflags_count; ++i) { clone->eflags[i] = detail->eflags[i] ? strdup(detail->eflags[i]) : NULL; } @@ -89,7 +89,7 @@ TestDetailX86 *test_detail_x86_clone(TestDetailX86 *detail) detail->fpu_flags ? cs_mem_calloc(sizeof(char *), detail->fpu_flags_count) : NULL; - for (size_t i = 0; i < detail->fpu_flags_count; ++i) { + for (size_t i = 0; clone->fpu_flags && i < detail->fpu_flags_count; ++i) { clone->fpu_flags[i] = detail->fpu_flags[i] ? strdup(detail->fpu_flags[i]) : NULL; diff --git a/suite/cstest/src/test_run.c b/suite/cstest/src/test_run.c index e38590846..13c921ac9 100644 --- a/suite/cstest/src/test_run.c +++ b/suite/cstest/src/test_run.c @@ -175,13 +175,7 @@ static bool open_cs_handle(UnitTestState *ustate) } else { ustate->arch_bits = 32; } - if (err != CS_ERR_OK) { - goto option_error; - } - if (err != CS_ERR_OK) { - goto option_error; - } for (size_t i = 0; i < options_set; ++i) { err = cs_option(ustate->handle, options[i].type, options[i].val); @@ -299,6 +293,8 @@ static void eval_test_cases(TestFile **test_files, TestRunStats *stats) // Use private function here, because the API takes only constant tables. int failed_tests = _cmocka_run_group_tests( "All test cases", utest_table, stats->tc_total, NULL, NULL); + assert(failed_tests >= 0 && "Faulty return value"); + for (size_t i = 0; i < stats->tc_total; ++i) { UnitTestState *ustate = utest_table[i].initial_state; if (!ustate) { diff --git a/suite/fuzz/platform.c b/suite/fuzz/platform.c index ac4d8db94..20f645465 100644 --- a/suite/fuzz/platform.c +++ b/suite/fuzz/platform.c @@ -401,7 +401,11 @@ unsigned int platform_len(void) { // get platform entry encoded n (first byte for input data of OSS fuzz) unsigned int get_platform_entry(uint8_t n) { - return n % platform_len(); + unsigned len = platform_len(); + if (len == 0) { + return 0; + } + return n % len; } // get cstoolname from encoded n (first byte for input data of OSS fuzz) diff --git a/tests/issues/issues.yaml b/tests/issues/issues.yaml index cc0a17cc6..8dc7232b3 100644 --- a/tests/issues/issues.yaml +++ b/tests/issues/issues.yaml @@ -4957,3 +4957,77 @@ test_cases: expected: insns: - asm_text: "jalrc $t9" + + - + input: + name: "issue 2471 -- max operands overflow" + bytes: [ 0xff, 0x00, 0x08, 0xc0 ] + arch: "CS_ARCH_AARCH64" + options: [ CS_OPT_DETAIL, CS_OPT_DETAIL_REAL ] + address: 0x0 + expected: + insns: + - + asm_text: "zero {za}" + is_alias: 1 + details: + aarch64: + operands: + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za0.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za1.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za2.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za3.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za4.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za5.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za6.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + - + type: AARCH64_OP_SME + sme: + type: AARCH64_SME_OP_TILE + tile: za7.d + access: CS_AC_READ + vas: AARCH64LAYOUT_VL_D + regs_read: [ za0.d, za1.d, za2.d, za3.d, za4.d, za5.d, za6.d, za7.d ] + groups: [ HasSME ] diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 2718f594f..4ac56ef87 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,14 +1,12 @@ cmake_minimum_required(VERSION 3.15) -# Old integration tests. -if (CAPSTONE_BUILD_LEGACY_TESTS) - enable_testing() - set(UNIT_TEST_SOURCES sstream.c) +enable_testing() +set(UNIT_TEST_SOURCES sstream.c utils.c) +include_directories(include) - foreach(TSRC ${UNIT_TEST_SOURCES}) - string(REGEX REPLACE ".c$" "" TBIN ${TSRC}) - add_executable(${TBIN} "${TESTS_UNIT_DIR}/${TSRC}") - target_link_libraries(${TBIN} PRIVATE capstone) - add_test(NAME "unit_${TBIN}" COMMAND ${TBIN}) - endforeach() -endif() +foreach(TSRC ${UNIT_TEST_SOURCES}) + string(REGEX REPLACE ".c$" "" TBIN ${TSRC}) + add_executable(${TBIN} "${TESTS_UNIT_DIR}/${TSRC}") + target_link_libraries(${TBIN} PRIVATE capstone) + add_test(NAME "unit_${TBIN}" COMMAND ${TBIN}) +endforeach() diff --git a/tests/unit/include/unit_test.h b/tests/unit/include/unit_test.h new file mode 100644 index 000000000..bf5b5cae0 --- /dev/null +++ b/tests/unit/include/unit_test.h @@ -0,0 +1,44 @@ +// Copyright © 2024 Rot127 +// SPDX-License-Identifier: BSD-3 + +#define CHECK_OS_EQUAL_RET_FALSE(OS, str) \ + do { \ + if (strcmp(OS.buffer, str) != 0) { \ + printf("OS.buffer != str\n"); \ + printf("OS.buffer: %s\n", OS.buffer); \ + printf("str : %s\n", str); \ + return false; \ + } \ + } while (0); + +#define CHECK_STR_EQUAL_RET_FALSE(a, b) \ + do { \ + if (strcmp(a, b) != 0) { \ + printf("%s != %s\n", a, b); \ + return false; \ + } \ + } while (0); + +#define CHECK_NULL_RET_FALSE(ptr) \ + do { \ + if (ptr != NULL) { \ + printf(#ptr " is not NULL\n"); \ + return false; \ + } \ + } while (0); + +#define CHECK_PTR_EQUAL_RET_FALSE(a, b) \ + do { \ + if (a != b) { \ + printf("%p != %p\n", a, b); \ + return false; \ + } \ + } while (0); + +#define CHECK_INT_EQUAL_RET_FALSE(a, b) \ + do { \ + if (a != b) { \ + printf("%" PRId32 " != %" PRId32 "\n", a, b); \ + return false; \ + } \ + } while (0); diff --git a/tests/unit/sstream.c b/tests/unit/sstream.c index c4f158b6c..8f6048575 100644 --- a/tests/unit/sstream.c +++ b/tests/unit/sstream.c @@ -1,21 +1,12 @@ // Copyright © 2024 Rot127 // SPDX-License-Identifier: BSD-3 +#include "unit_test.h" #include "../SStream.h" #include "../utils.h" #include #include -#define CHECK_EQUAL_RET_FALSE(OS, str) \ - do { \ - if (strcmp(OS.buffer, str) != 0) { \ - printf("OS.buffer != str\n"); \ - printf("OS.buffer: %s\n", OS.buffer); \ - printf("str : %s\n", str); \ - return false; \ - } \ - } while (0); - static void overflow_SStream_concat0(SStream *OS, bool *returned_in_time) { char buf[SSTREAM_BUF_LEN + 1] = { 0 }; @@ -74,22 +65,22 @@ static bool test_markup_os() SStream OS = { 0 }; SStream_Init(&OS); SStream_concat0(&OS, "0"); - CHECK_EQUAL_RET_FALSE(OS, "0"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0"); OS.markup_stream = true; printUInt64(&OS, 0); - CHECK_EQUAL_RET_FALSE(OS, "00"); + CHECK_OS_EQUAL_RET_FALSE(OS, "00"); markup_OS(&OS, Markup_Immediate); printUInt64(&OS, 0); - CHECK_EQUAL_RET_FALSE(OS, "00"); + CHECK_OS_EQUAL_RET_FALSE(OS, "00"); markup_OS(&OS, Markup_Memory); printUInt32(&OS, 0); - CHECK_EQUAL_RET_FALSE(OS, "00"); + CHECK_OS_EQUAL_RET_FALSE(OS, "00"); markup_OS(&OS, Markup_Target); printUInt32(&OS, 0); - CHECK_EQUAL_RET_FALSE(OS, "00"); + CHECK_OS_EQUAL_RET_FALSE(OS, "00"); markup_OS(&OS, Markup_Register); SStream_concat0(&OS, "r19"); - CHECK_EQUAL_RET_FALSE(OS, "00"); + CHECK_OS_EQUAL_RET_FALSE(OS, "00"); return true; } @@ -100,27 +91,27 @@ bool test_printint8() SStream OS = { 0 }; SStream_Init(&OS); printInt8(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0xa"); SStream_Flush(&OS, NULL); printInt8(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "9"); SStream_Flush(&OS, NULL); printInt8(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa"); SStream_Flush(&OS, NULL); printInt8(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-9"); SStream_Flush(&OS, NULL); printInt8(&OS, INT8_MAX); - CHECK_EQUAL_RET_FALSE(OS, "0x7f"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0x7f"); SStream_Flush(&OS, NULL); printInt8(&OS, INT8_MIN); - CHECK_EQUAL_RET_FALSE(OS, "-0x80"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0x80"); SStream_Flush(&OS, NULL); return true; } @@ -132,27 +123,27 @@ bool test_printint16() SStream OS = { 0 }; SStream_Init(&OS); printInt16(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0xa"); SStream_Flush(&OS, NULL); printInt16(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "9"); SStream_Flush(&OS, NULL); printInt16(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa"); SStream_Flush(&OS, NULL); printInt16(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-9"); SStream_Flush(&OS, NULL); printInt16(&OS, INT16_MAX); - CHECK_EQUAL_RET_FALSE(OS, "0x7fff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fff"); SStream_Flush(&OS, NULL); printInt16(&OS, INT16_MIN); - CHECK_EQUAL_RET_FALSE(OS, "-0x8000"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0x8000"); SStream_Flush(&OS, NULL); return true; } @@ -164,27 +155,27 @@ bool test_printint32() SStream OS = { 0 }; SStream_Init(&OS); printInt32(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0xa"); SStream_Flush(&OS, NULL); printInt32(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "9"); SStream_Flush(&OS, NULL); printInt32(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa"); SStream_Flush(&OS, NULL); printInt32(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-9"); SStream_Flush(&OS, NULL); printInt32(&OS, INT32_MAX); - CHECK_EQUAL_RET_FALSE(OS, "0x7fffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fffffff"); SStream_Flush(&OS, NULL); printInt32(&OS, INT32_MIN); - CHECK_EQUAL_RET_FALSE(OS, "-0x80000000"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0x80000000"); SStream_Flush(&OS, NULL); return true; } @@ -196,27 +187,27 @@ bool test_printint64() SStream OS = { 0 }; SStream_Init(&OS); printInt64(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0xa"); SStream_Flush(&OS, NULL); printInt64(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "9"); SStream_Flush(&OS, NULL); printInt64(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0xa"); SStream_Flush(&OS, NULL); printInt64(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-9"); SStream_Flush(&OS, NULL); printInt64(&OS, INT64_MAX); - CHECK_EQUAL_RET_FALSE(OS, "0x7fffffffffffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "0x7fffffffffffffff"); SStream_Flush(&OS, NULL); printInt64(&OS, INT64_MIN); - CHECK_EQUAL_RET_FALSE(OS, "-0x8000000000000000"); + CHECK_OS_EQUAL_RET_FALSE(OS, "-0x8000000000000000"); SStream_Flush(&OS, NULL); return true; } @@ -228,27 +219,27 @@ bool test_printint32_bang() SStream OS = { 0 }; SStream_Init(&OS); printInt32Bang(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "#0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa"); SStream_Flush(&OS, NULL); printInt32Bang(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#9"); SStream_Flush(&OS, NULL); printInt32Bang(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "#-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-0xa"); SStream_Flush(&OS, NULL); printInt32Bang(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-9"); SStream_Flush(&OS, NULL); printInt32Bang(&OS, INT32_MAX); - CHECK_EQUAL_RET_FALSE(OS, "#0x7fffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0x7fffffff"); SStream_Flush(&OS, NULL); printInt32Bang(&OS, INT32_MIN); - CHECK_EQUAL_RET_FALSE(OS, "#-0x80000000"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-0x80000000"); SStream_Flush(&OS, NULL); return true; } @@ -260,27 +251,27 @@ bool test_printint64_bang() SStream OS = { 0 }; SStream_Init(&OS); printInt64Bang(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "#0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa"); SStream_Flush(&OS, NULL); printInt64Bang(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#9"); SStream_Flush(&OS, NULL); printInt64Bang(&OS, -(HEX_THRESHOLD + 1)); - CHECK_EQUAL_RET_FALSE(OS, "#-0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-0xa"); SStream_Flush(&OS, NULL); printInt64Bang(&OS, -HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#-9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-9"); SStream_Flush(&OS, NULL); printInt64Bang(&OS, INT64_MAX); - CHECK_EQUAL_RET_FALSE(OS, "#0x7fffffffffffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0x7fffffffffffffff"); SStream_Flush(&OS, NULL); printInt64Bang(&OS, INT64_MIN); - CHECK_EQUAL_RET_FALSE(OS, "#-0x8000000000000000"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#-0x8000000000000000"); SStream_Flush(&OS, NULL); return true; } @@ -292,15 +283,15 @@ bool test_printuint32_bang() SStream OS = { 0 }; SStream_Init(&OS); printUInt32Bang(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "#0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa"); SStream_Flush(&OS, NULL); printUInt32Bang(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#9"); SStream_Flush(&OS, NULL); printUInt32Bang(&OS, UINT32_MAX); - CHECK_EQUAL_RET_FALSE(OS, "#0xffffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xffffffff"); SStream_Flush(&OS, NULL); return true; } @@ -312,19 +303,211 @@ bool test_printuint64_bang() SStream OS = { 0 }; SStream_Init(&OS); printUInt64Bang(&OS, HEX_THRESHOLD + 1); - CHECK_EQUAL_RET_FALSE(OS, "#0xa"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xa"); SStream_Flush(&OS, NULL); printUInt64Bang(&OS, HEX_THRESHOLD); - CHECK_EQUAL_RET_FALSE(OS, "#9"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#9"); SStream_Flush(&OS, NULL); printUInt64Bang(&OS, UINT64_MAX); - CHECK_EQUAL_RET_FALSE(OS, "#0xffffffffffffffff"); + CHECK_OS_EQUAL_RET_FALSE(OS, "#0xffffffffffffffff"); SStream_Flush(&OS, NULL); return true; } +bool test_trimls() { + printf("Test test_replc\n"); + + SStream OS = { 0 }; + SStream_Init(&OS); + SStream_concat0(&OS, "AAA"); + SStream_trimls(&OS); + CHECK_OS_EQUAL_RET_FALSE(OS, "AAA"); + SStream_Flush(&OS, NULL); + + SStream_concat0(&OS, "\t AAA"); + SStream_trimls(&OS); + CHECK_OS_EQUAL_RET_FALSE(OS, "AAA"); + + // Don't remove middle tabs and spaces + SStream_concat0(&OS, "\t AAA"); + SStream_trimls(&OS); + CHECK_OS_EQUAL_RET_FALSE(OS, "AAA\t AAA"); + SStream_Flush(&OS, NULL); + + // Test do nothing + SStream_trimls(&OS); + CHECK_OS_EQUAL_RET_FALSE(OS, ""); + + // Everywhere tabs + char cmp_buf[SSTREAM_BUF_LEN] = { 0 }; + memset(cmp_buf, '\t', sizeof(cmp_buf) - 1); + SStream_trimls(&OS); + CHECK_OS_EQUAL_RET_FALSE(OS, ""); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 0); + return true; +} + +bool test_copy_mnem_opstr() { + printf("Test test_copy_mnem_opstr\n"); + + SStream OS = { 0 }; + SStream_Init(&OS); + SStream_concat0(&OS, "AAA\tBBBB"); + + char mnem_1[1] = { 0 }; + char opstr_1[1] = { 0 }; + SStream_extract_mnem_opstr(&OS, mnem_1, sizeof(mnem_1), opstr_1, sizeof(opstr_1)); + CHECK_STR_EQUAL_RET_FALSE(mnem_1, ""); + CHECK_STR_EQUAL_RET_FALSE(opstr_1, ""); + + char mnem_3[3] = { 0 }; + char opstr_3[3] = { 0 }; + SStream_extract_mnem_opstr(&OS, mnem_3, sizeof(mnem_3), opstr_3, sizeof(opstr_3)); + CHECK_STR_EQUAL_RET_FALSE(mnem_3, "AA"); + CHECK_STR_EQUAL_RET_FALSE(opstr_3, "BB"); + + char mnem_4[4] = { 0 }; + char opstr_4[4] = { 0 }; + SStream_extract_mnem_opstr(&OS, mnem_4, sizeof(mnem_4), opstr_4, sizeof(opstr_4)); + CHECK_STR_EQUAL_RET_FALSE(mnem_4, "AAA"); + CHECK_STR_EQUAL_RET_FALSE(opstr_4, "BBB"); + + char mnem_5[5] = { 0 }; + char opstr_5[5] = { 0 }; + SStream_extract_mnem_opstr(&OS, mnem_5, sizeof(mnem_5), opstr_5, sizeof(opstr_5)); + CHECK_STR_EQUAL_RET_FALSE(mnem_5, "AAA"); + CHECK_STR_EQUAL_RET_FALSE(opstr_5, "BBBB"); + + // No mnemonic + char mnem_9[9] = { 0 }; + char opstr_9[9] = { 0 }; + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, " AAA\tBBBB"); + SStream_extract_mnem_opstr(&OS, mnem_9, sizeof(mnem_9), opstr_9, sizeof(opstr_9)); + CHECK_STR_EQUAL_RET_FALSE(mnem_9, ""); + CHECK_STR_EQUAL_RET_FALSE(opstr_9, "AAA\tBBBB"); + + // No opstr + char mnem_6[6] = { 0 }; + char opstr_6[6] = { 0 }; + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, "AAA \t"); + SStream_extract_mnem_opstr(&OS, mnem_6, sizeof(mnem_6), opstr_6, sizeof(opstr_6)); + CHECK_STR_EQUAL_RET_FALSE(mnem_6, "AAA"); + CHECK_STR_EQUAL_RET_FALSE(opstr_6, ""); + + return true; +} + +bool test_replc() +{ + printf("Test test_replc\n"); + + SStream OS = { 0 }; + SStream_Init(&OS); + char cmp_buf[SSTREAM_BUF_LEN] = { 0 }; + memset(cmp_buf, 'A', sizeof(cmp_buf) - 1); + cmp_buf[100] = 'C'; + SStream_concat0(&OS, cmp_buf); + + cmp_buf[0] = 'B'; + const char *next = SStream_replc(&OS, 'A', 'B'); + CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 1, next); + CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf); + + cmp_buf[1] = 'B'; + next = SStream_replc(&OS, 'A', 'B'); + CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 2, next); + CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf); + + cmp_buf[100] = 'A'; // Replace the C from before + next = SStream_replc(&OS, 'C', 'A'); + CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 101, next); + CHECK_OS_EQUAL_RET_FALSE(OS, cmp_buf); + + // X doesn't exist + next = SStream_replc(&OS, 'X', 'A'); + CHECK_NULL_RET_FALSE(next); + + // Replacing \0 byte is forbidden. + next = SStream_replc(&OS, '\0', 'A'); + CHECK_NULL_RET_FALSE(next); + + // But replacing any \0 byte is allowed. + SStream_Flush(&OS, NULL); + next = SStream_replc(&OS, '\0', 'A'); + CHECK_PTR_EQUAL_RET_FALSE(SStream_rbuf(&OS) + 1, next); + CHECK_OS_EQUAL_RET_FALSE(OS, "A"); + + return true; +} + + +bool test_replc_str() +{ + printf("Test test_replc_str\n"); + + SStream OS = { 0 }; + SStream_Init(&OS); + + SStream_replc_str(&OS, 'A', "REPLACED"); + CHECK_OS_EQUAL_RET_FALSE(OS, ""); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 0); + + SStream_replc_str(&OS, '\0', "REPLACED"); + CHECK_OS_EQUAL_RET_FALSE(OS, "REPLACED"); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 8); + + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, "\tA--X"); + SStream_replc_str(&OS, 'A', "REPLACED"); + CHECK_OS_EQUAL_RET_FALSE(OS, "\tREPLACED--X"); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 12); + SStream_replc_str(&OS, 'X', "REPLACED"); + CHECK_OS_EQUAL_RET_FALSE(OS, "\tREPLACED--REPLACED"); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 19); + + /// Too big strings are ignored. + char repl[SSTREAM_BUF_LEN] = { 0 }; + memset(repl, 'A', sizeof(repl) - 1); + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, "\tA--"); + SStream_replc_str(&OS, 'A', repl); + CHECK_OS_EQUAL_RET_FALSE(OS, "\tA--"); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 4); + + /// Last null byte is not replaced. + memset(repl, 'A', sizeof(repl) - 1); + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, repl); + SStream_replc_str(&OS, '\0', repl); + CHECK_OS_EQUAL_RET_FALSE(OS, repl); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 511); + + /// Last char is replaced. + memset(repl, 'A', sizeof(repl) - 1); + repl[sizeof(repl) - 2] = 'X'; + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, repl); + SStream_replc_str(&OS, 'X', "Y"); + repl[sizeof(repl) - 2] = 'Y'; + CHECK_OS_EQUAL_RET_FALSE(OS, repl); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 511); + + // Possible overflow + char too_long[SSTREAM_BUF_LEN + 10] = { 0 }; + memset(too_long, 'A', sizeof(too_long) - 1); + SStream_Flush(&OS, NULL); + SStream_concat0(&OS, "\tA--"); + SStream_replc_str(&OS, 'A', too_long); + CHECK_OS_EQUAL_RET_FALSE(OS, "\tA--"); + CHECK_INT_EQUAL_RET_FALSE(OS.index, 4); + + return true; +} + int main() { bool result = true; @@ -338,6 +521,10 @@ int main() result &= test_printint64_bang(); result &= test_printuint32_bang(); result &= test_printuint64_bang(); + result &= test_replc(); + result &= test_replc_str(); + result &= test_copy_mnem_opstr(); + result &= test_trimls(); if (result) { printf("All tests passed.\n"); } else { diff --git a/tests/unit/utils.c b/tests/unit/utils.c new file mode 100644 index 000000000..d5dd88b31 --- /dev/null +++ b/tests/unit/utils.c @@ -0,0 +1,76 @@ +// Copyright © 2024 Rot127 +// SPDX-License-Identifier: BSD-3 + +#include "unit_test.h" +#include "../utils.h" +#include +#include + +static bool test_str_append_no_realloc() +{ + printf("Test test_str_append_no_realloc\n"); + + char str_a[] = "AAAA\0\0\0\0\0"; + char str_b[] = "BBBB"; + char str_c[] = "\0\0\0\0\0"; + + CHECK_NULL_RET_FALSE(str_append(NULL, NULL)); + CHECK_NULL_RET_FALSE(str_append(str_a, NULL)); + CHECK_NULL_RET_FALSE(str_append(NULL, str_b)); + + str_append_no_realloc(str_a, sizeof(str_a), str_c); + CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAA"); + + str_append_no_realloc(str_a, sizeof(str_a), str_b); + CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAABBBB"); + + str_append_no_realloc(str_c, sizeof(str_c), str_b); + CHECK_STR_EQUAL_RET_FALSE(str_c, "BBBB"); + + str_append_no_realloc(str_b, sizeof(str_b), str_c); + CHECK_STR_EQUAL_RET_FALSE(str_b, "BBBB"); + + return true; +} + +static bool test_str_append() +{ + printf("Test test_str_append\n"); + char *str_a = NULL; + char *str_b = NULL; + CHECK_NULL_RET_FALSE(str_append(str_a, str_b)); + + str_a = calloc(5, sizeof(char)); + memcpy(str_a, "AAAA", 5); + CHECK_NULL_RET_FALSE(str_append(str_a, str_b)); + + str_b = calloc(5, sizeof(char)); + str_a = str_append(str_a, str_b); + CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAA"); + + memcpy(str_b, "BBBB", 5); + str_a = str_append(str_a, str_b); + CHECK_STR_EQUAL_RET_FALSE(str_a, "AAAABBBB"); + + memset(str_a, 0, strlen(str_a) + 1); + str_a = str_append(str_a, str_b); + CHECK_STR_EQUAL_RET_FALSE(str_a, "BBBB"); + free(str_a); + free(str_b); + + return true; +} + +int main() +{ + bool result = true; + result &= test_str_append(); + result &= test_str_append_no_realloc(); + + if (result) { + printf("All tests passed.\n"); + } else { + printf("Some tests failed.\n"); + } + return result ? 0 : -1; +} diff --git a/utils.c b/utils.c index 75c22c2be..fb744bcbc 100644 --- a/utils.c +++ b/utils.c @@ -181,36 +181,37 @@ void append_to_str_lower(char *str, size_t str_size, const char *src) { str[i] = '\0'; } -/// @brief Appends the string @p src to the string @p str. @p src is put to lower case. -/// @param str The string to append to. -/// @param str_buf_size Size of buffer @p str. +/// @brief Appends the string @p src to the string @p dest. +/// @p dest is can be a stack allocated buffer. +/// +/// @param dest The string to append to. +/// @param dest_buf_size Size of buffer @p str. /// @param src The string to append. /// Does nothing if any of the given strings is NULL. -void append_to_str(char *str, size_t str_buf_size, const char *src) { - if (!str || !src) { +void str_append_no_realloc(char *dest, size_t dest_buf_size, const char *src) { + if (!dest || !src) { return; } - if (strlen(str) + strlen(src) + 1 > str_buf_size) { - assert("str_size does not match actual string length." && 0); + if (strlen(dest) + strlen(src) + 1 > dest_buf_size) { + printf("str_size does not match actual string length.\n"); return; } - strncat(str, src, str_buf_size); + strncat(dest, src, dest_buf_size - strlen(dest)); } /// Allocates memory of strlen(str_a) + strlen(str_b) + 1 chars /// and copies all strings into it as str_a + str_b /// str_a is passed to realloc and should not be used afterwards. -/// Returns the result. +/// Returns the concatenated string. /// Returns NULL in case of failure. char *str_append(char *str_a, const char *str_b) { if (!str_a || !str_b) { return NULL; } - assert(str_a && str_b); size_t asize = strlen(str_a) + strlen(str_b) + 1; str_a = realloc(str_a, asize); - strncat(str_a, str_b, asize); + strncat(str_a, str_b, asize - strlen(str_a)); return str_a; } diff --git a/utils.h b/utils.h index c9c82bc27..baa87e257 100644 --- a/utils.h +++ b/utils.h @@ -44,7 +44,7 @@ uint64_t readBytes48(MCInst *MI, const uint8_t *Bytes); uint64_t readBytes64(MCInst *MI, const uint8_t *Bytes); void append_to_str_lower(char *str, size_t str_size, const char *src); -void append_to_str(char *str, size_t str_buf_size, const char *src); +void str_append_no_realloc(char *str, size_t str_buf_size, const char *src); char *str_append(char *str_a, const char *str_b); static inline bool strings_match(const char *str0, const char *str1) { return strcmp(str0, str1) == 0; }