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

Avoid termination due to unhandled exception when parsing invalid arguments to after(...), older(...), thresh(...) and thresh_m(...) #3

Closed
wants to merge 1 commit into from

Conversation

practicalswift
Copy link
Contributor

Hi sipa!

Thanks for your excellent work on miniscript and this C++ implementation!

This is really important work so I decided to put some time into breaking it :-)

That has proven quite hard: the implementation seems to be very robust and well-written. I really like the modern C++ style.

Anyways, this is a small issue I found:

Before:

$ ./miniscript <<< "after(1)"
      0 scriptlen=2 maxops=1 type=B safe=no nonmal=yes dissat=no input=0 output=nonzero miniscript=after(1)
$ ./miniscript <<< "after(100000000000000000000)"
terminate called after throwing an instance of 'std::out_of_range'
  what():  stoul
Aborted
$ ./miniscript <<< "after()"
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoul
Aborted
$ for FUNC in after older thresh thresh_m; do
    for N in "" "100000000000000000000"; do
      MINISCRIPT="${FUNC}(${N})"
      echo "Testing miniscript: ${MINISCRIPT}"
      ./miniscript <<< "${MINISCRIPT}"
      echo
    done
  done
Testing miniscript: after()
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoul
Aborted

Testing miniscript: after(100000000000000000000)
terminate called after throwing an instance of 'std::out_of_range'
  what():  stoul
Aborted

Testing miniscript: older()
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoul
Aborted

Testing miniscript: older(100000000000000000000)
terminate called after throwing an instance of 'std::out_of_range'
  what():  stoul
Aborted

Testing miniscript: thresh()
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoul
Aborted

Testing miniscript: thresh(100000000000000000000)
terminate called after throwing an instance of 'std::out_of_range'
  what():  stoul
Aborted

Testing miniscript: thresh_m()
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoul
Aborted

Testing miniscript: thresh_m(100000000000000000000)
terminate called after throwing an instance of 'std::out_of_range'
  what():  stoul
Aborted

After:

$ ./miniscript <<< "after(1)"
      0 scriptlen=2 maxops=1 type=B safe=no nonmal=yes dissat=no input=0 output=nonzero miniscript=after(1)
$ ./miniscript <<< "after(100000000000000000000)"
Failed to parse as policy or miniscript 'after(100000000000000000000)'
$ ./miniscript <<< "after()"
Failed to parse as policy or miniscript 'after()'
$ for FUNC in after older thresh thresh_m; do
    for N in "" "100000000000000000000"; do
      MINISCRIPT="${FUNC}(${N})"
      echo "Testing miniscript: ${MINISCRIPT}"
      ./miniscript <<< "${MINISCRIPT}"
      echo
    done
  done
Testing miniscript: after()
Failed to parse as policy or miniscript 'after()'

Testing miniscript: after(100000000000000000000)
Failed to parse as policy or miniscript 'after(100000000000000000000)'

Testing miniscript: older()
Failed to parse as policy or miniscript 'older()'

Testing miniscript: older(100000000000000000000)
Failed to parse as policy or miniscript 'older(100000000000000000000)'

Testing miniscript: thresh()
Failed to parse as policy or miniscript 'thresh()'

Testing miniscript: thresh(100000000000000000000)
Failed to parse as policy or miniscript 'thresh(100000000000000000000)'

Testing miniscript: thresh_m()
Failed to parse as policy or miniscript 'thresh_m()'

Testing miniscript: thresh_m(100000000000000000000)
Failed to parse as policy or miniscript 'thresh_m(100000000000000000000)'

@practicalswift practicalswift changed the title Handle parsing of invalid arguments to after(...), older(...), thresh(...) and thresh_m(...) more gracefully Avoid termination due to unhandled exception when parsing invalid arguments to after(...), older(...), thresh(...) and thresh_m(...) more gracefully Aug 27, 2019
@practicalswift practicalswift changed the title Avoid termination due to unhandled exception when parsing invalid arguments to after(...), older(...), thresh(...) and thresh_m(...) more gracefully Avoid termination due to unhandled exception when parsing invalid arguments to after(...), older(...), thresh(...) and thresh_m(...) Aug 27, 2019
@sipa
Copy link
Owner

sipa commented Aug 27, 2019

Nice find. It'd be better to abstract out the whole parse-a-number-and-catch-if-necessary logic rather than repeating it 4 times, though.

@practicalswift
Copy link
Contributor Author

@sipa Good point! I thought about that but wasn't sure about your preference. I'll add a function :-)

…uments to after(...), older(...), thresh(...) and thresh_m(...)
@practicalswift
Copy link
Contributor Author

Now using ParseUInt64 and ParseUInt32 instead.

When reviewing please note the change from unsigned long num to uint64_t num.

Looks OK?

@sipa
Copy link
Owner

sipa commented Sep 4, 2019

@practicalswift Sorry, I forgot about this. I fixed this independently after seeing the Bitcoin Core linter complaining about the use of locale-dependent functions stoul etc. It's fixed in 2e9deb2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants