-
-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
exercises(all-your-base): add missing frees #317
Conversation
The comment in user code says: /// Caller owns the returned memory. However, the testing code does not free returned memory if the answer is zero = {0}. As the result, users get memory leaks with wrong code due to testing code breaking the contract. Some awful hacks are necessary to workaround it.
This comment was marked as resolved.
This comment was marked as resolved.
Note that this is breaking change: solutions which previously did pass by adding a workaround will no longer pass after merging this. As a non-breaking alternative, it might be OK to disable memory leak check in these three tests, so that both the old solutions pass, and the proper solutions pass despite memory leak in testing code. |
Thanks for the PR. As-is, this PR may remove memory leak errors when testing an invalid solution. But it causes a panic when testing a valid solution, right?
|
Fix returning reference to invalid memory.
Fix "invalid free" errors.
I initially read this as "the problem only affects solutions that don't pass the tests". That is, "the tests where But I see that testing your submitted solution produces memory leak errors if you comment out lines 72-75. I didn't immediately see why. However, without this PR, there are no memory leak errors when testing the other published solutions:
and with this PR, testing each of the above solutions produces a panic due to invalid free. Could you please investigate why your solution requires lines 72-75, and other solutions don't require the same? Edit: I guess it's because one approach involves: var zero = [_]u32{0};
[...]
if (num == 0) {
return &zero;
} while your solution does: if (res.items.len == 0)
try res.append(0); So I think we do want to add |
As I explained in #319, all the accepted solutions are currently broken as well (mine inclueded!). Some of them return a reference to a local variable (which is obviously wrong), whereas some others return a reference to a global array (which is wrong too because if can be modified to not be zero anymore). The only options are:
Option 1 is not nice because it doesn't make much sense to sometimes return an owned slice and sometimes not. |
@FedericoStra thanks for your thoughts. I agree that it'd be better to avoid the global array. But if Can we do better than just adding comments to the tests, and adding explanation in the instructions? There's no reasonable and robust way to free That said, as @stgatilov pointed out, the doc comment does say "Caller owns the returned memory". |
I pushed commits to fix the example solution. I'll merge this soon, but later we could try to help the user that returns a reference to a global array for the tests that expect
I think it's better to break submitted solutions here. This exercise was added only recently. |
@stgatilov @FedericoStra Sorry for the inconvenience, and thanks again for the PRs. Apparently I wasn't thinking when I implemented this exercise. You should be able to fix your solutions now. |
Yes, I fixed the solution. P.S. Actually, exercism does not automatically drop accepted solutions, it merely suggests updating to the new version and retrying tests. So there is no problem at all in breaking existing solutions, if this makes the problem better. |
I don't think there is, apart from some scary dark magic... I personally think that the solutions returning a reference to a mutable global array should be considered invalid (mine currently does so) and people should be forced to respect the docstring contract that /// Caller owns the returned memory. |
If I recall correctly, when a test file changes, Exercism really does put every corresponding solution in a queue to be retested. You can see here that old solutions are now marked with a red cross. But it's fine to break solutions in this case anyway.
Sure. But as an aside: I think we should generally allow the user to alter the doc string, or at least append to it, to the extent permitted by the tests (which they shouldn't change). In this case, that contract is enforced by the tests. In other cases, the contract will be enforced by future tests (e.g. when But for example, in the /// Caller guarantees that the maximum nesting depth of brackets in `s` is at most 100 and then use a local array to determine whether brackets are matched, without using the given allocator. |
I agree that users should be allowed to change the contract, but I disagree that in this case the tests are thorough enough. Returning a mutable global array is clearly wrong and should be tested. The following tests breaks all current solutions that return a reference to the same global test "does not return the same zero multiple times" {
const expected = [_]u32{0};
const digits = [_]u32{0};
const input_base = 10;
const output_base = 2;
const actual = try convert(testing.allocator, &digits, input_base, output_base);
try testing.expectEqualSlices(u32, &expected, actual);
actual[0] = 1 // modify the output!
const again = try convert(testing.allocator, &digits, input_base, output_base);
try testing.expectEqualSlices(u32, &expected, again);
} |
@FedericoStra Thanks for your thoughts. Well, "the tests enforce the contract" in the sense that they now panic for a solution that returns a reference to a global array. Every test now contains a free, and that memory can't be freed. So the current tests are "sufficient" in the sense that Exercism won't mark such a solution as passing. But I agree the tests should be more thorough. Part of my concern above was that I'd like such a solution to fail a test, rather than only producing a panic. I've created #322 to add the test case you proposed, with exactly these changes:
I'll try to merge that PR before the weekend. If it's not merged when you read this: could you please review it? Otherwise, please yell at me if you have suggested improvements. |
And nice work on ziglang/zig@4f952c7 :) Was it from going down the rabbit hole on an Exercism exercise? I believe ziglang/zig#14827 was created due to the |
#322 looks good to me! With this test it should be indeed easier for a user to identify the problem with returning a global array.
Yes, exactly! I used On top of that, the comment before I love how it's a back and forth between two lovely languages trying to help each other out. |
The comment in user code says:
However, the testing code does not free returned memory if the answer is zero = {0}. As the result, users get memory leaks with wrong code due to testing code breaking the contract. Some awful hacks are necessary to workaround it.
Closes: #319