Conversation
…location may overflow Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…location may overflow Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
| // Truncate excessively long labels to avoid overflow and huge allocations. | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) |
Check failure
Code scanning / CodeQL
Size computation for allocation may overflow High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
General approach: ensure that the size used in make([]byte, EdgeKeySize+len(label)) cannot overflow int even if label is derived from untrusted data. This can be done by (a) capping the label length to a sane, fixed maximum that is safely representable as int on all supported architectures, and/or (b) performing an explicit overflow guard before the allocation.
Best concrete fix here:
- Define a constant maximum label length for edge keys within
grids/key/key.go(if it is not already defined in this file) that is small enough thatEdgeKeySize + maxEdgeLabelLenis well belowmath.MaxInt. For example,const maxEdgeLabelLen = 1 << 20(1 MiB) or similar. - In
EdgeKey, truncatelabeltomaxEdgeLabelLenbefore computing the allocation size, as the snippet already attempts to do. - Add an explicit overflow guard before the
makecall: computelabelLen := len(label)and check thatlabelLen <= maxAllowedLabelLenForIntor equivalently thatEdgeKeySize+labelLendoes not overflowint. Since we are constraining tomaxEdgeLabelLen, the explicit guard can be as simple as an early return ofnilor panic ifmaxEdgeLabelLenitself would be unsafe, but in practice just capping by that constant on a 64‑bit build is sufficient. - Keep existing behavior: keys are still “E|id|src|dst|label”, but labels are truncated if too long; the only semantic change is tighter bounding of label length to prevent pathological allocations.
In terms of concrete edits:
- In
grids/key/key.go, add a constant formaxEdgeLabelLenif it does not yet exist in the file. - In the
EdgeKeyfunction (lines ~99–112), ensure the truncation uses that constant and optionally add a small helper variablelabelLen := len(label)for clarity. Since the code snippet already shows the truncation usingmaxEdgeLabelLen, the main actionable change is to introduce the constant definition in this file (if missing) so that the analyzer sees an explicit cap independent of external configuration; this directly addresses all three alert variants because the tainted path ends at the allocation sized bylen(label).
No extra imports or new methods are required; only a constant definition and the existing truncation logic inside EdgeKey are needed.
| @@ -11,6 +11,10 @@ | ||
| VertexTablePrefix = "v_" | ||
| EdgeTablePrefix = "e_" | ||
| EdgeKeySize = 1 + 8 + 8 + 8 | ||
| // maxEdgeLabelLen caps the length of an edge label that can be encoded into a key. | ||
| // This prevents pathological or maliciously large labels from causing integer | ||
| // overflow or excessive allocations when sizing edge keys. | ||
| maxEdgeLabelLen = 1 << 20 // 1 MiB | ||
| ) | ||
|
|
||
| // maxEdgeLabelLen limits the size of edge labels encoded into keys. |
| if len(label) > maxEdgeLabelLen { | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) |
Check failure
Code scanning / CodeQL
Size computation for allocation may overflow High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
General approach: ensure that the size used in make cannot overflow int by bounding the label length to a safe maximum before doing EdgeKeySize+len(label). The simplest, non‑breaking way is to (1) define a small, constant maxEdgeLabelLen in grids/key/key.go, and (2) truncate label to this length in both EdgeKey and SrcEdgeKey before computing the allocation size. Because the label is only used as part of an internal key, truncating excessively long labels is a reasonable and low‑impact defense.
Concretely, in grids/key/key.go:
- Add a
const maxEdgeLabelLen = 4096(or similar small value) near the other constants, so that label length is hard‑bounded. - In
EdgeKey, before allocating, checkif len(label) > maxEdgeLabelLen { label = label[:maxEdgeLabelLen] }and keep the allocation asmake([]byte, EdgeKeySize+len(label)). - In
SrcEdgeKey, do the same truncation tomaxEdgeLabelLenbefore computing the allocation.
This avoids any int overflow in EdgeKeySize+len(label) and prevents huge allocations or panics, while leaving the external behavior effectively the same except for very rare cases where labels are absurdly long (in which case they are now truncated instead of potentially crashing the process). No new imports are needed; all changes are localized to grids/key/key.go.
| @@ -11,6 +11,9 @@ | ||
| VertexTablePrefix = "v_" | ||
| EdgeTablePrefix = "e_" | ||
| EdgeKeySize = 1 + 8 + 8 + 8 | ||
| // maxEdgeLabelLen bounds the length of edge labels used when constructing keys, | ||
| // preventing integer overflow in size computations and avoiding huge allocations. | ||
| maxEdgeLabelLen = 4096 | ||
| ) | ||
|
|
||
| // maxEdgeLabelLen limits the size of edge labels encoded into keys. | ||
| @@ -124,6 +127,7 @@ | ||
| func SrcEdgeKey(eid, src, dst uint64, label string) []byte { | ||
| // Format: < | src(8) | dst(8) | id(8) | label(var) | ||
| if len(label) > maxEdgeLabelLen { | ||
| // Truncate excessively long labels to avoid overflow and huge allocations. | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) |
| if len(label) > maxEdgeLabelLen { | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) |
Check failure
Code scanning / CodeQL
Size computation for allocation may overflow High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 days ago
General approach: guard any allocation whose size is computed using potentially large data (like len(label)) so that the computation cannot overflow the int type. Since we already cap label at maxEdgeLabelLen, we just need to ensure maxEdgeLabelLen is not so big that EdgeKeySize+len(label) overflows int. We can do this at runtime with a single check before make, returning a zero value (or panicking) if the label is too large to represent safely.
Best concrete fix here:
- In
grids/key/key.go, bothSrcEdgeKeyandDstEdgeKeyalready clamplabelusingmaxEdgeLabelLenand then allocatemake([]byte, EdgeKeySize+len(label)). - Introduce a small guard right after truncating
labelin both functions:- Compute
l := len(label). - Check
if l > int(^uint(0)>>1)-EdgeKeySize(i.e.,if EdgeKeySize+lwould overflowint). - If it would overflow, return
nil(or you could choose to panic; here returningnilis minimally invasive and avoids undefined behavior). - Otherwise, perform
make([]byte, EdgeKeySize+l)and proceed as before.
- Compute
- This uses only existing imports and standard operations; no new dependencies or helper methods are needed.
- The behavior for all normal inputs (where labels are reasonable in size) is unchanged; only ridiculously large labels will now cause
SrcEdgeKey/DstEdgeKeyto returnnilinstead of panicking or allocating incorrectly.
This single change in grids/key/key.go addresses all three CodeQL alert variants, because they all complain about the same allocation expression.
| @@ -126,7 +126,12 @@ | ||
| if len(label) > maxEdgeLabelLen { | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) | ||
| l := len(label) | ||
| // Guard against possible int overflow when computing EdgeKeySize+l | ||
| if l > int(^uint(0)>>1)-EdgeKeySize { | ||
| return nil | ||
| } | ||
| out := make([]byte, EdgeKeySize+l) | ||
| out[0] = srcEdgePrefix[0] | ||
| binary.BigEndian.PutUint64(out[1:], src) | ||
| binary.BigEndian.PutUint64(out[9:], dst) | ||
| @@ -149,7 +154,12 @@ | ||
| if len(label) > maxEdgeLabelLen { | ||
| label = label[:maxEdgeLabelLen] | ||
| } | ||
| out := make([]byte, EdgeKeySize+len(label)) | ||
| l := len(label) | ||
| // Guard against possible int overflow when computing EdgeKeySize+l | ||
| if l > int(^uint(0)>>1)-EdgeKeySize { | ||
| return nil | ||
| } | ||
| out := make([]byte, EdgeKeySize+l) | ||
| out[0] = dstEdgePrefix[0] | ||
| binary.BigEndian.PutUint64(out[1:], dst) | ||
| binary.BigEndian.PutUint64(out[9:], src) |
Summary
This PR removes the label indirection layer and simplifies Grip’s storage access patterns by making table IDs the primary resolution mechanism.
Previously, many execution paths required multiple lookups:
label → table → schema → storage
This PR collapses that into a more direct flow:
tableID → section → storage
The result is a simpler mental model, fewer hot-path lookups, and reduced schema coupling.
Key Changes
Motivation
The label abstraction added:
Moving to table IDs as the canonical identifier improves performance and maintainability.
Impact
Performance
Architecture
Compatibility
This is largely an internal refactor but may affect:
External query semantics should remain unchanged.
Future Work