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

format_from_string and string_of_format #7799

Closed
vicuna opened this issue May 31, 2018 · 5 comments
Closed

format_from_string and string_of_format #7799

vicuna opened this issue May 31, 2018 · 5 comments
Assignees

Comments

@vicuna
Copy link

vicuna commented May 31, 2018

Original bug ID: 7799
Reporter: gmelquiond
Assigned to: @nojb
Status: resolved (set by @nojb on 2018-06-07T07:29:19Z)
Resolution: fixed
Priority: normal
Severity: major
Version: 4.06.1
Category: standard library
Monitored by: @nojb @yakobowski

Bug description

I naively expect the functions format_from_string and string_of_format to be inverse of each other. But they are not, which leads to some obscure bugs when trying to use them. As far as I can tell, it is because format_from_string escapes double quotes but not backslashes before parsing the string. This is reproducible with all the versions of OCaml I have tested, from 4.02.3 to 4.07-beta.

Steps to reproduce

let test s = ignore (Scanf.format_from_string (string_of_format s) s);;
test "%s/%a";; (* OK )
test "\ ";; (
Exception: Scanf.Scan_failure "illegal escape character ' '". )
test "\x";; (
Exception: Scanf.Scan_failure "illegal escape character '"'". )
test "\x25s";; (
Exception: Scanf.Scan_failure "bad input: format type mismatch between "%s" and "\\x25s"". )
test "\"%s";; (
Exception: Scanf.Scan_failure "bad input: format type mismatch between "\\" and "\\\"%s"". )
test "\";; (
Exception: Scanf.Scan_failure "scanning of a String failed: premature end of file occurred before end of token". *)

@vicuna
Copy link
Author

vicuna commented May 31, 2018

Comment author: @gasche

Indeed, it appears that the Scanf.format_of_string implementation, which has its own implementation of string escaping, is buggy. The following would work correctly:

let format_from_string s fmt =
Scanf.sscanf_format (Printf.sprintf "%S" s) fmt (fun s -> s)

I can fix this in the stdlib, but you can also use the code above as a workaround for yourself.

@vicuna
Copy link
Author

vicuna commented May 31, 2018

Comment author: @gasche

Note: since the Big Format Change of 4.02, there is also a function CamlinternalFormat.format_of_string_format, with the same interface as Scanf.format_from_string, which I believe behaves correctly -- its implementation is more directly than Scanf's. CamlinternalFormat functions are internal and not meant for external usage, but this is also a workaround.

I'm curious, what is your use-case for using these functions?

@vicuna
Copy link
Author

vicuna commented May 31, 2018

Comment author: gmelquiond

Sometimes, operator '^^' is not sufficient to manipulate format strings, so you have to go back to plain strings to benefit from a lot more functions. In fact, unless I missed it, there is not even a function that takes a nonliteral string free of '%' and turns it into a plain format string (except for format_of_string, obviously).

Anyway, thanks for the suggestion of using Scanf.sscanf_format. It is much nicer than the one I had come up for Why3, which was to escape all the backslashes before feeding it to format_from_string.

@vicuna
Copy link
Author

vicuna commented Jun 6, 2018

Comment author: @nojb

Just as a follow-up, Scanf.format_from_string actually uses CamlinternalFormat.format_of_string_format. The problem is the implementation of escaping in Scanf.string_to_String which only escapes double quotes.

I submitted a PR with a variant of the fix suggested by Gabriel:

#1820

@vicuna
Copy link
Author

vicuna commented Jun 7, 2018

Comment author: @nojb

PR merged

@vicuna vicuna closed this as completed Jun 7, 2018
@vicuna vicuna added the stdlib label Mar 14, 2019
@vicuna vicuna added the bug label Mar 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants