Skip to content
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

Fix issue 19256: prevent JSONValue const conversion #6716

Conversation

FeepingCreature
Copy link
Contributor

@FeepingCreature FeepingCreature commented Sep 21, 2018

Fix https://issues.dlang.org/show_bug.cgi?id=19256
Reorder JSONValue's union members to make dmd realize that JSONValue contains const references and disallows reassigning const(JSONValue) to JSONValue, which would break constness.
This works around https://issues.dlang.org/show_bug.cgi?id=12885 .

Sample code illustrating the problem:

    const JSONValue innerObj = JSONValue(["foo": JSONValue(1)]);

    assert(innerObj["foo"] == JSONValue(1));

    // Why can I do this??
    JSONValue value = innerObj;

    value["foo"] = JSONValue(2);

    assert(innerObj["foo"] == JSONValue(1)); // fails

@dlang-bot
Copy link
Contributor

dlang-bot commented Sep 21, 2018

Thanks for your pull request and interest in making D better, @FeepingCreature! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

⚠️⚠️⚠️ Warnings ⚠️⚠️⚠️

  • In preparation for migrating from Bugzilla to GitHub Issues, the issue reference syntax has changed. Please add the word "Bugzilla" to issue references. For example, Fix Bugzilla Issue 12345 or Fix Bugzilla 12345.(Reminder: the edit needs to be done in the Git commit message, not the GitHub pull request.)

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + phobos#6716"

@CyberShadow
Copy link
Member

CyberShadow commented Sep 21, 2018

Test, please? You can use static assert(!__traits(compiles, ...)) to test for accepts-invalid bugs.

@FeepingCreature FeepingCreature force-pushed the fix/Issue-19256-JSONValue-const-conversion branch from ff10901 to 5af12a1 Compare September 21, 2018 11:16
@FeepingCreature
Copy link
Contributor Author

Test added.

@FeepingCreature FeepingCreature force-pushed the fix/Issue-19256-JSONValue-const-conversion branch 2 times, most recently from 6e11a63 to 421292b Compare September 21, 2018 11:26
Copy link
Member

@CyberShadow CyberShadow left a comment

Choose a reason for hiding this comment

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

LGTM.

Generally, working around a bug in A by a patch in B is suspicious, but in this case I think it's justified as:

@FeepingCreature
Copy link
Contributor Author

Regarding auto-tester failures, see dlang/druntime#2304

@FeepingCreature FeepingCreature force-pushed the fix/Issue-19256-JSONValue-const-conversion branch from 421292b to 00efd40 Compare September 25, 2018 06:27
@FeepingCreature
Copy link
Contributor Author

druntime PR merged, retrying.

@ghost
Copy link

ghost commented Sep 26, 2018

About buildkite i don't know if you have seen but this PR breaks a non trivial amount of projects (vibe, dls, dub, ...). Ask for an invite to wilzbach or Martin Nowak or andralex in order to see the logs.

const_json_projs

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

Something has to be done for the DUB projects that break.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented Sep 26, 2018

I am not sure that things can be done. D allows you to write straight-up wrong code involving JSONValue right now. Presumably that's what they're doing.

Occasionally fixing a bug implies breaking code that used to work, if it worked in a way that defied the language spec.

@ghost
Copy link

ghost commented Sep 26, 2018

Contacting people so that they change their code is what i had in mind.

@CyberShadow
Copy link
Member

The problem could be in just 1 place in the code, with so many projects failing because said code is a dependency.

@ghost
Copy link

ghost commented Sep 26, 2018

Almost. After looking more carefully at the logs it's always vibe-d (but several places) excepted for the project dls.

@CyberShadow
Copy link
Member

Perhaps leaving this to a compiler fix would be preferred after all, as then it could go through a deprecation phase.

@WalterBright How likely are we to get a fix for https://issues.dlang.org/show_bug.cgi?id=12885 in DMD?

@FeepingCreature
Copy link
Contributor Author

Ping? "Not very likely"?

@MartinNowak
Copy link
Member

@WalterBright How likely are we to get a fix for https://issues.dlang.org/show_bug.cgi?id=12885 in DMD?

I'd say we should fix that issue (https://issues.dlang.org/show_bug.cgi?id=12885#c3), though it will take some deprecation period. So this looks like a reasonable workaround in the meantime.

@MartinNowak
Copy link
Member

Build failure of vibe.d (https://buildkite.com/dlang/phobos/builds/397#dccb2203-9142-4358-9840-e650356a4ccb/99-140).

Error
vibe-core-1.4.3/vibe-core/source/vibe/core/args.d(68,27): Error: function `vibe.core.args.fromValue!bool.fromValue(JSONValue val)` is not callable using argument types `(const(JSONValue))`
vibe-core-1.4.3/vibe-core/source/vibe/core/args.d(68,27):        cannot pass argument `*pv` of type `const(JSONValue)` to parameter `JSONValue val`
vibe-core-1.4.3/vibe-core/source/vibe/core/args.d(298,12): Error: template instance `vibe.core.args.readOption!bool` error instantiating
vibe-core-1.4.3/vibe-core/source/vibe/core/core.d(692,70): Deprecation: `std.algorithm.setops.No` is not visible from module `core`
vibe-core-1.4.3/vibe-core/source/vibe/core/args.d(68,27): Error: function `vibe.core.args.fromValue!string.fromValue(JSONValue val)` is not callable using argument types `(const(JSONValue))`
vibe-core-1.4.3/vibe-core/source/vibe/core/args.d(68,27):        cannot pass argument `*pv` of type `const(JSONValue)` to parameter `JSONValue val`
vibe-core-1.4.3/vibe-core/source/vibe/core/core.d(1328,13): Error: template instance `vibe.core.args.readOption!string` error instantiating

MartinNowak added a commit to MartinNowak/vibe-core that referenced this pull request Nov 1, 2018
- "key" in JSONValue returns const(JSONValue)*
- fromValue expected non-const JSONValue
- implicit conversion of const(JSONValue) to JSONValue to be fixed
  with dlang/phobos#6716
@MartinNowak
Copy link
Member

Here is a trivial PR to vibe.d vibe-d/vibe-core#100, seems like a rare occurrence of sth. that breaks with this workaround, so it might still be reasonable to go ahead with this once a new vibe.d version is released.

@MartinNowak MartinNowak changed the base branch from stable to master January 1, 2019 23:41
@MartinNowak MartinNowak force-pushed the fix/Issue-19256-JSONValue-const-conversion branch from 00efd40 to 1609b9e Compare January 1, 2019 23:41
@MartinNowak
Copy link
Member

Should work now with the fixed vibe-d and good to go for 2.085.0 from my side. Seemed to risky to put in 2.084.0 without beta.

@FeepingCreature
Copy link
Contributor Author

ping

@thewilsonator
Copy link
Contributor

Ack, waiting on #7011 for green tests.

@thewilsonator
Copy link
Contributor

Can you please rebase this so the circle error goes away?

Reorder JSONValue's union members to make dmd realize that JSONValue contains const references and disallows reassigning const(JSONValue) to JSONValue, which would break constness.
This works around https://issues.dlang.org/show_bug.cgi?id=12885 .
@thewilsonator
Copy link
Contributor

Hmm vibe.d still fails.

@schveiguy
Copy link
Member

I think this PR should be closed. The only practical way forward is to deprecate and remove the behavior, and since the behavior is 100% compiler related (you can't hook an implicit cast away from const), it can't be done in a library.

Note, I found that SumType suffers from the same problem. And it happens in @safe code too.

https://forum.dlang.org/post/t5pp8u$6l7$1@digitalmars.com

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 17, 2022

I don't follow why. Should D take the const-convertible-ness of a union from the first field? I guess not, but it works today, and then JSONValue behaves correctly.

oh wait I see, you mean get rid of that logic. Yeah, I guess. I'd rather see it codified as "well this sucks, but it's the best we can do."

SumType can "fix" this by just reordering its union by hasIndirections. It's not a good solution but it is a solution.

edit: I think fixing 12885 is viable. For the record, I said in 2019 that I need this behavior, but this is no longer the case; librebindable uses a totally different approach (involving a lot more casting).

@schveiguy
Copy link
Member

I'd rather see it codified as "well this sucks, but it's the best we can do."

It's not memory safe in @safe code. If D is no longer serious about memory safety, then we can leave it. I guess another option is to disable using such types in @safe code.

SumType can "fix" this by just reordering its union by hasIndirections. It's not a good solution but it is a solution.

SumType will suffer exactly the same fate as JSONValue the more it is used. Eventually there will be critical projects that will break with your suggested change because they accidentally implicitly cast away const, and it will become untouchable.

And there is no way to deprecate it, unless we want to rename the type.

The only path forward is to deprecate the current memory-unsafe behavior, and then fix it.

librebindable uses a totally different approach (involving a lot more casting).

Rebindable in general is a horrendous hack, making up for a lack of tail-modifiers in the language. I'm not convinced it's sound type-wise.

@FeepingCreature
Copy link
Contributor Author

I mean, if the bug is fixed, JSONValue and SumType will break regardless, surely?

Rebindable in general is a horrendous hack, making up for a lack of tail-modifiers in the language. I'm not convinced it's sound type-wise.

I believe that librebindable is typesafe, or rather, can be used to build typesafe abstractions if used correctly. Phobos Rebindable definitely wouldn't be typesafe, especially if it worked for structs, because it exposes its value by ref, leading to pointer leaks that allow observing immutable changes. My primary argument for librebindable being sound is that it does not do this.

@schveiguy
Copy link
Member

I mean, if the bug is fixed, JSONValue and SumType will break regardless, surely?

Yes, but the big difference is that the compiler can deprecate the behavior first, notifying anyone using it for a (probably long-ish) period of time. A library cannot hook the implicit cast.

@schveiguy
Copy link
Member

I believe that librebindable is typesafe, or rather, can be used to build typesafe abstractions if used correctly.

I honestly have not read much into it. The idea of deconstifying copied data is sound (i.e. deconstifying the head), but what I'm more worried about is if it's sound within the current model. That is, will amazingly obtuse optimizations suddenly happen because they are sound within the model, but not with the hacks performed here?

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented May 18, 2022

Yes, but the big difference is that the compiler can deprecate the behavior first, notifying anyone using it for a (probably long-ish) period of time. A library cannot hook the implicit cast.

Ah, now I get what you're saying. Yeah if there's hope of the bug being fixed, I agree that's better than this PR.

@LightBender
Copy link
Contributor

Underlying issue has been fixed. You can reopen if it is still relevant. Closing this PR.

@FeepingCreature
Copy link
Contributor Author

FeepingCreature commented Oct 27, 2024

Underlying issue has not been fixed? I just reproed 19256 on dmd master.

@schveiguy schveiguy reopened this Oct 27, 2024
@thewilsonator
Copy link
Contributor

https://issues.dlang.org/show_bug.cgi?id=12885 was allegedly fixed by dlang/dmd#16594
Was that an incomplete fix?

@LightBender LightBender added the Review:Salvage This PR needs work, but we want to keep it and it can be salvaged. label Oct 27, 2024
@FeepingCreature
Copy link
Contributor Author

Oh! You are correct. It's gated behind -preview=fixImmutableConv. I'll add a comment to 19256.

@thewilsonator
Copy link
Contributor

Thanks for the investigation!

@FeepingCreature FeepingCreature deleted the fix/Issue-19256-JSONValue-const-conversion branch October 27, 2024 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Review:Salvage This PR needs work, but we want to keep it and it can be salvaged. Severity:Bug Fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants