Fix IvyStmtPrepare to honor query length from callers - #2176
jiangdaoli11 wants to merge 1 commit into
Conversation
IvyStmtPrepare() mirrors OCI's OCIStmtPrepare2(stmttxt, stmtlen) semantics: the caller supplies the exact statement length and the statement text is not required to be NUL-terminated. The implementation ignored query_len and used strdup(), which reads until the first NUL byte. For a caller that passes a fixed-length, non-NUL-terminated buffer this over-reads past the buffer and stores garbage as the statement text, breaking the subsequent parse/prepare, and leaves stmtHandle->query_len inconsistent with the stored string length. Copy exactly query_len bytes and NUL-terminate the stored query, and check malloc() failure. Now strlen(query) == query_len always holds, which also keeps the escaping-buffer sizing in Ivyreplacenamebindtoposition() consistent. Add exec_prepare_nonul() to testlibpq_prepare_dml covering a statement prepared from a padded heap buffer that has no NUL terminator (verified to fail with the old code and pass with the fix).
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: IvorySQL/IvorySQL/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthrough
ChangesNon-NUL Query Preparation
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~15 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to IvyStmtPrepare now safely handles non-NUL-terminated query buffers, and the added test exercises preparation and execution through that path. No actionable merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Thanks for picking this up — the fix also resolves the variant reported in #2172. One gap in the new coverage:
With const char *query = "SELECT :v + 1";
IvyStmtPrepare(stmt, error, query, strlen("SELECT :v"), 0, 0);
/* bind :v = 10, then execute */
printf("%s\n", Ivygetvalue(result, 0, 0)); /* before: 11, after this fix: 10 */Before the patch that prints Could a second case along these lines be added next to |
|
Thanks for contributing to IvorySQL! |
Fixes #2172
Summary
IvyStmtPrepare()mirrors OCI'sOCIStmtPrepare2(stmttxt, stmtlen)semantics: the caller passes the exact statement length inquery_len, and the statement text is not required to be NUL-terminated. The implementation, however, ignoredquery_lenand stored the query viastrdup(query)(i.e.strlen-based).For any caller that passes a fixed-length buffer without a NUL terminator,
strdup()over-reads past the caller's buffer until it happens upon a NUL byte, storing garbage as the statement text. The subsequent Parse/prepare then fails on the server (or executes the wrong statement), andstmtHandle->query_lenbecomes inconsistent with the actually-stored string, which also skews the escaping-buffer sizing inIvyreplacenamebindtoposition().Change
src/interfaces/libpq/ivy-exec.c: inIvyStmtPrepare(), allocatequery_len + 1bytes, copy exactlyquery_lenbytes and NUL-terminate the stored query; also add the missingmalloc()failure check. After the fix,strlen(query) == query_lenalways holds.src/interfaces/libpq/ivytest/testlibpq_prepare_dml.cand expected output: addexec_prepare_nonul(), a regression test that prepares and executes a statement from a 4096-byte heap buffer filled with'X'and containing no NUL anywhere, exactly the OCI pattern that used to break. Verified to fail with the old code (PQexecPrepared statement not return tuples properly, garbageXXXX...statement text) and to pass with the fix.Notes
pgindentwas intentionally not run: the ivy files use the fork's own local style and are notpgindent-clean even atHEAD(e.g. >2000 diff lines forivy-exec.con a pristine copy); a full-file reformat would drown the fix in noise. The added code follows the existing local style of the file.-Wall -Werror=vla, etc.).testlibpq_prepare_dmlrun against a live server produces output identical toexpected/testlibpq_prepare_dml.out(including the new40 nonulrow); the same test fails against the unfixed library, confirming it guards the bug.master(63fb0bfe61) and contains a single commit touching only these three files.Summary by CodeRabbit
Bug Fixes
Tests