Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TraceQL doesn't parse math.MinInt properly #4623

Open
ndk opened this issue Jan 27, 2025 · 4 comments
Open

TraceQL doesn't parse math.MinInt properly #4623

ndk opened this issue Jan 27, 2025 · 4 comments
Labels
good first issue Good for newcomers type/bug Something isn't working

Comments

@ndk
Copy link
Contributor

ndk commented Jan 27, 2025

Describe the bug
When adding test cases to TestSpansetFilterStatics:

func TestSpansetFilterStatics(t *testing.T) {
	tests := []struct {
		in       string
		expected FieldExpression
	}{
		...
		{in: "{ 9223372036854775807 }", expected: NewStaticInt(math.MaxInt)},
		{in: "{ -9223372036854775808 }", expected: NewStaticInt(math.MinInt)},

the second case (-9223372036854775808) triggers an out-of-range error:

Error:      	Received unexpected error:
            	parse error at line 1, col 4: strconv.Atoi: parsing "9223372036854775808": value out of range
Test:       	TestSpansetFilterStatics/{_-9223372036854775808_}

It appears the parser handles the numeric part (9223372036854775808) as a positive integer before applying the minus sign, causing the overflow.

The relevant parsing rule is in expr.y:

scalarExpression: // shares the same operators as scalarPipelineExpression. split out for readability
    OPEN_PARENS scalarExpression CLOSE_PARENS  { $$ = $2 }                                   
  | scalarExpression ADD scalarExpression      { $$ = newScalarOperation(OpAdd, $1, $3) }
  | scalarExpression SUB scalarExpression      { $$ = newScalarOperation(OpSub, $1, $3) }
  | scalarExpression MUL scalarExpression      { $$ = newScalarOperation(OpMult, $1, $3) }
  | scalarExpression DIV scalarExpression      { $$ = newScalarOperation(OpDiv, $1, $3) }
  | scalarExpression MOD scalarExpression      { $$ = newScalarOperation(OpMod, $1, $3) }
  | scalarExpression POW scalarExpression      { $$ = newScalarOperation(OpPower, $1, $3) }
  | aggregate                                  { $$ = $1 }
  | INTEGER                                    { $$ = NewStaticInt($1)              }
  | FLOAT                                      { $$ = NewStaticFloat($1)            }
  | DURATION                                   { $$ = NewStaticDuration($1)         }
  | SUB INTEGER                                { $$ = NewStaticInt(-$2)             }
  | SUB FLOAT                                  { $$ = NewStaticFloat(-$2)           }
  | SUB DURATION                               { $$ = NewStaticDuration(-$2)        }
  ;

A possible approach is to handle negative bounds explicitly, similar to how TiDB deals with it. They parse the numeric literal without the sign, then apply a range check for [-9223372036854775808, 9223372036854775807]. Here’s a snippet illustrating that approach:

SignedNum:
	Int64Num
|	'+' Int64Num
	{
		$$ = $2
	}
|	'-' NUM
	{
		unsigned_num := getUint64FromNUM($2)
		if unsigned_num > 9223372036854775808 {
			yylex.AppendError(yylex.Errorf("the Signed Value should be at the range of [-9223372036854775808, 9223372036854775807]."))
			return 1
		} else if unsigned_num == 9223372036854775808 {
			signed_one := int64(1)
			$$ = signed_one << 63
		} else {
			$$ = -int64(unsigned_num)
		}
	}

By incorporating a similar boundary check into TraceQL’s parser, -9223372036854775808 will no longer fail with an out-of-range error.

@joe-elliott
Copy link
Member

Thanks for the issue! I would be glad to accept a PR to fix, but given how minor this issue is, the PR would need to add very little complexity to Tempo.

Nice find on TiDB's parser, btw.

@stoewer stoewer added good first issue Good for newcomers type/bug Something isn't working labels Feb 5, 2025
@lemonnn-8
Copy link

can I work on this ?

@ndk
Copy link
Contributor Author

ndk commented Feb 12, 2025

BTW, if you choose to solve the issue by modifying expr.y, I would suggest asking the Grafana team which version of goyacc they are using. I found that it's definitely not the latest one, because the code I generated differed too much from the original. The version that produced the closest match to the original code was v0.1.0

@joe-elliott
Copy link
Member

I did not realize that we were generating this locally and didn't have it in a tools image. We should really fix that :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers type/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants