Skip to content

fix: pdcp data loss, pipeline conn leak, Close() race, FilterCustom error swallowing - #2549

Open
tal7aouy wants to merge 1 commit into
projectdiscovery:devfrom
tal7aouy:fix/pdcp-pipeline-filter-bugs
Open

fix: pdcp data loss, pipeline conn leak, Close() race, FilterCustom error swallowing#2549
tal7aouy wants to merge 1 commit into
projectdiscovery:devfrom
tal7aouy:fix/pdcp-pipeline-filter-bugs

Conversation

@tal7aouy

@tal7aouy tal7aouy commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes four bugs found during a code audit of the codebase.


Bugs Fixed

1. PDCP Writer: Data Loss When Chunk Exceeds MaxChunkSize

File: internal/pdcp/writer.go

When a result line would push the buffer over MaxChunkSize (4 MB), the buffer was flushed, but the current line was never written to the newly emptied buffer. This silently dropped every result that triggered a flush.

Before

if buff.Len()+len(line) > MaxChunkSize {
    if err := u.uploadChunk(buff); err != nil {
        gologger.Error().Msgf("Failed to upload asset results on cloud: %v", err)
    }
} else {
    buff.WriteString(line)
    buff.WriteString("\n")
}

After

if buff.Len()+len(line) > MaxChunkSize {
    if err := u.uploadChunk(buff); err != nil {
        gologger.Error().Msgf("Failed to upload asset results on cloud: %v", err)
    }

    // Write the current line to the now-empty buffer so it is not lost.
    buff.WriteString(line)
    buff.WriteString("\n")
} else {
    buff.WriteString(line)
    buff.WriteString("\n")
}

2. Pipeline: Connection Leak in SupportPipeline

File: common/httpx/pipeline.go

The dialed TCP/TLS connection was never closed on either the success or error path, leaking one file descriptor per call.

A defer conn.Close() was added immediately after a successful connection.

conn, err := pipelineDial(protocol, addr)
if err != nil {
    return false
}

defer conn.Close()

3. PDCP Writer: Race Condition in Close()

File: internal/pdcp/writer.go

The Load()close()Store() sequence around close(u.data) was not atomic. Concurrent calls to Close() could both pass the check, causing the second close(u.data) to panic with:

close of closed channel

Replaced the sequence with an atomic CompareAndSwap.

Before

func (u *UploadWriter) Close() {
    if !u.closed.Load() {
        close(u.data)
        u.closed.Store(true)
    }
    <-u.done
}

After

func (u *UploadWriter) Close() {
    if !u.closed.CompareAndSwap(false, true) {
        return
    }

    close(u.data)
    <-u.done
}

4. FilterCustom: Errors from Callbacks Silently Swallowed

File: common/httpx/filter.go

If a callback returned either (true, error) or (false, error), the error was silently discarded and iteration continued. As a result, the function could incorrectly return (false, nil) even though a callback had returned an error.

Errors are now propagated immediately.

Before

for _, callback := range f.CallBacks {
    ok, err := callback(response)
    if ok && err == nil {
        return true, err
    }
}

return false, nil

After

for _, callback := range f.CallBacks {
    ok, err := callback(response)
    if err != nil {
        return false, err
    }

    if ok {
        return true, nil
    }
}

return false, nil

Test Plan

  • go test ./common/httpx/ -run TestFilterCustom -v
    • New test covers all four callback scenarios:
      • Error with ok=true
      • Error with ok=false
      • First callback matches
      • No callbacks match
  • go vet ./common/httpx/ ./internal/pdcp/
  • go build ./common/httpx/ ./internal/pdcp/
  • go test ./common/httpx/ -short -count=1
    • Full package test suite passes.

Summary by CodeRabbit

  • Bug Fixes

    • Improved callback error handling so errors are reported immediately.
    • Prevented data loss when processing full-size chunks.
    • Ensured data channels are closed safely and only once.
    • Improved connection cleanup after successful pipeline setup.
  • Tests

    • Added coverage for callback errors, successful matches, and unmatched filters.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f0f57ce-1296-4868-872f-515fd3b7d545

📥 Commits

Reviewing files that changed from the base of the PR and between 8114098 and ca92e9f.

📒 Files selected for processing (4)
  • common/httpx/filter.go
  • common/httpx/filter_test.go
  • common/httpx/pipeline.go
  • internal/pdcp/writer.go

Walkthrough

The change fixes callback error propagation, pipeline connection cleanup, and PDCP writer behavior. It also prevents oversized result loss and makes writer channel closure safe for repeated calls.

Changes

Filter callback handling

Layer / File(s) Summary
Filter result handling
common/httpx/filter.go, common/httpx/filter_test.go
FilterCustom.Filter returns callback errors immediately. Tests cover errors, successful matches, and no matches.

Pipeline connection cleanup

Layer / File(s) Summary
Pipeline connection lifecycle
common/httpx/pipeline.go
SupportPipeline defers connection closure after a successful pipelineDial call.

PDCP writer correctness

Layer / File(s) Summary
Buffer retention and safe closure
internal/pdcp/writer.go
The writer preserves the current result after flushing a full buffer. Close uses atomic compare-and-swap before closing the data channel.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit checks the filter’s trail,
And keeps each error in the tale.
The pipeline shuts its door with care,
While buffered lines remain in there.
One close claim guards the channel tight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes all four bug fixes addressed by the pull request.
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.
✨ 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.

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.

1 participant