Octal Values
ID |
go.octal_values |
Severity |
critical |
Remediation Complexity |
trivial |
Remediation Risk |
medium |
Remediation Effort |
low |
Resource |
Code Smell |
Language |
Go |
Tags |
code-style, reliability |
Description
Reports an octal integer literal that is not being used as a Unix file mode.
Go writes octal two ways. The legacy form is a bare leading zero, 0644, which reads like a decimal
number and is not one. The modern form, 0o644, states the base explicitly. Both are reported when
the value is not a permission bitmask, because outside that one use neither base 8 nor the leading
zero carries meaning a reader can act on.
File modes are exempt: octal is the conventional notation for permissions and umasks, and 0o755 is
how the Go standard library documents them. See Configuration for how a file mode is recognised.
Rationale
const bufferSlots = 010 // FLAW — this is 8, not 10
var stride = 0777 // FLAW — octal bound to an ordinary variable
head := 010 // FLAW — an offset written in base 8 for no reason
The leading-zero form is a silent trap. 010 is decimal 8, and nothing on the line says so: the
literal looks like the decimal number ten to every reader who has not memorised the rule. A count, a
size, a port, a timeout or an array index typed with an accidental leading zero compiles and runs
with a different value than the author wrote, and no test that only exercises the happy path will
notice.
The explicit 0o form cannot be misread, but outside a permission bitmask it still leaves the
question of why the value is in base 8 unanswered. Octal is only self-explanatory when its digits
map onto three-bit groups, which is exactly what a Unix mode is and what an ordinary integer is not.
Remediation
Write the value in the base that matches how it is used, and let the type or the name say when a value is a permission.
const bufferSlots = 8 // a count, in decimal
var stride = 511 // if 511 really was the intent
// If the value is a file mode, say so — then octal is the right notation and is accepted.
var dirPerm os.FileMode = 0o755
perm := 0o640
os.Chmod(path, 0755)
tar.Header{Mode: 0644}
For bit flags, prefer the base that shows the bits: 0b1010 for a bitmask, 0x1F for a byte
pattern. Both are excluded from this rule.
Configuration
A literal is treated as a file mode, and not reported, when any one of these says so.
| Property | Meaning | Default |
|---|---|---|
|
Qualified function names whose arguments are permissions or umasks. Any octal anywhere in such a call’s argument list is accepted. |
|
|
Declared types that make a literal a file mode, on a |
|
|
Name words that make a literal a file mode. The identifier the literal is bound to — a |
|
Add a project’s own permission wrapper to fileModeFunctions to silence findings inside it.