raspberrypi / piserver

Raspberry Pi Server wizard to serve Raspbian to network booting Pis
313 stars 59 forks source link

GLib assertion 'datetime->ref_count > 0' fails causing GUI to not be displayed #133

Closed callumtilbury closed 3 years ago

callumtilbury commented 3 years ago

I am encountering the following bug, when trying to run PiServer (i.e. sudo piserver):

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed

(piserver:4988): GLib-CRITICAL **: 12:09:14.380: g_date_time_unref: assertion 'datetime->ref_count > 0' failed
**
GLib:ERROR:../../../glib/gdatetime.c:2194:g_date_time_get_ymd: assertion failed: (0 <= remaining_days)
Bail out! GLib:ERROR:../../../glib/gdatetime.c:2194:g_date_time_get_ymd: assertion failed: (0 <= remaining_days)
Aborted

This error has been encountered on both Pop!_OS 20.04 and Ubuntu 20.04.

It only appears intermittently, an arbitrary amount of time after installing PiServer. PiServer is actually running in the background—as the Pis do still boot—but the GUI cannot be accessed. The only workaround found thus far has been a full purge and reinstall.

maxnet commented 3 years ago

Does it work any better if in piserver/user.cpp you replace:

const std::string User::lastlogin(const char *format) const
{
    if (!_lastLoginTime)
        return "";

    auto dt = Glib::DateTime(_lastLoginTime);
    return dt.format(format);
}

with:

const std::string User::lastlogin(const char *format) const
{
    if (!_lastLoginTime)
        return "";

    gchar *gstr = g_date_time_format(_lastLoginTime, format);
    if (!gstr)
    return "";

    std::string result(gstr);
    g_free(gstr);

    return result;
}
callumtilbury commented 3 years ago

Does it work any better if in piserver/user.cpp you replace:

Thanks so much for the suggestion! I'll build with those changes, and see if the issue pops up in the coming days. I will let you know.

callumtilbury commented 3 years ago

@maxnet Unfortunately we have hit the same issue again.

It seems to be complaining about a call to g_date_time_unref( ), which is in the User destructor:

User::~User()
{
    if (_lastLoginTime)
    {
        g_date_time_unref(_lastLoginTime);
    }
}

Could it be an issue with that?

maxnet commented 3 years ago

Could it be an issue with that?

I do think that is where the error message is being generated.

However the GDateTime created by g_date_time_new_from_iso8601() in constructor (if LDAP server has a record for last login time of that user) does need to be unreferenced by g_date_time_unref() when no longer used.

https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-new-from-iso8601

You should release the return value by calling g_date_time_unref() when you are done with it.

So should only be a problem if:

maxnet commented 3 years ago

Hmm, thinking of it. Does it work better if you add a copy constructor that increases reference count (in addition to the previous change)?

In the user.cpp add:

User::User(const User &u)
{
    _dn = u._dn;
    _name = u._name;
    _description = u._description;
    _lastLoginTime = u._lastLoginTime;
    if (_lastLoginTime)
    {
        g_date_time_ref(_lastLoginTime);
    }
}

And in the user.h add somewhere under public:

User(const User &u);
maxnet commented 3 years ago

Managed to reproduce the assertion (although it does not crash for me). Fixed in 0.7.3