Skip to content

fix(traceql): stop intPow from hanging#6581

Merged
mdisibio merged 5 commits intomainfrom
intpow
Apr 2, 2026
Merged

fix(traceql): stop intPow from hanging#6581
mdisibio merged 5 commits intomainfrom
intpow

Conversation

@Proximyst
Copy link
Copy Markdown
Member

What this PR does:
We currently have a naive implementation of integer powers. This hangs CPUs if given very large numbers. As there is no context propagation, that also does not stop when the requester gives up.

Note: the bug and fix were both LLM-driven.

Which issue(s) this PR fixes:
No issue was filed here.

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]

@Proximyst
Copy link
Copy Markdown
Member Author

@codex Please review this PR

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c321135670

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkg/traceql/ast_execute.go Outdated
Comment on lines +929 to +930
if exp < 0 {
return 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve ±1 semantics for negative integer exponents

Returning 0 for every negative exponent in intPow changes valid TraceQL results for cases that have exact integer answers (for example, 1 ^ -3 should stay 1, and -1 ^ -3 should stay -1). This is a behavioral regression introduced by this patch because negative literals are parseable in scalar expressions, so integer-power queries with negative exponents now produce incorrect values instead of the prior behavior.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Negative powers were always broken AFAICT 🤔 maybe a different thing we may want to open a bug ticket for?

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c321135670

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkg/traceql/ast_execute.go Outdated
Comment on lines +929 to +930
if exp < 0 {
return 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid zeroing integer power when exponent is negative

Returning 0 for all negative exponents changes query results in reachable paths, not just unsupported a^-b inputs. Fresh evidence: both integer OpPower call sites still invoke intPow(rhsN, lhsN) (pkg/traceql/ast_execute.go:480 and :729), so a negative left operand (for example (-2) ^ 3) now hits this branch and collapses to 0 for every positive RHS, whereas this patch is only intended to address hangs. That introduces incorrect filter/evaluation behavior for integer-power expressions over negative values.

Useful? React with 👍 / 👎.

@mdisibio
Copy link
Copy Markdown
Contributor

mdisibio commented Mar 4, 2026

Example query: { 2^1000000000000000 > 0}

Interesting, I'm not sure the rationale for the naive implementation, perhaps the for loop is faster than math.Pow on common (i.e. smallish) inputs. However, unless we know this is a bottleneck for certain queries, I think a straightforward int(math.Pow(float64(base), float64(exp))) sounds better, any reason not to? Confirmed that it doesn't suffer a performance penalty on that query.

Although it does overflow resulting in a negative, for that query, but it handles negative exponents correctly, i.e. 10^-1 should be integer 0, but this loop returns 1.

@Proximyst
Copy link
Copy Markdown
Member Author

I shyed away from math.Pow pretty instinctively because of the float conversions. But giving it some thought, I suppose if you're in such massive numbers that float accuracy becomes a problem, you are probably using TraceQL wrong anyways, so should be fine?

Just for my own amusement, I'll try out some more AI, so will convert this to a draft while I do that :)

@Proximyst Proximyst marked this pull request as draft March 6, 2026 07:05
@Proximyst
Copy link
Copy Markdown
Member Author

@codex Can you update the implementation of the exponentiation function in this PR to use math.Pow as mdisibio suggested, please? Make sure to update the tests accordingly; some values will change when they're rather massive. Small values should not change (e.g. 2^2 should still be 4).

@chatgpt-codex-connector
Copy link
Copy Markdown

Summary

Testing

  • go test ./pkg/traceql -run TestIntPow -count=1
  • go test ./pkg/traceql -count=1

Also completed follow-up workflow actions:

  • Committed changes on branch work as commit 28d4b645.
  • Created a follow-up PR message with title: [follow-up] traceql: switch intPow to math.Pow and refresh edge-case expectations.

View task →

@Proximyst Proximyst marked this pull request as ready for review March 6, 2026 12:26
@Proximyst
Copy link
Copy Markdown
Member Author

@mdisibio I think this looks good. Impressed that Codex managed the tests :o

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47428eac43

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
return result
func intPow(base, exp int) int {
return int(math.Pow(float64(base), float64(exp)))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve exact integer power without float conversion

Converting operands through math.Pow(float64(...)) makes integer exponentiation lose precision for many in-range results, because float64 cannot represent all integers above 2^53 exactly. For example, 2147483647^2 should be 4611686014132420609 but this path returns 4611686014132420608, so integer OpPower expressions can now silently produce wrong query/filter results in both scalar execution paths that call intPow.

Useful? React with 👍 / 👎.

@mdisibio
Copy link
Copy Markdown
Contributor

mdisibio commented Mar 9, 2026

Thanks, changelog and then can merge.

@mdisibio
Copy link
Copy Markdown
Contributor

mdisibio commented Mar 9, 2026

Oh sorry, this also now has conflicts because I merged the other PR.

@Proximyst
Copy link
Copy Markdown
Member Author

Proximyst commented Mar 10, 2026

@mdisibio I've updated the changelog but I keep running into flaky tests :S

edit: as I comment this, of course the run passes 😂

Copilot AI review requested due to automatic review settings April 2, 2026 17:09
@mdisibio mdisibio enabled auto-merge (squash) April 2, 2026 17:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a TraceQL performance bug where integer exponentiation (^) could hang by iterating O(exp) times for large exponents.

Changes:

  • Replace the naive integer power loop with a math.Pow-based implementation.
  • Add unit tests covering intPow, including large-exponent cases intended to ensure the function completes quickly.
  • Add a changelog entry for the TraceQL bugfix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
pkg/traceql/ast_execute.go Reworks intPow implementation used by the integer ^ operator.
pkg/traceql/ast_execute_test.go Adds a dedicated TestIntPow with small/edge/large exponent cases.
CHANGELOG.md Records the bugfix in the changelog.

}
return result
func intPow(base, exp int) int {
return int(math.Pow(float64(base), float64(exp)))
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using math.Pow(float64(...)) for integer exponentiation changes semantics and can return incorrect results due to float64 rounding (e.g. (2^31-1)^2 cannot be represented exactly) and makes overflow behavior implementation-dependent when converting +Inf/NaN/out-of-range float64 back to int. Consider implementing an O(log exp) integer exponentiation-by-squaring version that keeps deterministic int wraparound behavior, and handle exp<0 explicitly (return 0 except base==±1, or return an error at the operator level). Also, current call sites pass intPow(rhsN, lhsN) (ast_execute.go:486/741), which is easy to misread with the new base/exp parameter names—worth aligning the argument order or renaming to avoid confusion.

Suggested change
return int(math.Pow(float64(base), float64(exp)))
if exp < 0 {
switch base {
case 1:
return 1
case -1:
if exp%2 == 0 {
return 1
}
return -1
default:
return 0
}
}
result := 1
for exp > 0 {
if exp&1 == 1 {
result *= base
}
exp >>= 1
if exp > 0 {
base *= base
}
}
return result

Copilot uses AI. Check for mistakes.
Comment on lines +2254 to +2263
{"large exponent", 2, 62, 1 << 62},
// These cases would hang with a naive O(n) loop.
// They must complete near-instantly or go test -timeout will kill them.
{"100 ^ 100", 100, 100, math.MinInt64},
{"maxint32 ^ 2", math.MaxInt32, 2, 4611686014132420608},
{"2 ^ maxint32", 2, math.MaxInt32, math.MinInt64},
{"maxint32 ^ maxint32", math.MaxInt32, math.MaxInt32, math.MinInt64},
{"maxint64 ^ 2", math.MaxInt64, 2, math.MinInt64},
{"2 ^ maxint64", 2, math.MaxInt64, math.MinInt64},
{"maxint64 ^ maxint64", math.MaxInt64, math.MaxInt64, math.MinInt64},
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several expectations here rely on float64 overflow / float64->int conversion behavior (e.g. expecting math.MinInt64 for huge results). That conversion is explicitly implementation-dependent in Go when the float64 value is out of int range or is ±Inf/NaN, so these test cases can be flaky across architectures / Go versions. Additionally, maxint32 ^ 2 is mathematically 4611686014132420609, but the test expects 4611686014132420608 (suggesting the implementation is rounding, not doing true integer pow). Could these “large exponent” cases instead assert that the call completes quickly, and/or compute a deterministic expected value based on the intended integer semantics (e.g., wraparound modulo 2^word using big.Int with bits.UintSize)?

Copilot uses AI. Check for mistakes.
@mdisibio mdisibio merged commit b0d434b into main Apr 2, 2026
31 checks passed
@mdisibio mdisibio deleted the intpow branch April 2, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants