Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit 570b232

Browse files
authored
Merge pull request #235 from gagliardetto/bad-unsafe
Query to find wrong uses of package "unsafe"
2 parents 534ab94 + 94c0bc3 commit 570b232

7 files changed

Lines changed: 661 additions & 0 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"unsafe"
6+
)
7+
8+
func main() {}
9+
10+
func badArrays() {
11+
// A harmless piece of data:
12+
harmless := [8]byte{'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'}
13+
// Something secret:
14+
secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'}
15+
16+
// The declared `leaking` contains data from `harmless`
17+
// plus the data from `secret`;
18+
// (notice we read more than the length of harmless)
19+
var leaking = (*[8 + 9]byte)(unsafe.Pointer(&harmless)) // BAD
20+
21+
fmt.Println(string((*leaking)[:]))
22+
23+
// Avoid optimization:
24+
if secret[0] == 123 {
25+
fmt.Println("hello world")
26+
}
27+
}
28+
func badIndexExpr() {
29+
// A harmless piece of data:
30+
harmless := [8]byte{'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'}
31+
// Something secret:
32+
secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'}
33+
34+
// Read before secret, overflowing into secret.
35+
// NOTE: unsafe.Pointer(&harmless) != unsafe.Pointer(&harmless[2])
36+
// Even tough harmless and leaking have the same size,
37+
// the new variable `leaking` will contain data starting from
38+
// the address of the 3rd element of the `harmless` array,
39+
// and continue for 8 bytes, going out of the boundaries of
40+
// `harmless` and crossing into the memory occupied by `secret`.
41+
var leaking = (*[8]byte)(unsafe.Pointer(&harmless[2])) // BAD
42+
43+
fmt.Println(string((*leaking)[:]))
44+
45+
// Avoid optimization:
46+
if secret[0] == 123 {
47+
fmt.Println("hello world")
48+
}
49+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"unsafe"
6+
)
7+
8+
func main() {}
9+
10+
func good0() {
11+
// A harmless piece of data:
12+
harmless := [8]byte{'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'}
13+
// Something secret:
14+
secret := [9]byte{'s', 'e', 'n', 's', 'i', 't', 'i', 'v', 'e'}
15+
16+
// Read before secret without overflowing to secret;
17+
// the new `target` variable contains only data
18+
// inside the bounds of `harmless`, without overflowing
19+
// into the memory occupied by `secret`.
20+
var target = (*[8]byte)(unsafe.Pointer(&harmless)) // OK
21+
22+
fmt.Println(string((*target)[:]))
23+
24+
// Avoid optimization:
25+
if secret[0] == 123 {
26+
fmt.Println("hello world")
27+
}
28+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
The package `unsafe` provides operations that step outside the type safety
8+
guarantees normally provided inside Go programs. This leaves room for
9+
errors in the usage of the `unsafe` package that are not caught by the compiler.
10+
</p>
11+
<p>
12+
One possible error is type casting between types of different sizes, that
13+
can result in reads to memory locations that are outside the bounds of
14+
the original target buffer, and also unexpected values.
15+
</p>
16+
</overview>
17+
<recommendation>
18+
<p>
19+
The basic recommendation is to avoid usage of the package `unsafe`. If that is
20+
not an option, you should always check the size of types you cast your data
21+
to/from to make sure they won't result in reading outside of the intended bounds.
22+
</p>
23+
</recommendation>
24+
<example>
25+
<p>
26+
The first example explores a few scenarios of read out of bounds because of an
27+
erroneous type casting done with <code>unsafe.Pointer</code>.
28+
</p>
29+
<sample src="UnsafeUsageBad.go"/>
30+
<p>
31+
The second example show an example of correct type casting done with <code>unsafe.Pointer</code>.
32+
</p>
33+
<sample src="UnsafeUsageOK.go"/>
34+
</example>
35+
<references>
36+
<li>
37+
<a href="https://medium.com/a-journey-with-go/go-what-is-the-unsafe-package-d2443da36350">Go: What is the Unsafe Package?</a>.
38+
</li>
39+
<li>
40+
<a href="https://medium.com/a-journey-with-go/go-cast-vs-conversion-by-example-26e0ef3003f0">Go: Cast vs Conversion by Example</a>.
41+
</li>
42+
<li>
43+
<a href="https://dev.to/jlauinger/exploitation-exercise-with-unsafe-pointer-in-go-information-leak-part-1-1kga">Exploitation Exercise with unsafe.Pointer in Go: Information Leak (Part 1)</a>.
44+
</li>
45+
</references>
46+
</qhelp>
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/**
2+
* @name Wrong usage of package unsafe
3+
* @description Casting between types with different memory sizes can produce reads to
4+
* memory locations that are after the target buffer, and/or unexpected values.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @id go/wrong-usage-of-unsafe
8+
* @tags security
9+
* external/cwe/cwe-119
10+
* external/cwe/cwe-126
11+
*/
12+
13+
import go
14+
import DataFlow::PathGraph
15+
16+
/*
17+
* Returns the type after all aliases, named types, and pointer
18+
* types have been replaced with the actual underlying type.
19+
*/
20+
21+
Type getFinalType(Type typ) { result = getBaseType*(typ.getUnderlyingType()).getUnderlyingType() }
22+
23+
/*
24+
* Returns the base type of a PointerType;
25+
* if the provided type is not a pointer,
26+
* then the original type is returned.
27+
*/
28+
29+
Type getBaseType(Type typ) {
30+
result = getBaseType*(typ.(PointerType).getBaseType*())
31+
or
32+
result = typ
33+
}
34+
35+
/* A conversion to a `unsafe.Pointer` */
36+
class ConversionToUnsafePointer extends DataFlow::TypeCastNode {
37+
ConversionToUnsafePointer() { getFinalType(getType()) instanceof UnsafePointerType }
38+
}
39+
40+
/* Type casting from a `unsafe.Pointer`.*/
41+
class UnsafeTypeCastingConf extends TaintTracking::Configuration {
42+
UnsafeTypeCastingConf() { this = "UnsafeTypeCastingConf" }
43+
44+
predicate isSource(DataFlow::Node source, ConversionToUnsafePointer conv) { source = conv }
45+
46+
predicate isSink(DataFlow::Node sink, DataFlow::TypeCastNode ca) {
47+
ca.getOperand().getType() instanceof UnsafePointerType and
48+
sink = ca
49+
}
50+
51+
override predicate isSource(DataFlow::Node source) { isSource(source, _) }
52+
53+
override predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
54+
}
55+
56+
/*
57+
* Type casting from a shorter array to a longer array
58+
* through the use of unsafe pointers.
59+
*/
60+
61+
predicate castShortArrayToLongerArray(
62+
DataFlow::PathNode source, DataFlow::PathNode sink, string message
63+
) {
64+
exists(
65+
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
66+
ArrayType arrTo, ArrayType arrFrom, int arrFromSize
67+
|
68+
cfg.hasFlowPath(source, sink) and
69+
cfg.isSource(source.getNode(), castLittle) and
70+
cfg.isSink(sink.getNode(), castBig) and
71+
arrTo = getFinalType(castBig.getType()) and
72+
(
73+
// Array (whole) to array:
74+
// The `unsafe.Pointer` expression is on the array
75+
// (e.g. unsafe.Pointer(&someArray)),
76+
// meaning that the pointer points to the start of the array:
77+
arrFrom = getFinalType(castLittle.getOperand().getType()) and
78+
arrFromSize = arrFrom.getLength() and
79+
message = "Dangerous array type casting to " + arrTo.pp() + " from " + arrFrom.pp()
80+
or
81+
// Piece of array (starting from an index), to array:
82+
// The `unsafe.Pointer` expression can also point to a specific
83+
// element of an array
84+
// (e.g. unsafe.Pointer(&someArray[2])),
85+
// which will be the starting point in memory for the newly cast
86+
// variable.
87+
exists(DataFlow::ElementReadNode indexExpr |
88+
indexExpr = castLittle.getOperand().(DataFlow::AddressOperationNode).getOperand() and
89+
// The `arrFrom` is the base of the index expression:
90+
arrFrom = indexExpr.getBase().getType() and
91+
// Calculate the size of the `arrFrom`:
92+
arrFromSize = arrFrom.getLength() - indexExpr.getIndex().getIntValue() and
93+
message =
94+
"Dangerous array type casting to " + arrTo.pp() + " from an index expression (" +
95+
arrFrom.pp() + ")[" + indexExpr.getIndex().getIntValue() + "]" +
96+
" (the destination type is " + (arrTo.getLength() - arrFromSize) + " elements longer)"
97+
)
98+
) and
99+
arrTo.getLength() > arrFromSize
100+
)
101+
}
102+
103+
/*
104+
* Type casting from a type to an array
105+
* through the use of unsafe pointers.
106+
*/
107+
108+
predicate castTypeToArray(DataFlow::PathNode source, DataFlow::PathNode sink, string message) {
109+
exists(
110+
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
111+
ArrayType arrTo, Type typeFrom
112+
|
113+
cfg.hasFlowPath(source, sink) and
114+
cfg.isSource(source.getNode(), castLittle) and
115+
cfg.isSink(sink.getNode(), castBig) and
116+
arrTo = getFinalType(castBig.getType()) and
117+
not typeFrom.getUnderlyingType() instanceof ArrayType and
118+
not typeFrom instanceof PointerType and
119+
not castLittle
120+
.getOperand()
121+
.(DataFlow::AddressOperationNode)
122+
.getOperand()
123+
.(DataFlow::ElementReadNode)
124+
.getBase()
125+
.getType() instanceof ArrayType and
126+
typeFrom = getFinalType(castLittle.getOperand().getType()) and
127+
message = "Dangerous type up-casting to " + arrTo.pp() + " from " + typeFrom
128+
)
129+
}
130+
131+
/*
132+
* Type casting between numeric types that have different bit sizes
133+
* through the use of unsafe pointers.
134+
*/
135+
136+
predicate castDifferentBitSizeNumbers(
137+
DataFlow::PathNode source, DataFlow::PathNode sink, string message
138+
) {
139+
exists(
140+
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
141+
NumericType numTo, NumericType numFrom
142+
|
143+
cfg.hasFlowPath(source, sink) and
144+
cfg.isSource(source.getNode(), castLittle) and
145+
cfg.isSink(sink.getNode(), castBig) and
146+
numTo = getFinalType(castBig.getType()) and
147+
numFrom = getFinalType(castLittle.getOperand().getType()) and
148+
// TODO: also consider cast from uint to int?
149+
getNumericTypeSize(numTo) != getNumericTypeSize(numFrom) and
150+
// Exclude casts to UintptrType (which is still a pointer):
151+
not numTo instanceof UintptrType and
152+
message = "Dangerous numeric type casting to " + numTo.getName() + " from " + numFrom.getName()
153+
)
154+
}
155+
156+
/*
157+
* Returns 0 if the NumericType is one of the numeric
158+
* types that have architecture-specific bit sizes.
159+
*/
160+
161+
int getNumericTypeSize(NumericType typ) {
162+
// If the numeric types have arch-specific
163+
// bit sizes, then set the size to 0 to distinguish
164+
// it from others.
165+
not exists(typ.getSize()) and
166+
result = 0
167+
or
168+
result = typ.getSize()
169+
}
170+
171+
from DataFlow::PathNode source, DataFlow::PathNode sink, string message
172+
where
173+
castShortArrayToLongerArray(source, sink, message) or
174+
castTypeToArray(source, sink, message) or
175+
castDifferentBitSizeNumbers(source, sink, message)
176+
select sink.getNode(), source, sink, "$@.", source.getNode(), message
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
edges
2+
| WrongUsageOfUnsafe.go:17:24:17:48 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:17:13:17:49 | type conversion |
3+
| WrongUsageOfUnsafe.go:34:24:34:51 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:34:13:34:52 | type conversion |
4+
| WrongUsageOfUnsafe.go:55:24:55:51 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:55:13:55:52 | type conversion |
5+
| WrongUsageOfUnsafe.go:77:27:77:54 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion |
6+
| WrongUsageOfUnsafe.go:93:20:93:44 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:93:13:93:45 | type conversion |
7+
| WrongUsageOfUnsafe.go:111:31:111:58 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion |
8+
| WrongUsageOfUnsafe.go:129:31:129:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion |
9+
| WrongUsageOfUnsafe.go:149:31:149:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion |
10+
| WrongUsageOfUnsafe.go:166:33:166:57 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion |
11+
| WrongUsageOfUnsafe.go:189:31:189:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion |
12+
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion |
13+
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:236:21:236:23 | definition of req : unsafe.Pointer |
14+
| WrongUsageOfUnsafe.go:236:21:236:23 | definition of req : unsafe.Pointer | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion |
15+
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion |
16+
| WrongUsageOfUnsafe.go:274:25:274:49 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion |
17+
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion |
18+
nodes
19+
| WrongUsageOfUnsafe.go:17:13:17:49 | type conversion | semmle.label | type conversion |
20+
| WrongUsageOfUnsafe.go:17:24:17:48 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
21+
| WrongUsageOfUnsafe.go:34:13:34:52 | type conversion | semmle.label | type conversion |
22+
| WrongUsageOfUnsafe.go:34:24:34:51 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
23+
| WrongUsageOfUnsafe.go:55:13:55:52 | type conversion | semmle.label | type conversion |
24+
| WrongUsageOfUnsafe.go:55:24:55:51 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
25+
| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | semmle.label | type conversion |
26+
| WrongUsageOfUnsafe.go:77:27:77:54 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
27+
| WrongUsageOfUnsafe.go:93:13:93:45 | type conversion | semmle.label | type conversion |
28+
| WrongUsageOfUnsafe.go:93:20:93:44 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
29+
| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | semmle.label | type conversion |
30+
| WrongUsageOfUnsafe.go:111:31:111:58 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
31+
| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | semmle.label | type conversion |
32+
| WrongUsageOfUnsafe.go:129:31:129:55 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
33+
| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | semmle.label | type conversion |
34+
| WrongUsageOfUnsafe.go:149:31:149:55 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
35+
| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | semmle.label | type conversion |
36+
| WrongUsageOfUnsafe.go:166:33:166:57 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
37+
| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | semmle.label | type conversion |
38+
| WrongUsageOfUnsafe.go:189:31:189:55 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
39+
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | semmle.label | type conversion |
40+
| WrongUsageOfUnsafe.go:211:31:211:60 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
41+
| WrongUsageOfUnsafe.go:227:31:227:55 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
42+
| WrongUsageOfUnsafe.go:236:21:236:23 | definition of req : unsafe.Pointer | semmle.label | definition of req : unsafe.Pointer |
43+
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | semmle.label | type conversion |
44+
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | semmle.label | type conversion |
45+
| WrongUsageOfUnsafe.go:256:28:256:52 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
46+
| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | semmle.label | type conversion |
47+
| WrongUsageOfUnsafe.go:274:25:274:49 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
48+
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | semmle.label | type conversion |
49+
| WrongUsageOfUnsafe.go:292:23:292:47 | type conversion : unsafe.Pointer | semmle.label | type conversion : unsafe.Pointer |
50+
#select
51+
| WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:77:16:77:55 | type conversion | $@. | WrongUsageOfUnsafe.go:77:27:77:54 | type conversion | Dangerous array type casting to [8]uint8 from an index expression ([8]uint8)[2] (the destination type is 2 elements longer) |
52+
| WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:111:16:111:59 | type conversion | $@. | WrongUsageOfUnsafe.go:111:31:111:58 | type conversion | Dangerous array type casting to [17]uint8 from an index expression ([8]uint8)[0] (the destination type is 9 elements longer) |
53+
| WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:129:16:129:56 | type conversion | $@. | WrongUsageOfUnsafe.go:129:31:129:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
54+
| WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:149:16:149:56 | type conversion | $@. | WrongUsageOfUnsafe.go:149:31:149:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
55+
| WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:166:16:166:58 | type conversion | $@. | WrongUsageOfUnsafe.go:166:33:166:57 | type conversion | Dangerous array type casting to [17]string from [8]string |
56+
| WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:189:16:189:56 | type conversion | $@. | WrongUsageOfUnsafe.go:189:31:189:55 | type conversion | Dangerous type up-casting to [17]uint8 from struct type |
57+
| WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:211:16:211:61 | type conversion | $@. | WrongUsageOfUnsafe.go:211:31:211:60 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
58+
| WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:243:9:243:27 | type conversion | $@. | WrongUsageOfUnsafe.go:227:31:227:55 | type conversion | Dangerous array type casting to [17]uint8 from [8]uint8 |
59+
| WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:256:16:256:53 | type conversion | $@. | WrongUsageOfUnsafe.go:256:28:256:52 | type conversion | Dangerous array type casting to [4]int64 from [1]int64 |
60+
| WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:274:16:274:50 | type conversion | $@. | WrongUsageOfUnsafe.go:274:25:274:49 | type conversion | Dangerous numeric type casting to int64 from int8 |
61+
| WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion : unsafe.Pointer | WrongUsageOfUnsafe.go:292:16:292:48 | type conversion | $@. | WrongUsageOfUnsafe.go:292:23:292:47 | type conversion | Dangerous numeric type casting to int from int8 |

0 commit comments

Comments
 (0)