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

Throw a runtime error instead of terminating #580

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

kalliste
Copy link
Contributor

Elsewhere in this file if something goes wrong we throw a runtime error. If we also do that here instead of calling std::terminate we can catch it and fix the calling code.

@HowardHinnant
Copy link
Owner

This is very difficult logic.

Have you ever had a case where this terminate was called? If so, can you reproduce it? How do you propose that the calling code do when this exception is caught? Or if uncaught, what can the programmer change when discovering the uncaught exception?

@kalliste
Copy link
Contributor Author

kalliste commented Jun 13, 2020

I had a case where terminate was called. It has happened multiple times for end users of my program but I haven't reproduced it yet. I may be able to.

I think probably the cause was that I was calling make_zoned with either NULL or a string that was not a valid timezone in this code:

struct tm t = pAlert->m_TimeStart;                                                                                                                                                                                                                                                                                            
auto system = sys_days{year{t.tm_year + 1900}/(t.tm_mon+1)/t.tm_mday} + hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec};
auto local = make_zoned(szCtlrTimezone, system);
auto lt = local.get_local_time();
auto ld = floor<days>(lt);
time_of_day<seconds> tod{lt - ld};                  
year_month_day ymd{ld};

switch (iIntID)
{
    case SF_INT_ID2_NOTIFICATION_YEAR_LOCAL:          return int{ymd.year()};
    case SF_INT_ID2_NOTIFICATION_MONTH_LOCAL:         return unsigned{ymd.month()};
    case SF_INT_ID2_NOTIFICATION_DAY_LOCAL:           return unsigned{ymd.day()};
    case SF_INT_ID2_NOTIFICATION_HOUR_LOCAL:          return tod.hours().count();
    case SF_INT_ID2_NOTIFICATION_MINUTE_LOCAL:        return tod.minutes().count();
}

Currently I am wrapping this whole section in a try/catch so if it throws instead of terminates then I can log what I was doing when I screwed up

@HowardHinnant
Copy link
Owner

If you pass in a bad time zone name, you'll get an exception with a .what() that says something like: "bad_name not found in timezone database", where "bad_name" is the name you passed in.

So NULL sounds like a more likely culprit. I get a segfault with that. But it didn't make it to the terminate() you propose changing. But guarding against that NULL sounds reasonable.

Repository owner deleted a comment from HowardHinnant Jun 13, 2020
@HowardHinnant
Copy link
Owner

I've added checks to the zoned_time constructors to check for nullptr and throw if found: d544e5a

@dkhalanskyjb
Copy link
Contributor

I did encounter an assertion error when trying to query the TZDB for dates earlier than the minimum year.

@HowardHinnant
Copy link
Owner

If you've got a test case I'd be happy to explore it. I did this and got garbage, but no assert:

#include "date/tz.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    zoned_time zt{current_zone(), sys_days{} - years{50'000}};
    auto lt = zt.get_local_time();
    cout << lt << '\n';
}

@dkhalanskyjb
Copy link
Contributor

Sure. With the current master,

current_zone()->get_info(local_seconds(seconds(-4266666666664)));

crashes for me with

src/tz.cpp:2128: date::sys_info date::time_zone::load_sys_info(std::vector<date::detail::transition>::const_iterator) const: Assertion `i != transitions_.begin()' failed.

I encountered this on both Linux and Mac.

On Linux, I compile the reproducer with these flags:

-lpthread -std=c++17 -DUSE_OS_TZDB=1

@HowardHinnant
Copy link
Owner

Thanks much @dkhalanskyjb ! Fixed with 658a3b9

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.

3 participants