Skip to content

Commit

Permalink
64 bit constants are truncated to 32 bit on windows (#341)
Browse files Browse the repository at this point in the history
* Move normalize_int to new file

* Use normalize_int in cexpressiongenerator.py

---------

Co-authored-by: rihi <19492038+rihi@users.noreply.github.com>
  • Loading branch information
github-actions[bot] and rihi authored Oct 5, 2023
1 parent 45ef92b commit 83b07e6
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 44 deletions.
24 changes: 2 additions & 22 deletions decompiler/backend/cexpressiongenerator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from ctypes import c_byte, c_int, c_long, c_short, c_ubyte, c_uint, c_ulong, c_ushort
from itertools import chain, repeat

from decompiler.structures import pseudo as expressions
Expand All @@ -8,6 +7,7 @@
from decompiler.structures.pseudo import operations as operations
from decompiler.structures.pseudo.operations import MemberAccess
from decompiler.structures.visitors.interfaces import DataflowObjectVisitorInterface
from decompiler.util.integer_util import normalize_int


class CExpressionGenerator(DataflowObjectVisitorInterface):
Expand Down Expand Up @@ -80,20 +80,6 @@ class CExpressionGenerator(DataflowObjectVisitorInterface):
# OperationType.adc: "adc",
}

SIGNED_FORMATS = {
8: lambda x: c_byte(x).value,
16: lambda x: c_short(x).value,
32: lambda x: c_int(x).value,
64: lambda x: c_long(x).value,
}

UNSIGNED_FORMATS = {
8: lambda x: c_ubyte(x).value,
16: lambda x: c_ushort(x).value,
32: lambda x: c_uint(x).value,
64: lambda x: c_ulong(x).value,
}

"""
Precedence used for correctly generating brackets.
Higher precedence is more tightly binding.
Expand Down Expand Up @@ -298,13 +284,7 @@ def _get_integer_literal_value(self, literal: expressions.Constant) -> int:
Return the right integer value for the given type, assuming that the
re-compilation host has the same sizes as the decompilation host.
"""
if literal.type.is_signed:
if handler := self.SIGNED_FORMATS.get(literal.type.size, None):
return handler(literal.value)
elif literal.value < 0:
if handler := self.UNSIGNED_FORMATS.get(literal.type.size, None):
return handler(literal.value)
return literal.value
return normalize_int(literal.value, literal.type.size, literal.type.is_signed)

@staticmethod
def _interpret_integer_literal_type(value: int) -> Integer:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Callable, Optional

from decompiler.structures.pseudo import Constant, Integer, OperationType
from decompiler.util.integer_util import normalize_int


def constant_fold(operation: OperationType, constants: list[Constant]) -> Constant:
Expand Down Expand Up @@ -103,27 +104,6 @@ def _constant_fold_shift(constants: list[Constant], fun: Callable[[int, int], in
)


def normalize_int(v: int, size: int, signed: bool) -> int:
"""
Normalizes an integer value to a specific size and signedness.
This function takes an integer value 'v' and normalizes it to fit within
the specified 'size' in bits by discarding overflowing bits. If 'signed' is
true, the value is treated as a signed integer, i.e. interpreted as a two's complement.
Therefore the return value will be negative iff 'signed' is true and the most-significant bit is set.
:param v: The value to be normalized.
:param size: The desired bit size for the normalized integer.
:param signed: True if the integer should be treated as signed.
:return: The normalized integer value.
"""
value = v & ((1 << size) - 1)
if signed and value & (1 << (size - 1)):
return value - (1 << size)
else:
return value


_OPERATION_TO_FOLD_FUNCTION: dict[OperationType, Callable[[list[Constant]], Constant]] = {
OperationType.minus: partial(_constant_fold_arithmetic_binary, fun=operator.sub),
OperationType.plus: partial(_constant_fold_arithmetic_binary, fun=operator.add),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from decompiler.pipeline.controlflowanalysis.expression_simplification.constant_folding import normalize_int
from decompiler.pipeline.controlflowanalysis.expression_simplification.rules.rule import SimplificationRule
from decompiler.structures.pseudo import BinaryOperation, Constant, Expression, Integer, Operation, OperationType
from decompiler.util.integer_util import normalize_int


class PositiveConstants(SimplificationRule):
Expand Down
19 changes: 19 additions & 0 deletions decompiler/util/integer_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
def normalize_int(v: int, size: int, signed: bool) -> int:
"""
Normalizes an integer value to a specific size and signedness.
This function takes an integer value 'v' and normalizes it to fit within
the specified 'size' in bits by discarding overflowing bits. If 'signed' is
true, the value is treated as a signed integer, i.e. interpreted as a two's complement.
Therefore the return value will be negative iff 'signed' is true and the most-significant bit is set.
:param v: The value to be normalized.
:param size: The desired bit size for the normalized integer.
:param signed: True if the integer should be treated as signed.
:return: The normalized integer value.
"""
value = v & ((1 << size) - 1)
if signed and value & (1 << (size - 1)):
return value - (1 << size)
else:
return value

0 comments on commit 83b07e6

Please sign in to comment.