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

The magic number checks of Ast_4NN.register appear to be broken #97

Closed
gasche opened this issue May 22, 2020 · 12 comments
Closed

The magic number checks of Ast_4NN.register appear to be broken #97

gasche opened this issue May 22, 2020 · 12 comments

Comments

@gasche
Copy link

gasche commented May 22, 2020

I am trying to understand the cause of a segfault in ppx_deriving (reported by @kit-ty-kate) since we migrated to ppxlib, see ocaml-ppx/ppx_deriving#210 (comment) . @thierry-martinez tracked down the issue to incompatible serialized ASTs (we seem to be calling input_value on an AST of some version, and getting a segfault when we try to use it as it was of another version), originating from a call to Ast_408.Ast_mapper.register. This suggests an issue in m-o-p, at least in terms of validation of magic numbers.

Indeed, the current source fo Ast_408 and all later versions have an Ast_mapper.apply_lazy module that performs magic number check using a Config module that appears to be the current compiler-libs config module (so it is checking against the current magic numbers, not 4.08's). There is a Config module defined later in the file, which provides the correct 4.08 magic numbers.

Magic number checking lines 3843-3847:
https://github.com/ocaml-ppx/ocaml-migrate-parsetree/blob/18c00c9/src/ast_408.ml#L3843-L3847

Re-definition of Config lines 4043-4046:
https://github.com/ocaml-ppx/ocaml-migrate-parsetree/blob/18c00c9/src/ast_408.ml#L4043-L4046

Questions:

  • Is this analysis correct, that the magic number checks of the Ast_4NN modules (_409 and _410 at least appear to have copy-pasted this code) are checking against the current-version magic number instead of their own version?
  • If this is the case, how come nobody noticed this before?
  • Why are those modules containing a reimplementation of this logic? This was not the case for Ast_407 and earlier versions. I tracked the issue to the first commit of @xclerc in Support for OCaml 4.08 #70. I suppose that the reimplementation is there to work around some kind of upstream change, but I am not sure which one.

(cc also @rgrinberg @jeremiedimino)

thierry-martinez added a commit to thierry-martinez/ocaml-migrate-parsetree that referenced this issue May 22, 2020
…gister`

This commit fixes
ocaml-ppx#97
which caused segfaults: `Ast_4NN.register` now correctly checks
AST magic number against the version-specific magic number instead
of using the magic number defined in the `Config` module of the
current compiler.

Version-specific magic numbers was already defined by overriding
`Config` module later in the file: the fix just consists in riding up the
overriding of `Config` before the overriding of
`Ast_helper`. Following Gabriel Scherer's trick recommended in
ocaml-ppx/ppx_deriving#210 (comment)
a unit-value `in_ast_4nn` is defined in `Config` module and used in
`Ast_helper.register` to ensure that the module are well ordered.
@gasche
Copy link
Author

gasche commented May 22, 2020

Thinking more about it, I am not completely sure of what is the intended semantics of Ast_4NN.register. Should it:

  1. register a 4NN-rewriter in such a way that it works on current serialized ASTs, or
  2. register a 4NN-rewriter in such a way that it works on serialized ASTs for OCaml 4NN?

Currently it is doing neither: it opens current serialized ASTs but calls a 4NN-rewriter without any conversion, leading to segfaults. My suggestion to change the magic-number check would implement (2). On the other hand, if you/we want (1), then we should (keep expecting the current magic numbers and) add a conversion pass on the rewriter.

I believe that the intended semantics should be documented clearly to help avoid issues. (Even without the current bug, if people use .register wrongly they get a runtime error, instead of a typing error as with most Migrate-parsetree version mistakes.)

(2) may be the more common need (it is rare to compile on a given version of OCaml and expect to produce a working ppx rewriter for an older version of OCaml), but then it is easily expressible by users today with just a single register function and the Convert module. It is also unclear to me that it can be implemented in the Ast_* module, because the conversion logic is not available yet at this point.

thierry-martinez added a commit to thierry-martinez/ocaml-migrate-parsetree that referenced this issue May 22, 2020
…rent AST

As Gabriel Scherer explained in
ocaml-ppx#97 (comment)
there is two possible semantics for `Ast_4NN.register`.

(1) register a 4NN-rewriter in such a way that it works on _current_ serialized ASTs

(2) register a 4NN-rewriter in such a way that it works on serialized ASTs for OCaml 4NN

This commit implements (1) whereas
ocaml-ppx#98
implements (2).
@gasche
Copy link
Author

gasche commented May 22, 2020

@thierry-martinez implemented two fixes that give either semantics: #98 and #99

It would be great to have guidance from someone more familiar with ocaml-migrate-parsetree (in particular someone who could review and make merge decisions!) on which way the tool should go.

@ghost
Copy link

ghost commented May 25, 2020

I'm pretty sure we added these by accident since 4.08. The update process of omp is quite complicated, so I'm not surprised this happened.

@gasche
Copy link
Author

gasche commented May 28, 2020

You mention that you are planning to remove those erroneous register function, which I think is perfectly fine. Which other parts of the API do you think should be removed? (There more copy-paste from the compiler implementation in those files?). I think the safest would be to expose no more than Ast_407 and earlier modules, but I suppose there was a reason why more code was copied at the _408 level? (Maybe to deal with the updated Location or something?)

@ghost
Copy link

ghost commented May 28, 2020

There seems to be some register functions in Docstrings as well. Though I don't expect this module to be used much, so I'm not planning to be over-zealous here.

I think the safest would be to expose no more than Ast_407 and earlier modules, but I suppose there was a reason why more code was copied at the _408 level? (Maybe to deal with the updated Location or something?)

The upgrade process is not mechanical. It is painfully manual and not very well formalised. For 4.08, it was done by a new person and the fact that the register functions have to be delete wasn't written anywhere. Nowadays I always glance at the diff between ast_N.ml and ast_(N+1).ml to check it looks sensible.

@ghost
Copy link

ghost commented Jun 1, 2020

I believe this can be closed now.

@ghost ghost closed this as completed Jun 1, 2020
@ghost
Copy link

ghost commented Jun 1, 2020

BTW, one thing we mentioned in the past with @let-def is that we could narrow the scope of ocaml-migrate-parsetree to just the parsetree type migrations. Which is what it was originally supposed to be. It seems that ppxlib has been adopted quite widely adopted now, so it might be realistic to reduce the various Ast_XXX modules to just the parsetree types, get rid of the Driver module and maybe a couple of other things. That would make the ecosystem a bit simpler, and perhaps make our work on the new ppx library a bit easier as well.

@let-def
Copy link
Collaborator

let-def commented Jun 1, 2020

Yes, I still think this is a worthwhile simplification. It should just be done carefully to avoid more breakage.

@ghost
Copy link

ghost commented Jun 1, 2020

Indeed. I was looking at the dune-universe and there seems to be quite a few references to Migrate_parsetree.Driver still, so we'd have to ask quite a few people to port their code to ppxlib. Given that the plan is to eventually ask everyone to switch to ppx, we should probably just wait until ppx is ready.

@ghost
Copy link

ghost commented Jun 2, 2020

We were just talking about this with @NathanReb and @avsm, and that seems to be a good problem to throw at the duniverse. More precisely, we could simplify ocaml-migrate-parsetree as one breaking 2.0.0 release and use duniverse to realistically migrate all packages currently relying on the omp driver to ppxlib at once.

We started playing with the idea of creating a duniverse with all the ppx projects out there still using the ocaml-migrate-parsetree driver: https://github.com/dune-universe/ppx-duniverse

@ghost
Copy link

ghost commented Jun 9, 2020

After talking to a few people, we are actually going to do this. The overall plan is:

  • port packages using omp/ppx_tools_versioned to ppxlib
  • prepare a 2.0.0 version of omp that is just the parsetree types and migration functions
  • update ppxlib to work with omp 2.0.0
  • address the few aspects of ppxlib that might make people reluctant to depend on it, such as the dependency on Base
  • once all the packages ported to ppxlib have been released, release omp 2.0.0 and the version ppxlib compatible with it

I'll announce this more publicly on discuss shortly.

@ghost
Copy link

ghost commented Jun 9, 2020

@gasche @thierry-martinez when you have some time, I'm also interested to talk about the loader of ppx_deriving

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants