Skip to content

Commit af646a8

Browse files
Merge branch 'bug-fix-benchmark-script' of https://github.com/lisa-analyzer/evm-lisa into bug-fix-benchmark-script
2 parents 297dd41 + 0c59447 commit af646a8

File tree

6 files changed

+192
-132
lines changed

6 files changed

+192
-132
lines changed

evm-testcases/cfs/sar/report.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
"files" : [ "report.json", "untyped_program.evm-testcases_cfs_sar_sar_eth.sol().json" ],
44
"info" : {
55
"cfgs" : "1",
6-
"duration" : "11ms",
7-
"end" : "2025-02-26T11:44:05.873+01:00",
8-
"expressions" : "6",
6+
"duration" : "118ms",
7+
"end" : "2025-05-12T21:39:27.481+02:00",
8+
"expressions" : "48",
99
"files" : "1",
1010
"globals" : "0",
1111
"members" : "1",
1212
"programs" : "1",
13-
"start" : "2025-02-26T11:44:05.862+01:00",
14-
"statements" : "10",
13+
"start" : "2025-05-12T21:39:27.363+02:00",
14+
"statements" : "80",
1515
"units" : "0",
1616
"version" : "0.1",
1717
"warnings" : "0"

evm-testcases/cfs/sar/sar_eth.sol

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,74 @@ PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
77
PUSH1 0x04
88
SAR
99
PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
10+
EQ
11+
PUSH32 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
12+
PUSH2 0x0100
13+
SAR
14+
PUSH1 0x00
15+
EQ
16+
PUSH32 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
17+
PUSH1 0xff
18+
SAR
19+
PUSH1 0x00
20+
EQ
21+
PUSH32 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
22+
PUSH1 0xfe
23+
SAR
24+
PUSH1 0x01
25+
EQ
26+
PUSH32 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
27+
PUSH1 0xf8
28+
SAR
29+
PUSH32 0x000000000000000000000000000000000000000000000000000000000000007f
30+
EQ
31+
PUSH32 0x4000000000000000000000000000000000000000000000000000000000000000
32+
PUSH1 0xfe
33+
SAR
34+
PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001
35+
EQ
36+
PUSH32 0x0000000000000000000000000000000000000000000000000000000000000000
37+
PUSH1 0x01
38+
SAR
39+
PUSH32 0x0000000000000000000000000000000000000000000000000000000000000000
40+
EQ
41+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
42+
PUSH1 0x0100
43+
SAR
44+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
45+
EQ
46+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
47+
PUSH1 0xff
48+
SAR
49+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
50+
EQ
51+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
52+
PUSH1 0x01
53+
SAR
54+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
55+
EQ
56+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
57+
PUSH1 0x00
58+
SAR
59+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
60+
EQ
61+
PUSH32 0x8000000000000000000000000000000000000000000000000000000000000000
62+
PUSH2 0x0101
63+
SAR
64+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
65+
EQ
66+
PUSH32 0x8000000000000000000000000000000000000000000000000000000000000000
67+
PUSH2 0x0100
68+
SAR
69+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
70+
EQ
71+
PUSH32 0x8000000000000000000000000000000000000000000000000000000000000000
72+
PUSH1 0xff
73+
SAR
74+
PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
75+
EQ
76+
PUSH32 0x8000000000000000000000000000000000000000000000000000000000000000
77+
PUSH1 0x01
78+
SAR
79+
PUSH32 0xc000000000000000000000000000000000000000000000000000000000000000
1080
EQ

evm-testcases/cfs/sar/untyped_program.evm-testcases_cfs_sar_sar_eth.sol().json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/main/java/it/unipr/analysis/StackElement.java

Lines changed: 20 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package it.unipr.analysis;
22

3+
import it.unipr.utils.BitManager;
34
import it.unive.lisa.analysis.BaseLattice;
45
import it.unive.lisa.analysis.Lattice;
56
import it.unive.lisa.analysis.SemanticException;
@@ -451,11 +452,14 @@ else if (isTop() || other.isTop())
451452
return top();
452453
else if (isTopNotJumpdest() || other.isTopNotJumpdest())
453454
return NOT_JUMPDEST_TOP;
454-
else if (n.compareTo(new Number(256)) >= 0)
455-
return ZERO;
455+
else if (n.compareTo(new Number(Number.MAX_INT)) > 0)
456+
return bottom(); // fake path
456457

457-
return new StackElement(other.n.shiftLeft(this.n.getInt()));
458+
int[] bits = BitManager.toBitArray(Number.toBigInteger(other.n));
459+
int[] shiftedBits = BitManager.shiftLeft(bits, n.getInt());
460+
BigInteger result = BitManager.fromBitArray(shiftedBits);
458461

462+
return new StackElement(new Number(result));
459463
}
460464

461465
public StackElement shr(StackElement other) {
@@ -465,10 +469,14 @@ else if (isTop() || other.isTop())
465469
return top();
466470
else if (isTopNotJumpdest() || other.isTopNotJumpdest())
467471
return NOT_JUMPDEST_TOP;
468-
else if (n.compareTo(new Number(256)) >= 0)
469-
return ZERO;
472+
else if (n.compareTo(new Number(Number.MAX_INT)) > 0)
473+
return bottom(); // fake path
474+
475+
int[] bits = BitManager.toBitArray(Number.toBigInteger(other.n));
476+
int[] shiftedBits = BitManager.shiftRight(bits, n.getInt());
477+
BigInteger result = BitManager.fromBitArray(shiftedBits);
470478

471-
return new StackElement(other.n.shiftRight(this.n.getInt()));
479+
return new StackElement(new Number(result));
472480
}
473481

474482
public StackElement sar(StackElement other) {
@@ -478,126 +486,14 @@ else if (isTop() || other.isTop())
478486
return top();
479487
else if (isTopNotJumpdest() || other.isTopNotJumpdest())
480488
return NOT_JUMPDEST_TOP;
481-
else if (n.compareTo(new Number(256)) > 0)
482-
return ZERO;
483-
484-
return new StackElement(
485-
new Number(
486-
new BigInteger(
487-
StackElement.shiftArithmeticRight(
488-
other.n.toByteArray(),
489-
this.n.getInt()))));
490-
}
491-
492-
/**
493-
* Shifts the given byte array to the left by the specified number of bits.
494-
*
495-
* @param byteArray The byte array to be left-shifted.
496-
* @param shiftBitCount The number of bits by which to shift the byte array
497-
* to the left.
498-
*
499-
* @return The resulting byte array after left-shifting by the specified bit
500-
* count.
501-
* <p>
502-
* This method performs a left shift on the provided byte array,
503-
* where each byte is shifted to the left by the given number of
504-
* bits. The shift operation is performed in a bitwise manner,
505-
* and the bits shifted beyond the byte boundary are wrapped
506-
* around to the opposite end. The shift is done in place, and
507-
* the modified byte array is returned as the result.
508-
* </p>
509-
* <p>
510-
* The {@code shiftBitCount} parameter determines the number of
511-
* bits to shift.
512-
* </p>
513-
*
514-
* @throws IllegalArgumentException If the input {@code byteArray} is
515-
* {@code null}.
516-
*/
517-
public static byte[] shiftLeft(byte[] byteArray, int shiftBitCount) {
518-
final int shiftMod = shiftBitCount % 8;
519-
final byte carryMask = (byte) ((1 << shiftMod) - 1);
520-
final int offsetBytes = (shiftBitCount / 8);
489+
else if (n.compareTo(new Number(Number.MAX_INT)) > 0)
490+
return bottom(); // fake path
521491

522-
int start;
492+
int[] bits = BitManager.toBitArray(Number.toBigInteger(other.n));
493+
int[] shiftedBits = BitManager.arithmeticShiftRight(bits, n.getInt());
494+
BigInteger result = BitManager.fromBitArray(shiftedBits);
523495

524-
if (byteArray.length > 32)
525-
start = 1;
526-
else
527-
start = 0;
528-
529-
int sourceIndex;
530-
for (int i = start; i < byteArray.length; i++) {
531-
sourceIndex = i + offsetBytes;
532-
if (sourceIndex >= byteArray.length) {
533-
byteArray[i] = 0;
534-
} else {
535-
byte src = byteArray[sourceIndex];
536-
byte dst = (byte) (src << shiftMod);
537-
if (sourceIndex + 1 < byteArray.length) {
538-
dst |= byteArray[sourceIndex + 1] >>> (8 - shiftMod) & carryMask;
539-
}
540-
byteArray[i] = dst;
541-
}
542-
}
543-
return byteArray;
544-
}
545-
546-
/**
547-
* Shifts the bits of the given byte array towards the least significant bit
548-
* (SAR - Shift Arithmetic Right). The bits moved before the first one are
549-
* discarded, and the new bits are set to 0 if the previous most significant
550-
* bit was 0; otherwise, the new bits are set to 1.
551-
*
552-
* @param byteArray The byte array to be right-shifted.
553-
* @param shiftBitCount The number of bits by which to shift the byte array
554-
* to the right.
555-
*
556-
* @return The resulting byte array after right-shifting by the specified
557-
* bit count.
558-
* <p>
559-
* This method performs a right shift on the provided byte array
560-
* (SAR operation), where each byte is shifted to the right by
561-
* the given number of bits. The shift operation is performed in
562-
* a bitwise manner, and the bits shifted beyond the byte
563-
* boundary are discarded. The new bits introduced during the
564-
* shift are set based on the value of the previous most
565-
* significant bit (0 or 1).
566-
* </p>
567-
* <p>
568-
* The {@code shiftBitCount} parameter determines the number of
569-
* bits to shift.
570-
* </p>
571-
*
572-
* @throws IllegalArgumentException If the input {@code byteArray} is
573-
* {@code null}.
574-
*/
575-
public static byte[] shiftArithmeticRight(byte[] byteArray, int shiftBitCount) {
576-
final int shiftMod = shiftBitCount % 8;
577-
final byte carryMask = (byte) (0xFF << (8 - shiftMod));
578-
final int offsetBytes = (shiftBitCount / 8);
579-
580-
int sourceIndex;
581-
int start;
582-
583-
if (byteArray.length > 32)
584-
start = 1;
585-
else
586-
start = 0;
587-
for (int i = start; i < byteArray.length; i++) {
588-
sourceIndex = i + offsetBytes;
589-
if (sourceIndex >= byteArray.length) {
590-
byteArray[i] = (byte) (byteArray[i] < 0 ? 0xFF : 0);
591-
} else {
592-
byte src = byteArray[sourceIndex];
593-
byte dst = (byte) (src >>> shiftMod);
594-
if (sourceIndex + 1 < byteArray.length) {
595-
dst |= byteArray[sourceIndex + 1] << (8 - shiftMod) & carryMask;
596-
}
597-
byteArray[i] = dst;
598-
}
599-
}
600-
return byteArray;
496+
return new StackElement(new Number(result));
601497
}
602498

603499
/**
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package it.unipr.utils;
2+
3+
import java.math.BigInteger;
4+
5+
public class BitManager {
6+
public static final int SIZE = 256;
7+
8+
/**
9+
* Converts a BigInteger to an array of bits (0s and 1s), MSB first.
10+
*/
11+
public static int[] toBitArray(BigInteger value) {
12+
if (value.signum() < 0) {
13+
throw new IllegalArgumentException("Negative numbers not supported.");
14+
}
15+
16+
String binaryString = value.toString(2); // base 2 string
17+
int[] bits = new int[SIZE];
18+
int padding = SIZE - binaryString.length();
19+
20+
for (int i = 0; i < binaryString.length(); i++) {
21+
bits[padding + i] = (binaryString.charAt(i) == '1') ? 1 : 0;
22+
}
23+
return bits;
24+
}
25+
26+
/**
27+
* Converts an array of bits (0s and 1s), MSB first, to a BigInteger.
28+
*/
29+
public static BigInteger fromBitArray(int[] bits) {
30+
BigInteger result = BigInteger.ZERO;
31+
for (int bit : bits) {
32+
result = result.shiftLeft(1).or(BigInteger.valueOf(bit));
33+
}
34+
return result;
35+
}
36+
37+
/**
38+
* Logical left shift (<<): discards MSBs, fills with 0s at LSBs.
39+
*/
40+
public static int[] shiftLeft(int[] bits, int n) {
41+
if (bits.length != SIZE)
42+
throw new IllegalArgumentException("Input must be 256 bits");
43+
44+
int[] result = new int[SIZE];
45+
if (n >= SIZE)
46+
return result; // all zeros
47+
48+
System.arraycopy(bits, n, result, 0, SIZE - n);
49+
return result;
50+
}
51+
52+
/**
53+
* Logical right shift (>>>): discards LSBs, fills with 0s at MSBs.
54+
*/
55+
public static int[] shiftRight(int[] bits, int n) {
56+
if (bits.length != SIZE)
57+
throw new IllegalArgumentException("Input must be 256 bits");
58+
59+
int[] result = new int[SIZE];
60+
if (n >= SIZE)
61+
return result; // all zeros
62+
63+
System.arraycopy(bits, 0, result, n, SIZE - n);
64+
return result;
65+
}
66+
67+
/**
68+
* Arithmetic right shift (>>): discards LSBs, fills with sign bit at MSBs.
69+
*/
70+
public static int[] arithmeticShiftRight(int[] bits, int n) {
71+
if (bits.length != SIZE)
72+
throw new IllegalArgumentException("Input must be 256 bits");
73+
74+
int[] result = new int[SIZE];
75+
int sign = bits[0]; // MSB = sign bit
76+
if (n >= SIZE) {
77+
// All bits set to sign
78+
for (int i = 0; i < SIZE; i++)
79+
result[i] = sign;
80+
return result;
81+
}
82+
for (int i = 0; i < n; i++)
83+
result[i] = sign;
84+
System.arraycopy(bits, 0, result, n, SIZE - n);
85+
return result;
86+
}
87+
88+
public static void print(String label, int[] bits) {
89+
System.out.print(label + ": ");
90+
for (int b : bits)
91+
System.out.print(b);
92+
System.out.println();
93+
}
94+
}

src/test/java/it/unipr/analysis/cron/semantics/EVMAbstractSemanticsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public void testShr() throws AnalysisSetupException, IOException {
181181
CronConfiguration conf = createConfiguration("cfs", "shr", "shr_eth.sol", false);
182182
perform(conf);
183183
}
184-
184+
185185
@Test
186186
public void testShr2() throws AnalysisSetupException, IOException {
187187
CronConfiguration conf = createConfiguration("cfs", "shr2", "shr_eth.sol", false);
@@ -259,7 +259,7 @@ public void testShl2() throws AnalysisSetupException, IOException {
259259
CronConfiguration conf = createConfiguration("cfs", "shl2", "shl.sol", false);
260260
perform(conf);
261261
}
262-
262+
263263
/**
264264
* All the items in the final stack must be 1
265265
*/

0 commit comments

Comments
 (0)