-
Notifications
You must be signed in to change notification settings - Fork 2k
feat(lint): add UnsafeTypecast lint #11046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(lint): add UnsafeTypecast lint #11046
Conversation
@@ -353,7 +353,7 @@ jiff = "0.2" | |||
heck = "0.5" | |||
uuid = "1.17.0" | |||
flate2 = "1.1" | |||
|
|||
num-bigint = "0.4" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
@@ -0,0 +1,106 @@ | |||
contract UnsafeTypecast { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current throws false positives when typecasting to the same type or upcasting. We need more granular tests, here's some tests that ensure uint/int downcasts always trigger and upcasts never trigger.
contract UnsafeTypecast { | |
contract UnsafeTypecast { | |
function upcastSafeUint() public pure { | |
uint8 a = type(uint8).max; | |
uint16 b = uint16(a); | |
uint24 c = uint24(b); | |
uint32 d = uint32(c); | |
uint40 e = uint40(d); | |
uint48 f = uint48(e); | |
uint56 g = uint56(f); | |
uint64 h = uint64(g); | |
uint72 i = uint72(h); | |
uint80 j = uint80(i); | |
uint88 k = uint88(j); | |
uint96 l = uint96(k); | |
uint104 m = uint104(l); | |
uint112 n = uint112(m); | |
uint120 o = uint120(n); | |
uint128 p = uint128(o); | |
uint136 q = uint136(p); | |
uint144 r = uint144(q); | |
uint152 s = uint152(r); | |
uint160 t = uint160(s); | |
uint168 u = uint168(t); | |
uint176 v = uint176(u); | |
uint184 w = uint184(v); | |
uint192 x = uint192(w); | |
uint200 y = uint200(x); | |
uint208 z = uint208(y); | |
uint216 A = uint216(z); | |
uint224 B = uint224(A); | |
uint232 C = uint232(B); | |
uint240 D = uint240(C); | |
uint248 E = uint248(D); | |
uint256 F = uint256(E); | |
} | |
function upcastSafeInt() public pure { | |
int8 a = type(int8).max; | |
int16 b = int16(a); | |
int24 c = int24(b); | |
int32 d = int32(c); | |
int40 e = int40(d); | |
int48 f = int48(e); | |
int56 g = int56(f); | |
int64 h = int64(g); | |
int72 i = int72(h); | |
int80 j = int80(i); | |
int88 k = int88(j); | |
int96 l = int96(k); | |
int104 m = int104(l); | |
int112 n = int112(m); | |
int120 o = int120(n); | |
int128 p = int128(o); | |
int136 q = int136(p); | |
int144 r = int144(q); | |
int152 s = int152(r); | |
int160 t = int160(s); | |
int168 u = int168(t); | |
int176 v = int176(u); | |
int184 w = int184(v); | |
int192 x = int192(w); | |
int200 y = int200(x); | |
int208 z = int208(y); | |
int216 A = int216(z); | |
int224 B = int224(A); | |
int232 C = int232(B); | |
int240 D = int240(C); | |
int248 E = int248(D); | |
int256 F = int256(E); | |
} | |
function downcastSafeUint() public pure { | |
uint256 a = type(uint256).max; | |
uint248 b = uint248(a); //~WARN: typecasts that can truncate values should be avoided | |
uint240 c = uint240(b); //~WARN: typecasts that can truncate values should be avoided | |
uint232 d = uint232(c); //~WARN: typecasts that can truncate values should be avoided | |
uint224 e = uint224(d); //~WARN: typecasts that can truncate values should be avoided | |
uint216 f = uint216(e); //~WARN: typecasts that can truncate values should be avoided | |
uint208 g = uint208(f); //~WARN: typecasts that can truncate values should be avoided | |
uint200 h = uint200(g); //~WARN: typecasts that can truncate values should be avoided | |
uint192 i = uint192(h); //~WARN: typecasts that can truncate values should be avoided | |
uint184 j = uint184(i); //~WARN: typecasts that can truncate values should be avoided | |
uint176 k = uint176(j); //~WARN: typecasts that can truncate values should be avoided | |
uint168 l = uint168(k); //~WARN: typecasts that can truncate values should be avoided | |
uint160 m = uint160(l); //~WARN: typecasts that can truncate values should be avoided | |
uint152 n = uint152(m); //~WARN: typecasts that can truncate values should be avoided | |
uint144 o = uint144(n); //~WARN: typecasts that can truncate values should be avoided | |
uint136 p = uint136(o); //~WARN: typecasts that can truncate values should be avoided | |
uint128 q = uint128(p); //~WARN: typecasts that can truncate values should be avoided | |
uint120 r = uint120(q); //~WARN: typecasts that can truncate values should be avoided | |
uint112 s = uint112(r); //~WARN: typecasts that can truncate values should be avoided | |
uint104 t = uint104(s); //~WARN: typecasts that can truncate values should be avoided | |
uint96 u = uint96(t); //~WARN: typecasts that can truncate values should be avoided | |
uint88 v = uint88(u); //~WARN: typecasts that can truncate values should be avoided | |
uint80 w = uint80(v); //~WARN: typecasts that can truncate values should be avoided | |
uint72 x = uint72(w); //~WARN: typecasts that can truncate values should be avoided | |
uint64 y = uint64(x); //~WARN: typecasts that can truncate values should be avoided | |
uint56 z = uint56(y); //~WARN: typecasts that can truncate values should be avoided | |
uint48 A = uint48(z); //~WARN: typecasts that can truncate values should be avoided | |
uint40 B = uint40(A); //~WARN: typecasts that can truncate values should be avoided | |
uint32 C = uint32(B); //~WARN: typecasts that can truncate values should be avoided | |
uint24 D = uint24(C); //~WARN: typecasts that can truncate values should be avoided | |
uint16 E = uint16(D); //~WARN: typecasts that can truncate values should be avoided | |
uint8 F = uint8(E); //~WARN: typecasts that can truncate values should be avoided | |
} | |
function downcastSafeInt() public pure { | |
int256 a = type(int256).max; | |
int248 b = int248(a); //~WARN: typecasts that can truncate values should be avoided | |
int240 c = int240(b); //~WARN: typecasts that can truncate values should be avoided | |
int232 d = int232(c); //~WARN: typecasts that can truncate values should be avoided | |
int224 e = int224(d); //~WARN: typecasts that can truncate values should be avoided | |
int216 f = int216(e); //~WARN: typecasts that can truncate values should be avoided | |
int208 g = int208(f); //~WARN: typecasts that can truncate values should be avoided | |
int200 h = int200(g); //~WARN: typecasts that can truncate values should be avoided | |
int192 i = int192(h); //~WARN: typecasts that can truncate values should be avoided | |
int184 j = int184(i); //~WARN: typecasts that can truncate values should be avoided | |
int176 k = int176(j); //~WARN: typecasts that can truncate values should be avoided | |
int168 l = int168(k); //~WARN: typecasts that can truncate values should be avoided | |
int160 m = int160(l); //~WARN: typecasts that can truncate values should be avoided | |
int152 n = int152(m); //~WARN: typecasts that can truncate values should be avoided | |
int144 o = int144(n); //~WARN: typecasts that can truncate values should be avoided | |
int136 p = int136(o); //~WARN: typecasts that can truncate values should be avoided | |
int128 q = int128(p); //~WARN: typecasts that can truncate values should be avoided | |
int120 r = int120(q); //~WARN: typecasts that can truncate values should be avoided | |
int112 s = int112(r); //~WARN: typecasts that can truncate values should be avoided | |
int104 t = int104(s); //~WARN: typecasts that can truncate values should be avoided | |
int96 u = int96(t); //~WARN: typecasts that can truncate values should be avoided | |
int88 v = int88(u); //~WARN: typecasts that can truncate values should be avoided | |
int80 w = int80(v); //~WARN: typecasts that can truncate values should be avoided | |
int72 x = int72(w); //~WARN: typecasts that can truncate values should be avoided | |
int64 y = int64(x); //~WARN: typecasts that can truncate values should be avoided | |
int56 z = int56(y); //~WARN: typecasts that can truncate values should be avoided | |
int48 A = int48(z); //~WARN: typecasts that can truncate values should be avoided | |
int40 B = int40(A); //~WARN: typecasts that can truncate values should be avoided | |
int32 C = int32(B); //~WARN: typecasts that can truncate values should be avoided | |
int24 D = int24(C); //~WARN: typecasts that can truncate values should be avoided | |
int16 E = int16(D); //~WARN: typecasts that can truncate values should be avoided | |
int8 F = int8(E); //~WARN: typecasts that can truncate values should be avoided | |
} | |
} |
warning[unsafe-typecast]: typecasts that can truncate values should be avoided | ||
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC | ||
| | ||
5 | uint128 b = uint128(a); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint128 -> uint128 is safe
uintN -> uintN is always safe
intN -> intN is always safe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a is an address
type so i think it still unsafe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely ensure the compiler isn't catching some of these, cannot directly convert an address to uint128 without a compile error.
warning[unsafe-typecast]: typecasts that can truncate values should be avoided | ||
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC | ||
| | ||
94 | uint128 a = uint128(1000000000000000000000000000000000000000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure the compiler prevents you from downcasting a literal that's smaller than the target type size.
warning[unsafe-typecast]: typecasts that can truncate values should be avoided | ||
--> ROOT/testdata/UnsafeTypecast.sol:LL:CC | ||
| | ||
8 | uint64 c = uint64(a); | ||
| --------- | ||
| | ||
= help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,106 @@ | |||
contract UnsafeTypecast { | |||
function numericDowncasts() public { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will also want a test for uint
to int
same size (unsafe since integers have leading sign bit).
Also a test for int
to uint
same size (safe since type(uintN).max > type(intN).max
)
function numericDowncasts() public { | |
function numericDowncasts() public { | |
function unsafeUintToIntSameSize() public pure { | |
uint256 a = type(uint256).max; | |
int256 b = int256(a); //~WARN: typecasts that can truncate values should be avoided | |
uint248 c = type(uint248).max; | |
int248 d = int248(c); //~WARN: typecasts that can truncate values should be avoided | |
uint240 e = type(uint240).max; | |
int240 f = int240(e); //~WARN: typecasts that can truncate values should be avoided | |
uint232 g = type(uint232).max; | |
int232 h = int232(g); //~WARN: typecasts that can truncate values should be avoided | |
uint224 i = type(uint224).max; | |
int224 j = int224(i); //~WARN: typecasts that can truncate values should be avoided | |
uint216 k = type(uint216).max; | |
int216 l = int216(k); //~WARN: typecasts that can truncate values should be avoided | |
uint208 m = type(uint208).max; | |
int208 n = int208(m); //~WARN: typecasts that can truncate values should be avoided | |
uint200 o = type(uint200).max; | |
int200 p = int200(o); //~WARN: typecasts that can truncate values should be avoided | |
uint192 q = type(uint192).max; | |
int192 r = int192(q); //~WARN: typecasts that can truncate values should be avoided | |
uint184 s = type(uint184).max; | |
int184 t = int184(s); //~WARN: typecasts that can truncate values should be avoided | |
uint176 u = type(uint176).max; | |
int176 v = int176(u); //~WARN: typecasts that can truncate values should be avoided | |
uint168 w = type(uint168).max; | |
int168 x = int168(w); //~WARN: typecasts that can truncate values should be avoided | |
uint160 y = type(uint160).max; | |
int160 z = int160(y); //~WARN: typecasts that can truncate values should be avoided | |
uint152 A = type(uint152).max; | |
int152 B = int152(A); //~WARN: typecasts that can truncate values should be avoided | |
uint144 C = type(uint144).max; | |
int144 D = int144(C); //~WARN: typecasts that can truncate values should be avoided | |
uint136 E = type(uint136).max; | |
int136 F = int136(E); //~WARN: typecasts that can truncate values should be avoided | |
uint128 G = type(uint128).max; | |
int128 H = int128(G); //~WARN: typecasts that can truncate values should be avoided | |
uint120 I = type(uint120).max; | |
int120 J = int120(I); //~WARN: typecasts that can truncate values should be avoided | |
uint112 K = type(uint112).max; | |
int112 L = int112(K); //~WARN: typecasts that can truncate values should be avoided | |
uint104 M = type(uint104).max; | |
int104 N = int104(M); //~WARN: typecasts that can truncate values should be avoided | |
uint96 O = type(uint96).max; | |
int96 P = int96(O); //~WARN: typecasts that can truncate values should be avoided | |
uint88 Q = type(uint88).max; | |
int88 R = int88(Q); //~WARN: typecasts that can truncate values should be avoided | |
uint80 S = type(uint80).max; | |
int80 T = int80(S); //~WARN: typecasts that can truncate values should be avoided | |
uint72 U = type(uint72).max; | |
int72 V = int72(U); //~WARN: typecasts that can truncate values should be avoided | |
uint64 W = type(uint64).max; | |
int64 X = int64(W); //~WARN: typecasts that can truncate values should be avoided | |
uint56 Y = type(uint56).max; | |
int56 Z = int56(Y); //~WARN: typecasts that can truncate values should be avoided | |
uint48 a1 = type(uint48).max; | |
int48 b1 = int48(a1); //~WARN: typecasts that can truncate values should be avoided | |
uint40 c1 = type(uint40).max; | |
int40 d1 = int40(c1); //~WARN: typecasts that can truncate values should be avoided | |
uint32 e1 = type(uint32).max; | |
int32 f1 = int32(e1); //~WARN: typecasts that can truncate values should be avoided | |
uint24 g1 = type(uint24).max; | |
int24 h1 = int24(g1); //~WARN: typecasts that can truncate values should be avoided | |
uint16 i1 = type(uint16).max; | |
int16 j1 = int16(i1); //~WARN: typecasts that can truncate values should be avoided | |
uint8 k1 = type(uint8).max; | |
int8 l1 = int8(k1); //~WARN: typecasts that can truncate values should be avoided | |
} |
Motivation
Closes #11029
Solution
PR Checklist