tarantool / tarantool/tarantool

sql: unterminated legacy name when the uppercase form is longer

Open Beginner friendly
#13,160 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Lua
Stars
3.7k
Forks
419
Avg merge
1d 23h
Merged PRs (30d)
88

Description

Bug description

sql_legacy_name_new() in src/box/sql/util.c uppercases an unquoted SQL identifier with ucasemap_utf8ToUpper() into a buffer sized for the input. When the uppercased form is longer than the input, the first call returns U_BUFFER_OVERFLOW_ERROR and the code reallocates a larger buffer and retries, but it doesn't reset status to U_ZERO_ERROR first. ICU returns right away when the incoming status already holds a failure, so the retry writes nothing and returns 0. The returned name has no NUL terminator and its tail is uninitialized heap memory, and the callers then use it as a C string (space_by_name0(), strcmp(), ...). The legacy-name lookup fails, and the lookup itself reads past the written bytes.

Any client SQL with an unquoted identifier whose uppercase form is longer in bytes hits this, for example Greek ΐ (U+0390, 2 bytes) whose uppercase is Ϊ́ (U+0399 U+0308 U+0301, 6 bytes). Identifiers whose uppercase is not longer take the early return before the retry, so ASCII names are unaffected.

  • OS: MacOS
  • OS Version: macOS 26 (Darwin 25.6.0), also present in the sources on Linux
  • Architecture: arm64

Tarantool 3.9.0-entrypoint (master, commit 9ca342c5)

Steps to reproduce

Reproducer script:

#!/usr/bin/env tarantool
box.cfg{}
-- U+0390 is 2 bytes, its uppercase form U+0399 U+0308 U+0301 is 6 bytes.
local s = box.schema.space.create('\xCE\x99\xCC\x88\xCC\x81',
                                  {format = {{'a', 'integer'}}})
s:create_index('pk')
s:insert({1})
local res, err = box.execute('SELECT a FROM \xCE\x90 WHERE a = 1;')
print(res ~= nil and require('json').encode(res.rows) or err)
os.exit()

How to run:

Just type tarantool test.lua.

Actual behavior

Space 'ΐ' does not exist

The space is not found through its legacy uppercased name because the retry never wrote the uppercased bytes, and the lookup runs strlen()/strcmp() over a buffer that has no terminator.

Expected behavior

[[1]]

The unquoted identifier resolves to the space named by its uppercased form, the same way it does for ASCII identifiers (SELECT * FROM asd finds ASD).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/box/sql/util.c at sql_legacy_name_new() and inspect the retry after ucasemap_utf8ToUpper() reports U_BUFFER_OVERFLOW_ERROR. Run the provided Lua reproducer with tarantool test.lua; done when the unquoted Greek identifier resolves to the created space and prints [[1]].

Written by the indexing model from the issue text.

Assessment

Tech stack
c, lua, sql
Domain
database
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.