Skip to content

Commit

Permalink
Make out of range long or int casts throw :ARGUMENT
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Oct 1, 2024
1 parent 9cf7653 commit de1a4c7
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 18 deletions.
2 changes: 2 additions & 0 deletions convex-core/src/main/java/convex/core/data/Blob.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class Blob extends AArrayBlob {
public static final Blob EMPTY = Cells.intern(wrap(Utils.EMPTY_BYTES));
public static final Blob SINGLE_ZERO = Cells.intern(wrap(new byte[] {0}));
public static final Blob SINGLE_ONE = Cells.intern(wrap(new byte[] {1}));
public static final Blob SINGLE_A =wrap(new byte[] {0x41});

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

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


@Override
public boolean isCanonical() {
return count <= Blob.CHUNK_LENGTH;
Expand Down
4 changes: 2 additions & 2 deletions convex-core/src/main/java/convex/core/data/type/Blob.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
public class Blob extends AStandardType<ABlob> {

public static final Blob INSTANCE = new Blob();

private Blob() {
super(ABlob.class);
}
Expand All @@ -26,7 +26,7 @@ public String toString() {

@Override
public ABlob defaultValue() {
return convex.core.data.Blob.EMPTY;
return convex.core.data.Blob.SINGLE_A;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public String toString () {

@Override
public CVMDouble defaultValue() {
return CVMDouble.ZERO;
return CVMDouble.ONE;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public String toString () {

@Override
public AInteger defaultValue() {
return CVMLong.ZERO;
return CVMLong.ONE;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* Type that represents CVM Byte values
*/
public final class StringType extends AStandardType<AString> {

private static final StringShort DEFAULT_VALUE=StringShort.create("A");
/**
* Singleton runtime instance
*/
Expand All @@ -30,7 +32,7 @@ public String toString () {

@Override
public AString defaultValue() {
return StringShort.EMPTY;
return DEFAULT_VALUE;
}

@Override
Expand Down
10 changes: 8 additions & 2 deletions convex-core/src/main/java/convex/core/lang/Core.java
Original file line number Diff line number Diff line change
Expand Up @@ -1759,7 +1759,10 @@ public Context invoke(Context context, ACell[] args) {

ACell a = args[0];
CVMLong result = RT.castLong(a);
if (result == null) return context.withCastError(0, args,Types.LONG);
if (result == null) {
if (a instanceof ANumeric) return context.withArgumentError("Out of range");
return context.withCastError(0, args,Types.LONG);
}

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

ACell a = args[0];
AInteger result = RT.castInteger(a);
if (result == null) return context.withCastError(0, args,Types.INTEGER);
if (result == null) {
if (a instanceof ANumeric) return context.withArgumentError("Out of range");
return context.withCastError(0, args,Types.INTEGER);
}
// TODO: bigint construction cost?
return context.withResult(Juice.ARITHMETIC, result);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package convex.core.lang.exception;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import convex.core.ErrorCodes;
import convex.core.data.ACell;
import convex.core.data.AString;
import convex.core.data.Address;
Expand All @@ -28,17 +30,32 @@
*/
public class ErrorValue extends AThrowable {

private static final HashMap<Keyword,ErrorValue> defaultErrors= new HashMap<>();

private final ACell message;
private final ArrayList<AString> trace=new ArrayList<>();
private ACell log;
private Address address=null;

static {
addDefaultError(ErrorCodes.ARGUMENT,"Invalid argument value");
addDefaultError(ErrorCodes.NOBODY,"Account does not exist");
}

private ErrorValue(ACell code, ACell message) {
super (code);
this.message=message;
}

private static void addDefaultError(Keyword code, String message) {
defaultErrors.put(code,create(code,message));
}

public static ErrorValue create(Keyword code) {
if (defaultErrors.containsKey(code)) {
return defaultErrors.get(code);
}

return new ErrorValue(code,null);
}

Expand Down
18 changes: 17 additions & 1 deletion convex-core/src/test/java/convex/core/lang/CastTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;

import org.junit.jupiter.api.Test;

import convex.core.ErrorCodes;
import convex.core.data.ACell;
import convex.core.data.Address;
import convex.core.data.Strings;
import convex.core.data.Symbol;
import convex.core.data.prim.CVMChar;
import convex.core.data.type.AType;

import static convex.test.Assertions.*;

public class CastTest extends ACVMTest {

static final String[] casts = new String[] {"double","int", "long", "boolean","blob","address", "str","name","symbol","keyword","char"};
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"};

@Test
public void testRoundTrips() {
assertCVMEquals(1L,eval("(long (address 1))"));
assertCVMEquals(Address.ZERO,eval("(address (blob #0))"));
}

@Test
public void testAllCasts() {
for (String c: casts) {
Expand All @@ -25,7 +36,12 @@ public void testAllCasts() {
if (ctx.isError()) {
ACell code=ctx.getErrorCode();
if (ErrorCodes.ARGUMENT.equals(code)) {
// anything to test?
// the default value should be in range
AType type=RT.getType(Reader.read(v));
Context nctx=step("("+c+" "+RT.print(type.defaultValue())+")");
if (nctx.isError()) {
fail("ARGUMENT fallback not working in: "+cmd);
}
} else {
assertEquals(ErrorCodes.CAST,code,()->"Unexpected "+code+" in "+cmd);
}
Expand Down
22 changes: 12 additions & 10 deletions convex-core/src/test/java/convex/core/lang/CoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,11 @@ public void testLong() {
assertEquals(9007199254740992L,evalL("(long 9007199254740992.0)")); // 2^53
assertEquals(9007199254740992L,evalL("(long (double 9007199254740993))"));

// Cast errors on non-finite doubles
assertCastError(step("(long ##NaN)"));
assertCastError(step("(long ##Inf)"));
assertCastError(step("(long ##-Inf)"));
// :ARGUMENT errors on non-finite or out of range doubles
assertArgumentError(step("(long ##NaN)"));
assertArgumentError(step("(long ##Inf)"));
assertArgumentError(step("(long ##-Inf)"));
assertArgumentError(step("(long 1e50)"));

assertArityError(step("(long)"));
assertArityError(step("(long 1 2)"));
Expand All @@ -436,9 +437,9 @@ public void testLong() {
// Long limits and overflow
assertEquals(Long.MAX_VALUE,evalL("(long 9223372036854775807)"));
assertEquals(Long.MIN_VALUE,evalL("(long -9223372036854775808)"));
assertCastError(step("(long 18446744073709551616)"));
assertCastError(step("(long 9223372036854775808)"));
assertCastError(step("(long -9223372036854775809)"));
assertArgumentError(step("(long 18446744073709551616)"));
assertArgumentError(step("(long 9223372036854775808)"));
assertArgumentError(step("(long -9223372036854775809)"));

}

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

assertCastError(step("(int ##NaN)"));
assertCastError(step("(int ##Inf)"));
assertCastError(step("(int ##-Inf)"));
// These are :ARGUMENT error because of out of range. Other doubles might work.
assertArgumentError(step("(int ##NaN)"));
assertArgumentError(step("(int ##Inf)"));
assertArgumentError(step("(int ##-Inf)"));

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

0 comments on commit de1a4c7

Please sign in to comment.