Skip to content

fix: use csv_config_copy to ensure config is properly duplicated in CSV Reader - #16

Open
Kwanddwo wants to merge 1 commit into
csvtoolkit:mainfrom
Kwanddwo:fix-reader-config-copy
Open

fix: use csv_config_copy to ensure config is properly duplicated in CSV Reader#16
Kwanddwo wants to merge 1 commit into
csvtoolkit:mainfrom
Kwanddwo:fix-reader-config-copy

Conversation

@Kwanddwo

@Kwanddwo Kwanddwo commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

csv_reader now copies the config properly into persistent_arena using csv_config_copy instead of copying by pointer

This fixes #10

Summary by CodeRabbit

  • Bug Fixes
    • Improved CSV reader stability by ensuring its configuration is stored internally rather than relying on externally managed memory.
    • Reduced the risk of unexpected behavior when using CSV reader setup across different lifetimes or contexts.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Both csv_reader_init_with_config and csv_reader_init_standalone now assign reader->config from an arena-allocated copy via csv_config_copy, instead of storing the caller-provided config pointer directly, changing config ownership and lifetime.

Changes

Config ownership fix

Layer / File(s) Summary
Arena-copy config in reader init
csv_reader.c
Both init functions now copy the config into the persistent arena via csv_config_copy instead of referencing the caller's pointer.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Possibly related issues

Possibly related PRs

  • csvtoolkit/FastCSV-C#2: Also modifies csv_reader_init_with_config/csv_reader_init_standalone in csv_reader.c to change configuration allocation/ownership using the persistent arena.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: copying the CSV Reader config with csv_config_copy instead of storing the caller pointer.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
csv_reader.c (1)

31-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Header parsing still uses caller's config, not the arena copy.

The header-loading block continues to reference the original config parameter (e.g. config->hasHeader, passed into csv_parse_line_inplace) instead of reader->config. Functionally equivalent right after the copy, but it undermines the intent of decoupling from the caller-owned pointer within the same function and is inconsistent with the new ownership model established at line 23/93.

Also applies to: 101-112

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@csv_reader.c` around lines 31 - 42, The header-loading path in the CSV reader
still uses the caller-owned config instead of the arena-owned copy, so update
the header parsing block in the CSV reader flow to consistently reference
reader->config rather than the config parameter. In the logic that checks
hasHeader and calls csv_parse_line_inplace, use the reader-owned configuration
everywhere so the function matches the new ownership model established in the
reader initialization and stays decoupled from the caller’s pointer; apply the
same fix in the other header-loading block noted in the review.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@csv_reader.c`:
- Around line 91-94: `csv_reader_init_with_arena` is missing a NULL check after
`csv_config_copy`, so a failed config copy can return a fully allocated reader
with `reader->config` unset. Update the initialization flow to detect a NULL
return from `csv_config_copy`, then follow the same cleanup pattern already used
in this function by freeing `persistent_arena`, `temp_arena`, and `reader`
before returning failure. Keep the fix localized around
`csv_reader_init_with_arena` and match the existing sibling error paths for
consistency.
- Around line 21-24: The reader setup in csv_reader creation is storing the
result of csv_config_copy directly into reader->config without checking for
NULL. Add a validation step immediately after the csv_config_copy call in the
csv_reader initialization path, and if it fails, clean up and return an error
instead of returning a reader with a NULL config. Use the csv_config_copy result
and the reader->config field as the key symbols to update.

---

Nitpick comments:
In `@csv_reader.c`:
- Around line 31-42: The header-loading path in the CSV reader still uses the
caller-owned config instead of the arena-owned copy, so update the header
parsing block in the CSV reader flow to consistently reference reader->config
rather than the config parameter. In the logic that checks hasHeader and calls
csv_parse_line_inplace, use the reader-owned configuration everywhere so the
function matches the new ownership model established in the reader
initialization and stays decoupled from the caller’s pointer; apply the same fix
in the other header-loading block noted in the review.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80eae7f8-29ea-4683-9015-bd8d90c89b90

📥 Commits

Reviewing files that changed from the base of the PR and between cc93661 and a3c0821.

📒 Files selected for processing (1)
  • csv_reader.c

Comment thread csv_reader.c
Comment on lines 21 to 24
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = config;
reader->config = csv_config_copy(persistent_arena, config);
reader->headers_loaded = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing NULL check on csv_config_copy result.

csv_config_copy returns NULL on allocation failure (see csv_config.c:32-42), but the result is stored directly into reader->config without validation. If persistent_arena allocation fails here, reader is still returned to the caller with a NULL config, which will crash later wherever reader->config is dereferenced.

🛡️ Proposed fix
     reader->persistent_arena = persistent_arena;
     reader->temp_arena = temp_arena;
-    reader->config = csv_config_copy(persistent_arena, config);
+    reader->config = csv_config_copy(persistent_arena, config);
+    if (!reader->config) {
+        fclose(reader->file);
+        return NULL;
+    }
     reader->headers_loaded = false;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = config;
reader->config = csv_config_copy(persistent_arena, config);
reader->headers_loaded = false;
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = csv_config_copy(persistent_arena, config);
if (!reader->config) {
fclose(reader->file);
return NULL;
}
reader->headers_loaded = false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@csv_reader.c` around lines 21 - 24, The reader setup in csv_reader creation
is storing the result of csv_config_copy directly into reader->config without
checking for NULL. Add a validation step immediately after the csv_config_copy
call in the csv_reader initialization path, and if it fails, clean up and return
an error instead of returning a reader with a NULL config. Use the
csv_config_copy result and the reader->config field as the key symbols to
update.

Comment thread csv_reader.c
Comment on lines 91 to 94
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = config;
reader->config = csv_config_copy(persistent_arena, config);
reader->headers_loaded = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Missing NULL check on csv_config_copy result.

Same issue as csv_reader_init_with_config: if csv_config_copy fails, reader->config is silently NULL and the fully-allocated reader is still returned, risking a later NULL-pointer dereference. Also note existing sibling error paths in this function already free persistent_arena/temp_arena/reader consistently on failure, so this new failure path should follow the same cleanup pattern.

🛡️ Proposed fix
     reader->persistent_arena = persistent_arena;
     reader->temp_arena = temp_arena;
-    reader->config = csv_config_copy(persistent_arena, config);
+    reader->config = csv_config_copy(persistent_arena, config);
+    if (!reader->config) {
+        fclose(reader->file);
+        arena_destroy(persistent_arena);
+        arena_destroy(temp_arena);
+        free(persistent_arena);
+        free(temp_arena);
+        free(reader);
+        return NULL;
+    }
     reader->headers_loaded = false;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = config;
reader->config = csv_config_copy(persistent_arena, config);
reader->headers_loaded = false;
reader->persistent_arena = persistent_arena;
reader->temp_arena = temp_arena;
reader->config = csv_config_copy(persistent_arena, config);
if (!reader->config) {
fclose(reader->file);
arena_destroy(persistent_arena);
arena_destroy(temp_arena);
free(persistent_arena);
free(temp_arena);
free(reader);
return NULL;
}
reader->headers_loaded = false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@csv_reader.c` around lines 91 - 94, `csv_reader_init_with_arena` is missing a
NULL check after `csv_config_copy`, so a failed config copy can return a fully
allocated reader with `reader->config` unset. Update the initialization flow to
detect a NULL return from `csv_config_copy`, then follow the same cleanup
pattern already used in this function by freeing `persistent_arena`,
`temp_arena`, and `reader` before returning failure. Keep the fix localized
around `csv_reader_init_with_arena` and match the existing sibling error paths
for consistency.

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.

CSV Reader copies config pointer directly rather than using csv_config_copy

1 participant