← Design Verification Interviews

Interview Question · Concept

Who Frees DPI Memory

L2 Mid-LevelL3 Seniordpimemory

The Question

The interviewer asks

A C model returns a string built with malloc on every call. Who frees it? And who frees a string argument, an open array, or a model behind a chandle?

Reveal the Model Answer

Each side frees only what it allocated. Strings, arrays and vectors that SystemVerilog passes in are borrowed for the call. C never frees them or keeps pointers to them. A string C returns is still C's memory. The simulator copies it and never frees it, so a fresh malloc per call leaks. Keep result buffers inside the model, and give a chandle model a delete call that SystemVerilog makes once.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Mid-Level)

States the own-what-you-allocate rule and finds the leak in the malloc result.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyBreak ItCompareScale It

  1. Who Frees DPI Memory
  2. WhyWhy Each Side Frees Its Own MemoryL2 Mid-Level

    Why does the standard forbid C from freeing memory that SystemVerilog passed in, even if it came from malloc?

    Reveal the Model Answer

    C cannot know how the simulator made that memory. It may come from a pool, the stack, a temporary copy, or a C++ object. Only the allocator that made a block may free it. A clear rule on each side makes both implementations free to change.

    Self-Check

    Tick each key point you covered in your answer.

    Tool as Truth

    "It came from malloc on my simulator, so free is safe."

    That is one build of one tool. The next release, or a different simulator, may use another allocator and crash.

    Source IEEE 1800-2017 §35.5.1.4

  3. CompareThree Ways to Return a String from CL2 Mid-Level

    Compare a fresh malloc per call, one static buffer, and a buffer inside the model struct for a string result.

    Reveal the Model Answer

    The fresh malloc leaks on every call. The static buffer does not leak, but every model shares it and the next call overwrites it. A buffer inside the model struct is owned by that model and freed with it. Choose the model buffer.

    Where the string result livesLeaks?Overwritten by the next call?Use it when
    A fresh malloc per callYes, every callNoNever, unless C also gets a free call
    One static bufferNoYesOnly one model, and the caller copies at once
    A buffer inside the model structNoOnly by that modelThe default for a model behind a chandle

    The simulator copies a returned string into its own storage, so a buffer C reuses is safe once the call has returned.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Return a pointer to a local char buf[64]."

    The array dies when the function returns, so the simulator copies from freed stack memory. That is undefined behaviour.

    Source ISO C11 §6.2.4 (storage durations of objects)

  4. Break ItA Chandle Used After DeleteL2 Mid-Level

    Break it: the scoreboard calls model_delete(h) in its final phase, but a late monitor callback still calls model_predict(h, ...). What happens?

    Reveal the Model Answer

    The chandle still holds the old address, so C writes into freed memory. That may work, return garbage or crash much later. C cannot tell a freed pointer from a live one. Set the handle to null right after delete, and have SystemVerilog check it before every call.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "C can check whether the pointer is still valid."

    A freed address looks exactly like a live one. Only a null check on the SystemVerilog side is reliable.

    Source Lesson D1.6 review claims (ISO C++17 [basic.life])

  5. Scale ItCatching DPI Memory Bugs in RegressionL3 Senior

    How do you catch leaks and use-after-free bugs in DPI code across a whole regression?

    Reveal the Model Answer

    Run a nightly subset with AddressSanitizer: build the C model and the simulation with -fsanitize=address. It reports a use-after-free or a wild read at the line that does it. Also keep a live-model counter in C, and check at the end of every test that it is zero.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    Proposes a sanitizer build on a subset, plus a cheap counter check in every test.

    Half-Truth

    "If it does not crash, there is no memory bug."

    A use-after-free often reads stale but plausible data. It corrupts results silently, long before any crash.

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"SystemVerilog frees the returned string when it is done with it."

The simulator copies the text into its own string and leaves C's buffer alone. The twin's heap grows by about 10 MB in 10000 calls.

Run It

A C model returns a fresh 1 KB buffer for each name, 10000 times. glibc reports the heap in use.

RUNVerilator + C/C++ over DPI · simulator service
Edit the code, then run it
Expected: last name=pkt_9999 FAIL: the heap grew by more than 5 MB in 10000 calls; nobody frees the strings C returned
See the Fix
module tb;
  import "DPI-C" function string c_name(input int id);
  import "DPI-C" function longint c_heap_bytes();
  string s;
  longint start_bytes, grew;
  initial begin
    start_bytes = c_heap_bytes();
    for (int i = 0; i < 10000; i++) s = c_name(i);
    grew = c_heap_bytes() - start_bytes;
    $display("last name=%s", s);
    if (grew > 5000000) $display("FAIL: the heap grew by more than 5 MB in 10000 calls; nobody frees the strings C returned");
    else if (grew < 100000) $display("PASS: the heap grew by less than 100 KB; the model reuses a buffer it owns");
    $finish;
  end
endmodule

Prints: last name=pkt_9999 PASS: the heap grew by less than 100 KB; the model reuses a buffer it owns

Misconception

"Both sides use malloc, so C may free a string argument."

The simulator may pass a pointer into its own pool, a stack copy or an internal object. Freeing it corrupts the simulator's heap.

Source IEEE 1800-2017 §35.5.1.4 (memory management)

Buzzword Without Mechanism

"Use smart pointers, and ownership is solved."

A unique_ptr cannot cross the C boundary. SystemVerilog holds a raw address in a chandle, so someone must still call delete exactly once.

Missed Corner

Creates a new model on every DUT reset and never deletes the old one.

Each reset leaks a whole model. Keep one model and give it a reset call, or delete before creating.

Source Lesson D1.6 example (a reset entry point keeps the address and clears the contents)

Learn It, Then Prove It