-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
48 changed files
with
2,176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--- | ||
id: detectors | ||
title: Detectors Overview | ||
--- | ||
|
||
# Detectors Overview | ||
|
||
## Built-in Detectors | ||
|
||
| # | Detector | Severity | Requires Soufflé | Enabled by default | | ||
|----|-----------|-----------|--------------------|---------------------| | ||
| 1 | [ArgCopyMutation](./detectors/ArgCopyMutation.md) | High | | ✔ | | ||
| 2 | [AsmIsUsed](./detectors/AsmIsUsed.md) | Info | | | | ||
| 3 | [BranchDuplicate](./detectors/BranchDuplicate.md) | High | | ✔ | | ||
| 4 | [CellBounds](./detectors/CellBounds.md) | Critical | | ✔ | | ||
| 5 | [ConstantAddress](./detectors/ConstantAddress.md) | Info | | | | ||
| 6 | [DivideBeforeMultiply](./detectors/DivideBeforeMultiply.md) | High | ✔ | ✔ | | ||
| 7 | [DumpIsUsed](./detectors/DumpIsUsed.md) | Info | | | | ||
| 8 | [DuplicatedCondition](./detectors/DuplicatedCondition.md) | High | | ✔ | | ||
| 9 | [EnsurePrgSeed](./detectors/EnsurePrgSeed.md) | Medium | | ✔ | | ||
| 10 | [EtaLikeSimplifications](./detectors/EtaLikeSimplifications.md) | Low | | ✔ | | ||
| 11 | [ExitCodeUsage](./detectors/ExitCodeUsage.md) | High | | ✔ | | ||
| 12 | [FalseCondition](./detectors/FalseCondition.md) | Medium | | ✔ | | ||
| 13 | [FieldDoubleInit](./detectors/FieldDoubleInit.md) | Medium | | ✔ | | ||
| 14 | [InheritedStateMutation](./detectors/InheritedStateMutation.md) | Low | | | | ||
| 15 | [NeverAccessedVariables](./detectors/NeverAccessedVariables.md) | Medium | | ✔ | | ||
| 16 | [OptimalMathFunction](./detectors/OptimalMathFunction.md) | Low | | ✔ | | ||
| 17 | [PreferAugmentedAssign](./detectors/PreferAugmentedAssign.md) | Info | | ✔ | | ||
| 18 | [PreferredStdlibApi](./detectors/PreferredStdlibApi.md) | Info | | | | ||
| 19 | [ReadOnlyVariables](./detectors/ReadOnlyVariables.md) | Medium | ✔ | ✔ | | ||
| 20 | [SendInLoop](./detectors/SendInLoop.md) | Medium | | | | ||
| 21 | [ShortCircuitCondition](./detectors/ShortCircuitCondition.md) | Low | | ✔ | | ||
| 22 | [StringReceiversOverlap](./detectors/StringReceiversOverlap.md) | High | | ✔ | | ||
| 23 | [SuspiciousMessageMode](./detectors/SuspiciousMessageMode.md) | Medium | | ✔ | | ||
| 24 | [UnboundLoop](./detectors/UnboundLoop.md) | High | ✔ | ✔ | | ||
| 25 | [UnboundMap](./detectors/UnboundMap.md) | Low | | | | ||
| 26 | [UnusedExpressionResult](./detectors/UnusedExpressionResult.md) | Medium | | ✔ | | ||
| 27 | [UnusedOptional](./detectors/UnusedOptional.md) | Low | | ✔ | | ||
| 28 | [ZeroAddress](./detectors/ZeroAddress.md) | Low | | ✔ | | ||
|
||
Some of the detectors require [Soufflé](https://souffle-lang.github.io/install) to be installed. If no Soufflé installation is found, these detectors won't be executed. | ||
|
||
A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the `--all-detectors` option. You can find a full list of configuration options on the [configuration page](./tutorial/configuration.md). | ||
|
||
Each detector targets a specific type of problem in your code. Click on the detector name to learn more. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# ArgCopyMutation | ||
A detector that highlights cases where function argument mutations are ineffective | ||
due to [call-by-value semantics](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value) in Tact. | ||
|
||
## Why is it bad? | ||
In Tact, function arguments are passed by value, meaning that any mutations applied | ||
to these arguments will only affect the local copy of the variable within the function. | ||
Such mutations are unobservable outside the function, except for potentially | ||
increasing gas consumption or causing exceptions. | ||
|
||
## Example | ||
```tact | ||
fun addEntry(m: map<Int,Int>) { | ||
m.set(1, 10); // Bad: Mutating the copy | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
fun addEntry() { | ||
self.m.set(1, 10); // OK: Changing contract's state | ||
} | ||
``` | ||
|
||
Alternatively, you could redesign the method: | ||
```tact | ||
fun generateNewValue(): Int { | ||
// ... produce new value for the map | ||
return self.nextValue + 1; | ||
} | ||
m.set(self.nextKey, self.generateNewValue()); // OK | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# AsmIsUsed | ||
An optional detector that highlights all the `asm` functions. | ||
|
||
## Why is it bad? | ||
Using TVM Assembly is a potentially dangerous operation that requires additional | ||
attention from an auditor. This optional detector will highlight all its uses to | ||
assist in contract security audits. | ||
|
||
## Example | ||
```tact | ||
// Highlighted: the asm function use should be audited | ||
asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE } | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# BranchDuplicate | ||
Detector that reports duplicated code in conditional branches. | ||
|
||
## Why is it bad? | ||
Duplicated code in branches is bad because it: | ||
1. **Reduces Readability**: Repetition makes the code harder to understand. | ||
2. **Increases Maintenance**: Changes must be made in multiple places, risking errors. | ||
3. **Signals Poor Design**: It suggests missed opportunities for cleaner, more abstract code. | ||
|
||
## Example | ||
```tact | ||
if (a > 42) { | ||
a = 43; // bad: duplicated code | ||
} else { | ||
a = 43; | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
if (a > 42) { | ||
a = inc(b); // ok | ||
} else { | ||
a = 43; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# CellBounds | ||
A detector that identifies cell overflow and underflow problems. | ||
|
||
## Why is it bad? | ||
Cell overflow and underflow are issues specific to the TON blockchain. TON | ||
stores data in cells, which are low-level data structures used for serialization | ||
and deserialization. | ||
|
||
The overflow issue occurs when the user attempts to store more data in a cell | ||
than it supports. The current limitation is 1023 bits and 4 references to other | ||
cells. When these limits are exceeded, the contract throws an error with the | ||
exit code `8` during the compute phase. | ||
|
||
The underflow issue occurs when the user attempts to get more data from a | ||
structure than it supports. cells. When it happens, the contract throws an | ||
error with the exit code `9` during the compute phase. | ||
|
||
## Example | ||
```tact | ||
// Bad: storeRef is used more than 4 times | ||
beginCell() | ||
.storeRef(...) | ||
.storeAddress(myAddress()) | ||
.storeRef(...) | ||
.storeRef(...) | ||
.storeRef(...) | ||
.storeRef(...) | ||
.endCell() | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
// OK: Fixed after the analyzer highlighted it | ||
beginCell() | ||
.storeRef(...) | ||
.storeAddress(myAddress()) | ||
.storeRef(...) | ||
.storeRef(...) | ||
.storeRef(...) | ||
.endCell() | ||
``` | ||
|
||
## Resources | ||
1. [Cell & Bag of Cells (BoC) | TON Docs](https://docs.ton.org/develop/data-formats/cell-boc) | ||
2. [TVM Exit codes | TON Docs](https://docs.ton.org/learn/tvm-instructions/tvm-exit-codes) | ||
3. [Cells, Builders and Slices | Tact Docs](https://docs.tact-lang.org/ref/core-cells/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# ConstantAddress | ||
An optional detector that highlights all the constant addresses appearing in the source code. | ||
|
||
## Why is it bad? | ||
Using hardcoded addresses can sometimes indicate poor contract design. | ||
Some constant addresses may need to be set dynamically, e.g., using | ||
`contractAddress`, or at least have a way to change them at runtime, for | ||
example, when upgrading a contract. | ||
|
||
## Example | ||
```tact | ||
contract Main { | ||
proxy: Address; | ||
init() { | ||
// Bad: Constant address highlighted by the analyzer. | ||
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI"); | ||
} | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
contract Main { | ||
proxy: Address; | ||
init() { | ||
let proxy: Proxy = initOf Proxy(myAddress()); | ||
// OK: Address depends on how the proxy contact has been deployed | ||
self.proxy = contractAddress(proxy); | ||
} | ||
} | ||
``` |
27 changes: 27 additions & 0 deletions
27
versioned_docs/version-0.6/detectors/DivideBeforeMultiply.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# DivideBeforeMultiply | ||
A detector that identifies and corrects instances of division before multiplication to | ||
ensure accurate mathematical operations. | ||
|
||
## Why is it bad? | ||
Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors: | ||
* **Precision Loss:** Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers. | ||
* **Rounding Errors:** Early division might cause rounding errors that propagate through subsequent calculations. | ||
* **Unexpected Behavior:** Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging. | ||
|
||
## Example | ||
```tact | ||
let a: Int = 10; | ||
let b: Int = 3; | ||
let c: Int = 2; | ||
// Bad: Division before multiplication | ||
let result: Int = a / b * c; | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
let a: Int = 10; | ||
let b: Int = 3; | ||
let c: Int = 2; | ||
// Correct: Multiplication before division | ||
let result: Int = a * c / b; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# DumpIsUsed | ||
An optional detector that highlights all the `dump` debug prints. | ||
|
||
## Why is it bad? | ||
The `dump` function is a debug print that shouldn't be in the final code. | ||
Even though the compiler removes it in production, its presence suggests the | ||
developer was debugging something. This can flag areas where issues might exist, | ||
so auditors should take a closer look at these parts of the code. | ||
|
||
## Example | ||
```tact | ||
fun test(): Int { | ||
// ... other computations | ||
let combined: Int = (RANDOM_SEED >> half_shift) & | ||
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask; | ||
dump(combined); // Suspicious: Highlighted by the detector | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
fun test(): Int { | ||
// ... other computations | ||
let combined: Int = this.seed ^ shift_mask | ||
// OK: The code was reviewed and simplified; `dump` was removed | ||
} | ||
``` |
28 changes: 28 additions & 0 deletions
28
versioned_docs/version-0.6/detectors/DuplicatedCondition.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# DuplicatedCondition | ||
A detector that finds duplicated conditions appearing in conditional expressions. | ||
|
||
## Why is it bad? | ||
Typically, these cases are developer errors caused by copy-pasting code, leading | ||
to unreachable code. | ||
|
||
## Example | ||
```tact | ||
fun test(a: Int): Int { | ||
if (a < 1) { return 1; } | ||
else if (a > 4) { return 2; } | ||
// Bad: A developer copy-pasted the condition | ||
else if (a > 4) { return 3; } | ||
return 4; | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
fun test(a: Int): Int { | ||
if (a < 1) { return 1; } | ||
else if (a > 4) { return 2; } | ||
// OK: Fixed | ||
else if (a < x) { return 3; } | ||
return 4; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# EnsurePrgSeed | ||
A detector that identifies all calls to `nativeRandom` and `nativeRandomInterval` | ||
without a preceding PRG seed initialization. | ||
|
||
## Why is it bad? | ||
Using `nativeRandom` or `nativeRandomInterval` without first initializing the PRG seed via | ||
`nativePrepareRandom`, `nativeRandomize`, or `nativeRandomizeLt` may lead to unintended behavior | ||
or weak random number generation. This detector ensures that PRG seed initialization | ||
is always performed before any use of random functions, enhancing contract security. | ||
|
||
## Example | ||
```tact | ||
// Bad: `nativeRandom` is used without prior PRG seed initialization | ||
fun generateRandomValue(): Int { | ||
return nativeRandom() | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
fun test(): Int { | ||
nativePrepareRandom(); | ||
} | ||
// OK: PRG has been initialized somewhere in the contract | ||
fun generateRandomValue(): Int { | ||
return nativeRandom() | ||
} | ||
``` |
34 changes: 34 additions & 0 deletions
34
versioned_docs/version-0.6/detectors/EtaLikeSimplifications.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# EtaLikeSimplifications | ||
Detects opportunities for simplifying code by eliminating redundant boolean expressions and statements. | ||
|
||
## Why is it bad? | ||
Redundant code can make programs less efficient and harder to read. Simplifying such code improves readability, | ||
maintainability, and can prevent potential logical errors. | ||
|
||
**What it checks:** | ||
- `if` statements that return boolean literals directly based on a condition. | ||
- Comparisons of boolean expressions with boolean literals (`true` or `false`). | ||
- Conditional expressions (ternary operators) that return boolean literals. | ||
|
||
## Example | ||
|
||
```tact | ||
// Redundant 'if' statement: | ||
if (condition) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
// Simplify to: | ||
return condition; | ||
// Redundant comparison: | ||
return a == true; | ||
// Simplify to: | ||
return a; | ||
// Redundant conditional expression: | ||
return b ? true : false; | ||
// Simplify to: | ||
return b; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# ExitCodeUsage | ||
A detector that identifies improper use of exit codes outside the developer-allowed range. | ||
|
||
## Why is it bad? | ||
In the TON blockchain, exit codes are divided into specific ranges: 0 to 127 | ||
are reserved for the TVM or FunC, and 128 to 255 are reserved for Tact. This | ||
structure leaves the range from 256 to 65535 for developers to define custom | ||
exit codes. | ||
|
||
When exit codes are defined outside this allowed range, it may lead to | ||
conflicts with existing reserved codes, causing unintended behavior or | ||
errors in the contract. | ||
|
||
## Example | ||
```tact | ||
contract Foo { | ||
receive("foobar") { | ||
// Bad: exit code defined in the reserved range for Tact | ||
let code: Int = 128; | ||
nativeThrowUnless(code, sender() == self.owner); | ||
} | ||
} | ||
``` | ||
|
||
Use instead: | ||
```tact | ||
contract Foo { | ||
receive("foobar") { | ||
// OK: using exit code from the allowed range | ||
let code: Int = 256; | ||
nativeThrowUnless(code, sender() == self.owner); | ||
} | ||
} | ||
``` | ||
|
||
## Resources | ||
1. [Exit Codes | Tact Docs](https://docs.tact-lang.org/book/exit-codes) |
Oops, something went wrong.