Skip to content

Commit de1a4c7

Browse files
committed
Make out of range long or int casts throw :ARGUMENT
1 parent 9cf7653 commit de1a4c7

File tree

9 files changed

+63
-18
lines changed

9 files changed

+63
-18
lines changed

convex-core/src/main/java/convex/core/data/Blob.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class Blob extends AArrayBlob {
2424
public static final Blob EMPTY = Cells.intern(wrap(Utils.EMPTY_BYTES));
2525
public static final Blob SINGLE_ZERO = Cells.intern(wrap(new byte[] {0}));
2626
public static final Blob SINGLE_ONE = Cells.intern(wrap(new byte[] {1}));
27+
public static final Blob SINGLE_A =wrap(new byte[] {0x41});
2728

2829
public static final Blob NULL_ENCODING = Blob.wrap(new byte[] {Tag.NULL});
2930

@@ -251,6 +252,7 @@ public int estimatedEncodingSize() {
251252
*/
252253
public static final int MAX_ENCODING_LENGTH=1+Format.getVLCCountLength(CHUNK_LENGTH)+CHUNK_LENGTH;
253254

255+
254256
@Override
255257
public boolean isCanonical() {
256258
return count <= Blob.CHUNK_LENGTH;

convex-core/src/main/java/convex/core/data/type/Blob.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
public class Blob extends AStandardType<ABlob> {
1010

1111
public static final Blob INSTANCE = new Blob();
12-
12+
1313
private Blob() {
1414
super(ABlob.class);
1515
}
@@ -26,7 +26,7 @@ public String toString() {
2626

2727
@Override
2828
public ABlob defaultValue() {
29-
return convex.core.data.Blob.EMPTY;
29+
return convex.core.data.Blob.SINGLE_A;
3030
}
3131

3232
@Override

convex-core/src/main/java/convex/core/data/type/Double.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public String toString () {
3030

3131
@Override
3232
public CVMDouble defaultValue() {
33-
return CVMDouble.ZERO;
33+
return CVMDouble.ONE;
3434
}
3535

3636
@Override

convex-core/src/main/java/convex/core/data/type/Integer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public String toString () {
3131

3232
@Override
3333
public AInteger defaultValue() {
34-
return CVMLong.ZERO;
34+
return CVMLong.ONE;
3535
}
3636

3737
@Override

convex-core/src/main/java/convex/core/data/type/StringType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
* Type that represents CVM Byte values
99
*/
1010
public final class StringType extends AStandardType<AString> {
11+
12+
private static final StringShort DEFAULT_VALUE=StringShort.create("A");
1113
/**
1214
* Singleton runtime instance
1315
*/
@@ -30,7 +32,7 @@ public String toString () {
3032

3133
@Override
3234
public AString defaultValue() {
33-
return StringShort.EMPTY;
35+
return DEFAULT_VALUE;
3436
}
3537

3638
@Override

convex-core/src/main/java/convex/core/lang/Core.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,7 +1759,10 @@ public Context invoke(Context context, ACell[] args) {
17591759

17601760
ACell a = args[0];
17611761
CVMLong result = RT.castLong(a);
1762-
if (result == null) return context.withCastError(0, args,Types.LONG);
1762+
if (result == null) {
1763+
if (a instanceof ANumeric) return context.withArgumentError("Out of range");
1764+
return context.withCastError(0, args,Types.LONG);
1765+
}
17631766

17641767
return context.withResult(Juice.ARITHMETIC, result);
17651768
}
@@ -1773,7 +1776,10 @@ public Context invoke(Context context, ACell[] args) {
17731776

17741777
ACell a = args[0];
17751778
AInteger result = RT.castInteger(a);
1776-
if (result == null) return context.withCastError(0, args,Types.INTEGER);
1779+
if (result == null) {
1780+
if (a instanceof ANumeric) return context.withArgumentError("Out of range");
1781+
return context.withCastError(0, args,Types.INTEGER);
1782+
}
17771783
// TODO: bigint construction cost?
17781784
return context.withResult(Juice.ARITHMETIC, result);
17791785
}

convex-core/src/main/java/convex/core/lang/exception/ErrorValue.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package convex.core.lang.exception;
22

33
import java.util.ArrayList;
4+
import java.util.HashMap;
45
import java.util.List;
56

7+
import convex.core.ErrorCodes;
68
import convex.core.data.ACell;
79
import convex.core.data.AString;
810
import convex.core.data.Address;
@@ -28,17 +30,32 @@
2830
*/
2931
public class ErrorValue extends AThrowable {
3032

33+
private static final HashMap<Keyword,ErrorValue> defaultErrors= new HashMap<>();
34+
3135
private final ACell message;
3236
private final ArrayList<AString> trace=new ArrayList<>();
3337
private ACell log;
3438
private Address address=null;
39+
40+
static {
41+
addDefaultError(ErrorCodes.ARGUMENT,"Invalid argument value");
42+
addDefaultError(ErrorCodes.NOBODY,"Account does not exist");
43+
}
3544

3645
private ErrorValue(ACell code, ACell message) {
3746
super (code);
3847
this.message=message;
3948
}
4049

50+
private static void addDefaultError(Keyword code, String message) {
51+
defaultErrors.put(code,create(code,message));
52+
}
53+
4154
public static ErrorValue create(Keyword code) {
55+
if (defaultErrors.containsKey(code)) {
56+
return defaultErrors.get(code);
57+
}
58+
4259
return new ErrorValue(code,null);
4360
}
4461

convex-core/src/test/java/convex/core/lang/CastTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,31 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertNotNull;
5+
import static org.junit.jupiter.api.Assertions.fail;
56

67
import org.junit.jupiter.api.Test;
78

89
import convex.core.ErrorCodes;
910
import convex.core.data.ACell;
11+
import convex.core.data.Address;
1012
import convex.core.data.Strings;
1113
import convex.core.data.Symbol;
1214
import convex.core.data.prim.CVMChar;
15+
import convex.core.data.type.AType;
16+
17+
import static convex.test.Assertions.*;
1318

1419
public class CastTest extends ACVMTest {
1520

1621
static final String[] casts = new String[] {"double","int", "long", "boolean","blob","address", "str","name","symbol","keyword","char"};
1722
static final String[] vals = new String[] {"##Inf","1e308","0.0", "-0.0", "999999999999999999999999999", "9223372036854775807", "1","0","-1","0xcafebabe1234567890","0x41","0x","\\c","\\u0474", "\"hello\"","\"\"","#12",":foo","'baz","true","false","nil"};
1823

24+
@Test
25+
public void testRoundTrips() {
26+
assertCVMEquals(1L,eval("(long (address 1))"));
27+
assertCVMEquals(Address.ZERO,eval("(address (blob #0))"));
28+
}
29+
1930
@Test
2031
public void testAllCasts() {
2132
for (String c: casts) {
@@ -25,7 +36,12 @@ public void testAllCasts() {
2536
if (ctx.isError()) {
2637
ACell code=ctx.getErrorCode();
2738
if (ErrorCodes.ARGUMENT.equals(code)) {
28-
// anything to test?
39+
// the default value should be in range
40+
AType type=RT.getType(Reader.read(v));
41+
Context nctx=step("("+c+" "+RT.print(type.defaultValue())+")");
42+
if (nctx.isError()) {
43+
fail("ARGUMENT fallback not working in: "+cmd);
44+
}
2945
} else {
3046
assertEquals(ErrorCodes.CAST,code,()->"Unexpected "+code+" in "+cmd);
3147
}

convex-core/src/test/java/convex/core/lang/CoreTest.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,11 @@ public void testLong() {
417417
assertEquals(9007199254740992L,evalL("(long 9007199254740992.0)")); // 2^53
418418
assertEquals(9007199254740992L,evalL("(long (double 9007199254740993))"));
419419

420-
// Cast errors on non-finite doubles
421-
assertCastError(step("(long ##NaN)"));
422-
assertCastError(step("(long ##Inf)"));
423-
assertCastError(step("(long ##-Inf)"));
420+
// :ARGUMENT errors on non-finite or out of range doubles
421+
assertArgumentError(step("(long ##NaN)"));
422+
assertArgumentError(step("(long ##Inf)"));
423+
assertArgumentError(step("(long ##-Inf)"));
424+
assertArgumentError(step("(long 1e50)"));
424425

425426
assertArityError(step("(long)"));
426427
assertArityError(step("(long 1 2)"));
@@ -436,9 +437,9 @@ public void testLong() {
436437
// Long limits and overflow
437438
assertEquals(Long.MAX_VALUE,evalL("(long 9223372036854775807)"));
438439
assertEquals(Long.MIN_VALUE,evalL("(long -9223372036854775808)"));
439-
assertCastError(step("(long 18446744073709551616)"));
440-
assertCastError(step("(long 9223372036854775808)"));
441-
assertCastError(step("(long -9223372036854775809)"));
440+
assertArgumentError(step("(long 18446744073709551616)"));
441+
assertArgumentError(step("(long 9223372036854775808)"));
442+
assertArgumentError(step("(long -9223372036854775809)"));
442443

443444
}
444445

@@ -468,9 +469,10 @@ public void testInt() {
468469
assertEquals(CVMLong.MAX_VALUE,eval("(int 9223372036854775807.0)")); // actual max value
469470
assertEquals(CVMLong.MAX_VALUE,eval("(int 9223372036854775809.0)")); // above max value
470471

471-
assertCastError(step("(int ##NaN)"));
472-
assertCastError(step("(int ##Inf)"));
473-
assertCastError(step("(int ##-Inf)"));
472+
// These are :ARGUMENT error because of out of range. Other doubles might work.
473+
assertArgumentError(step("(int ##NaN)"));
474+
assertArgumentError(step("(int ##Inf)"));
475+
assertArgumentError(step("(int ##-Inf)"));
474476

475477
// Currently we disallow bools to explicitly cast to longs. Not round trippable
476478
assertCastError(step("(int true)"));

0 commit comments

Comments
 (0)