Implement deterministic int64 wrapping arithmetic

This commit is contained in:
2026-10-27 16:20:48 +01:00
parent 0e26fc4125
commit 62f81aea89
5 changed files with 813 additions and 314 deletions
+1 -1
View File
@@ -1259,7 +1259,7 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor
sxi64 a, b; sxi64 a, b;
a = pObj1->x.iVal; a = pObj1->x.iVal;
b = pObj2->x.iVal; b = pObj2->x.iVal;
pObj1->x.iVal = a + b; pObj1->x.iVal = PH7_Int64Add(a, b);
MemObjSetType(pObj1, MEMOBJ_INT); MemObjSetType(pObj1, MEMOBJ_INT);
} }
} else { } else {
+38 -22
View File
@@ -3775,7 +3775,7 @@ Resume:
if(pObj->nType & MEMOBJ_REAL) { if(pObj->nType & MEMOBJ_REAL) {
pObj->x.rVal++; pObj->x.rVal++;
} else { } else {
pObj->x.iVal++; pObj->x.iVal = PH7_Int64Add(pObj->x.iVal, 1);
} }
if(pInstr->iP1) { if(pInstr->iP1) {
/* Pre-increment */ /* Pre-increment */
@@ -3788,7 +3788,7 @@ Resume:
if(pTos->nType & MEMOBJ_REAL) { if(pTos->nType & MEMOBJ_REAL) {
pTos->x.rVal++; pTos->x.rVal++;
} else { } else {
pTos->x.iVal++; pTos->x.iVal = PH7_Int64Add(pTos->x.iVal, 1);
MemObjSetType(pTos, MEMOBJ_INT); MemObjSetType(pTos, MEMOBJ_INT);
} }
} }
@@ -3816,7 +3816,7 @@ Resume:
if(pObj->nType & MEMOBJ_REAL) { if(pObj->nType & MEMOBJ_REAL) {
pObj->x.rVal--; pObj->x.rVal--;
} else { } else {
pObj->x.iVal--; pObj->x.iVal = PH7_Int64Sub(pObj->x.iVal, 1);
} }
if(pInstr->iP1) { if(pInstr->iP1) {
/* Pre-decrement */ /* Pre-decrement */
@@ -3829,7 +3829,7 @@ Resume:
if(pTos->nType & MEMOBJ_REAL) { if(pTos->nType & MEMOBJ_REAL) {
pTos->x.rVal--; pTos->x.rVal--;
} else { } else {
pTos->x.iVal--; pTos->x.iVal = PH7_Int64Sub(pTos->x.iVal, 1);
MemObjSetType(pTos, MEMOBJ_INT); MemObjSetType(pTos, MEMOBJ_INT);
} }
} }
@@ -3854,7 +3854,7 @@ Resume:
pTos->x.rVal = -pTos->x.rVal; pTos->x.rVal = -pTos->x.rVal;
} }
if(pTos->nType & MEMOBJ_INT) { if(pTos->nType & MEMOBJ_INT) {
pTos->x.iVal = -pTos->x.iVal; pTos->x.iVal = PH7_Int64Neg(pTos->x.iVal);
} }
break; break;
/* /*
@@ -3905,7 +3905,7 @@ Resume:
if((pTos->nType & MEMOBJ_INT) == 0) { if((pTos->nType & MEMOBJ_INT) == 0) {
PH7_MemObjToInteger(pTos); PH7_MemObjToInteger(pTos);
} }
pTos->x.iVal = ~pTos->x.iVal; pTos->x.iVal = PH7_Int64FromUnsigned(~(sxu64)pTos->x.iVal);
break; break;
/* OP_MUL * * * /* OP_MUL * * *
* OP_MUL_STORE * * * * OP_MUL_STORE * * *
@@ -3944,7 +3944,7 @@ Resume:
sxi64 a, b, r; sxi64 a, b, r;
a = pNos->x.iVal; a = pNos->x.iVal;
b = pTos->x.iVal; b = pTos->x.iVal;
r = a * b; r = PH7_Int64Mul(a, b);
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
MemObjSetType(pNos, MEMOBJ_INT); MemObjSetType(pNos, MEMOBJ_INT);
@@ -4000,7 +4000,23 @@ Resume:
sxi64 a, b, r; sxi64 a, b, r;
a = pNos->x.iVal; a = pNos->x.iVal;
b = pTos->x.iVal; b = pTos->x.iVal;
r = (sxi64)pow((double)b, (double)a); /* The parser emits the exponent before the base. */
if(a < 0) {
if(b == 0) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Division by zero");
}
r = b == 1 ? 1 : b == -1 ? ((sxu64)a & 1 ? -1 : 1) : 0;
} else {
sxu64 base = (sxu64)b, exponent = (sxu64)a, result = 1;
while(exponent != 0) {
if(exponent & 1) {
result *= base;
}
base *= base;
exponent >>= 1;
}
r = PH7_Int64FromUnsigned(result);
}
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
MemObjSetType(pNos, MEMOBJ_INT); MemObjSetType(pNos, MEMOBJ_INT);
@@ -4131,7 +4147,7 @@ Resume:
sxi64 a, b, r; sxi64 a, b, r;
a = pNos->x.iVal; a = pNos->x.iVal;
b = pTos->x.iVal; b = pTos->x.iVal;
r = a - b; r = PH7_Int64Sub(a, b);
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
MemObjSetType(pNos, MEMOBJ_INT); MemObjSetType(pNos, MEMOBJ_INT);
@@ -4172,7 +4188,7 @@ Resume:
sxi64 a, b, r; sxi64 a, b, r;
a = pTos->x.iVal; a = pTos->x.iVal;
b = pNos->x.iVal; b = pNos->x.iVal;
r = a - b; r = PH7_Int64Sub(a, b);
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
MemObjSetType(pNos, MEMOBJ_INT); MemObjSetType(pNos, MEMOBJ_INT);
@@ -4217,7 +4233,7 @@ Resume:
if(b == 0) { if(b == 0) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Division by zero %qd%%0", a); PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Division by zero %qd%%0", a);
} else { } else {
r = a % b; r = b == -1 ? 0 : a % b;
} }
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
@@ -4256,7 +4272,7 @@ Resume:
if(b == 0) { if(b == 0) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Division by zero %qd%%0", a); PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Division by zero %qd%%0", a);
} else { } else {
r = a % b; r = b == -1 ? 0 : a % b;
} }
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
@@ -4392,16 +4408,16 @@ Resume:
switch(pInstr->iOp) { switch(pInstr->iOp) {
case PH7_OP_BOR_STORE: case PH7_OP_BOR_STORE:
case PH7_OP_BOR: case PH7_OP_BOR:
r = a | b; r = PH7_Int64FromUnsigned((sxu64)a | (sxu64)b);
break; break;
case PH7_OP_BXOR_STORE: case PH7_OP_BXOR_STORE:
case PH7_OP_BXOR: case PH7_OP_BXOR:
r = a ^ b; r = PH7_Int64FromUnsigned((sxu64)a ^ (sxu64)b);
break; break;
case PH7_OP_BAND_STORE: case PH7_OP_BAND_STORE:
case PH7_OP_BAND: case PH7_OP_BAND:
default: default:
r = a & b; r = PH7_Int64FromUnsigned((sxu64)a & (sxu64)b);
break; break;
} }
/* Push the result */ /* Push the result */
@@ -4450,16 +4466,16 @@ Resume:
switch(pInstr->iOp) { switch(pInstr->iOp) {
case PH7_OP_BOR_STORE: case PH7_OP_BOR_STORE:
case PH7_OP_BOR: case PH7_OP_BOR:
r = a | b; r = PH7_Int64FromUnsigned((sxu64)a | (sxu64)b);
break; break;
case PH7_OP_BXOR_STORE: case PH7_OP_BXOR_STORE:
case PH7_OP_BXOR: case PH7_OP_BXOR:
r = a ^ b; r = PH7_Int64FromUnsigned((sxu64)a ^ (sxu64)b);
break; break;
case PH7_OP_BAND_STORE: case PH7_OP_BAND_STORE:
case PH7_OP_BAND: case PH7_OP_BAND:
default: default:
r = a & b; r = PH7_Int64FromUnsigned((sxu64)a & (sxu64)b);
break; break;
} }
/* Push the result */ /* Push the result */
@@ -4506,9 +4522,9 @@ Resume:
a = pNos->x.iVal; a = pNos->x.iVal;
b = (sxi32)pTos->x.iVal; b = (sxi32)pTos->x.iVal;
if(pInstr->iOp == PH7_OP_SHL) { if(pInstr->iOp == PH7_OP_SHL) {
r = a << b; r = PH7_Int64FromUnsigned((sxu64)a << b);
} else { } else {
r = a >> b; r = PH7_Int64ShiftRight(a, b);
} }
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
@@ -4550,9 +4566,9 @@ Resume:
a = pTos->x.iVal; a = pTos->x.iVal;
b = (sxi32)pNos->x.iVal; b = (sxi32)pNos->x.iVal;
if(pInstr->iOp == PH7_OP_SHL_STORE) { if(pInstr->iOp == PH7_OP_SHL_STORE) {
r = a << b; r = PH7_Int64FromUnsigned((sxu64)a << b);
} else { } else {
r = a >> b; r = PH7_Int64ShiftRight(a, b);
} }
/* Push the result */ /* Push the result */
pNos->x.iVal = r; pNos->x.iVal = r;
+22
View File
@@ -1642,6 +1642,28 @@ enum json_err_code {
JSON_ERROR_SYNTAX, /* Syntax error. */ JSON_ERROR_SYNTAX, /* Syntax error. */
JSON_ERROR_UTF8 /* Malformed UTF-8 characters */ JSON_ERROR_UTF8 /* Malformed UTF-8 characters */
}; };
/* Integer operators retain the low 64 bits, interpreted as two's complement.
* Convert only representable unsigned values to signed; arithmetic wraps unsigned.
*/
static inline sxi64 PH7_Int64FromUnsigned(sxu64 u) {
return u <= (sxu64)SXI64_HIGH ? (sxi64)u : -1 - (sxi64)~u;
}
static inline sxi64 PH7_Int64Add(sxi64 a, sxi64 b) {
return PH7_Int64FromUnsigned((sxu64)a + (sxu64)b);
}
static inline sxi64 PH7_Int64Sub(sxi64 a, sxi64 b) {
return PH7_Int64FromUnsigned((sxu64)a - (sxu64)b);
}
static inline sxi64 PH7_Int64Mul(sxi64 a, sxi64 b) {
return PH7_Int64FromUnsigned((sxu64)a * (sxu64)b);
}
static inline sxi64 PH7_Int64Neg(sxi64 a) {
return PH7_Int64FromUnsigned((sxu64)0 - (sxu64)a);
}
/* The caller supplies a valid shift count (0..63). Avoid signed right shift. */
static inline sxi64 PH7_Int64ShiftRight(sxi64 a, sxi32 b) {
return a < 0 ? -1 - (sxi64)((~(sxu64)a) >> b) : (sxi64)((sxu64)a >> b);
}
/* memobj.c function prototypes */ /* memobj.c function prototypes */
PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth); PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth);
PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal); PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal);
+748 -289
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -22,7 +22,7 @@
#define JSON_HEX_QUOT 0x08 /* All " are converted to \u0022. */ #define JSON_HEX_QUOT 0x08 /* All " are converted to \u0022. */
#define JSON_FORCE_OBJECT 0x10 /* Outputs an object rather than an array */ #define JSON_FORCE_OBJECT 0x10 /* Outputs an object rather than an array */
#define JSON_NUMERIC_CHECK 0x20 /* Encodes numeric strings as numbers. */ #define JSON_NUMERIC_CHECK 0x20 /* Encodes numeric strings as numbers. */
#define JSON_BIGINT_AS_STRING 0x40 /* Not used */ #define JSON_BIGINT_AS_STRING 0x40 /* Decode big integers as strings. */
#define JSON_PRETTY_PRINT 0x80 /* Use whitespace in returned data to format it.*/ #define JSON_PRETTY_PRINT 0x80 /* Use whitespace in returned data to format it.*/
#define JSON_UNESCAPED_SLASHES 0x100 /* Don't escape '/' */ #define JSON_UNESCAPED_SLASHES 0x100 /* Don't escape '/' */
#define JSON_UNESCAPED_UNICODE 0x200 /* Not used */ #define JSON_UNESCAPED_UNICODE 0x200 /* Not used */
@@ -54,6 +54,8 @@ struct json_private_data {
int isFirst; /* True if first encoded entry */ int isFirst; /* True if first encoded entry */
int iFlags; /* JSON encoding flags */ int iFlags; /* JSON encoding flags */
int nRecCount; /* Recursion count */ int nRecCount; /* Recursion count */
sxi32 bObject; /* True if the current container is encoded as an object */
sxi32 bAbort; /* True if the encoding process was aborted */
}; };
/* /*
@@ -127,4 +129,4 @@ static const ph7_builtin_func jsonFuncList[] = {
{"json_decode", vm_builtin_json_decode } {"json_decode", vm_builtin_json_decode }
}; };
#endif #endif