[{"id":17168,"web_url":"https://patchwork.libcamera.org/comment/17168/","msgid":"<CAO5uPHPAZ-TMQV0N6A3VYiVicn4KXeK4RgWhqomyD_QOA04m8w@mail.gmail.com>","date":"2021-05-24T05:19:03","subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","submitter":{"id":63,"url":"https://patchwork.libcamera.org/api/people/63/","name":"Hirokazu Honda","email":"hiroh@chromium.org"},"content":"Hi Laurent, thank you for the patch.\n\nOn Sun, May 23, 2021 at 9:04 AM Laurent Pinchart <\nlaurent.pinchart@ideasonboard.com> wrote:\n\n> The LogCategory instances are constructed on first use as static\n> variables in accessor functions, following the Meyers singleton pattern.\n> As a result, their destruction order is not guaranteed. This can cause\n> issues as the global Logger object, constructed in a similar fashion, is\n> accessed from the LogCategory destructor and may be destroyed first.\n>\n> To fix this, keep the same singleton pattern, but allocate the\n> LogCategory instances dynamically. As they get registered with the\n> global Logger instance, we can destroy them in the Logger destructor.\n>\n> This only avoids destruction order issues between LogCategory and\n> Logger, and doesn't address yet the fact that LOG() calls from\n> destructors of global objects may access an already destroyed Logger.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/internal/log.h |  5 ++---\n>  src/libcamera/log.cpp            | 32 +++++++++++---------------------\n>  2 files changed, 13 insertions(+), 24 deletions(-)\n>\n> diff --git a/include/libcamera/internal/log.h\n> b/include/libcamera/internal/log.h\n> index b66bf55bc57d..1032bdd93e7c 100644\n> --- a/include/libcamera/internal/log.h\n> +++ b/include/libcamera/internal/log.h\n> @@ -29,7 +29,6 @@ class LogCategory\n>  {\n>  public:\n>         explicit LogCategory(const char *name);\n> -       ~LogCategory();\n\n\n>         const char *name() const { return name_; }\n>         LogSeverity severity() const { return severity_; }\n> @@ -48,8 +47,8 @@ extern const LogCategory &_LOG_CATEGORY(name)();\n>  #define LOG_DEFINE_CATEGORY(name)                                      \\\n>  const LogCategory &_LOG_CATEGORY(name)()                               \\\n>  {                                                                      \\\n> -       static LogCategory category(#name);                             \\\n> -       return category;                                                \\\n>\n\nI would like to have a comment that the created category will be deleted on\nLogger destruction?\n\nWith that, this change looks good to me.\n\nReviewed-by: Hirokazu Honda <hiroh@chormium.org>\n\n+       static LogCategory *category = new LogCategory(#name);          \\\n> +       return *category;                                               \\\n>  }\n>\n>  class LogMessage\n> diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\n> index dd991647b9bc..74829a56916e 100644\n> --- a/src/libcamera/log.cpp\n> +++ b/src/libcamera/log.cpp\n> @@ -248,6 +248,8 @@ void LogOutput::writeStream(const std::string &str)\n>  class Logger\n>  {\n>  public:\n> +       ~Logger();\n> +\n>         static Logger *instance();\n>\n>         void write(const LogMessage &msg);\n> @@ -267,7 +269,6 @@ private:\n>\n>         friend LogCategory;\n>         void registerCategory(LogCategory *category);\n> -       void unregisterCategory(LogCategory *category);\n>\n>         std::unordered_set<LogCategory *> categories_;\n>         std::list<std::pair<std::string, LogSeverity>> levels_;\n> @@ -369,6 +370,12 @@ void logSetLevel(const char *category, const char\n> *level)\n>         Logger::instance()->logSetLevel(category, level);\n>  }\n>\n> +Logger::~Logger()\n> +{\n> +       for (LogCategory *category : categories_)\n> +               delete category;\n> +}\n> +\n>  /**\n>   * \\brief Retrieve the logger instance\n>   *\n> @@ -665,18 +672,6 @@ void Logger::registerCategory(LogCategory *category)\n\n        }\n>  }\n>\n> -/**\n> - * \\brief Unregister a log category from the logger\n> - * \\param[in] category The log category\n> - *\n> - * If the \\a category hasn't been registered with the logger this function\n> - * performs no operation.\n> - */\n> -void Logger::unregisterCategory(LogCategory *category)\n> -{\n> -       categories_.erase(category);\n> -}\n> -\n>  /**\n>   * \\enum LogSeverity\n>   * Log message severity\n> @@ -711,11 +706,6 @@ LogCategory::LogCategory(const char *name)\n>         Logger::instance()->registerCategory(this);\n>  }\n>\n> -LogCategory::~LogCategory()\n> -{\n> -       Logger::instance()->unregisterCategory(this);\n> -}\n> -\n>  /**\n>   * \\fn LogCategory::name()\n>   * \\brief Retrieve the log category name\n> @@ -746,12 +736,12 @@ void LogCategory::setSeverity(LogSeverity severity)\n>   * The default log category is named \"default\" and is used by the LOG()\n> macro\n>   * when no log category is specified.\n>   *\n> - * \\return A pointer to the default log category\n> + * \\return A reference to the default log category\n>   */\n>  const LogCategory &LogCategory::defaultCategory()\n>  {\n> -       static const LogCategory category(\"default\");\n> -       return category;\n> +       static const LogCategory *category = new LogCategory(\"default\");\n> +       return *category;\n>  }\n>\n>  /**\n> --\n> Regards,\n>\n> Laurent Pinchart\n>\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 12F11C3200\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 24 May 2021 05:19:17 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 71C7E6891B;\n\tMon, 24 May 2021 07:19:16 +0200 (CEST)","from mail-ed1-x536.google.com (mail-ed1-x536.google.com\n\t[IPv6:2a00:1450:4864:20::536])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 255BB602AD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 24 May 2021 07:19:15 +0200 (CEST)","by mail-ed1-x536.google.com with SMTP id y7so12895273eda.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 23 May 2021 22:19:15 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"ibEfPUlG\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org;\n\ts=google; \n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=rOjDKuT1trZI9JQlzJA/03YBoA7i9DQoBOAC/vIxetw=;\n\tb=ibEfPUlGDkRLcJkB2io+N1A9Rylwi9fiKqp9NEW6KQaOCCIrNQNXMPA0SMUJF8hXVf\n\tG2gCOLbRNzzFL0iDjfkaRZ/aY5PvDRX+3UyPDc6moRwMTVO8aTE0U1A2rtcdlFsSbcaz\n\tk+bfWBesdWpVS0pWe5f/ySMX9lS+MuL7Ou0AE=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=rOjDKuT1trZI9JQlzJA/03YBoA7i9DQoBOAC/vIxetw=;\n\tb=cD095Vig1wuJ7+Qus5ZeaUImu50yyhVxPI+rKsCjC/domDO4/vOlYtga2tBm9ZoLgs\n\tQf6a8u06LvvCaXJQoXLunawXo2nFFY45Q2q06L9iYjhT3O7jYNMs34a1lptZz5O2Zd4L\n\tK6Oxerm0oKbYuDTUAphsbM5TvJTE8cCqO0LM+bal+s0osmVqnx678F+ovGe6sMhu4AsX\n\tc2hi/ElOQ7OgnvY7GkuZjWhMZTuee3w+pZmHc2n4XHFqImpCFf0waNba4PK6Dx9JAcsN\n\tprtJeRKeNHd7huQt7E9dGMdiZttsRV0HDGl7PD7UntcQbrYEvsTLmVX73ukdHmRgBwSH\n\tZXHw==","X-Gm-Message-State":"AOAM532jYco4Sg5LRn3f5bUzLrIXckMiwVw/ze4SefivnON6OSJtih3I\n\tJyHc4f4/SMkTP5Fjbky6qUrb/UAfGdQlANX9eDstEI+IolM=","X-Google-Smtp-Source":"ABdhPJwfqh9sFMtJeiHgaOAPHgLc87gxt+tz5JUer+Wk+o1FzvS7ZoEDAxiNxRuDCQLA7JXveZJlb1yS0JHeMzceY4g=","X-Received":"by 2002:a50:afa3:: with SMTP id\n\th32mr23433829edd.202.1621833554843; \n\tSun, 23 May 2021 22:19:14 -0700 (PDT)","MIME-Version":"1.0","References":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>","In-Reply-To":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>","From":"Hirokazu Honda <hiroh@chromium.org>","Date":"Mon, 24 May 2021 14:19:03 +0900","Message-ID":"<CAO5uPHPAZ-TMQV0N6A3VYiVicn4KXeK4RgWhqomyD_QOA04m8w@mail.gmail.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Content-Type":"multipart/alternative; boundary=\"000000000000ec07f705c30c8c8f\"","Subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17196,"web_url":"https://patchwork.libcamera.org/comment/17196/","msgid":"<YKubfnMd5XFNhAVP@pendragon.ideasonboard.com>","date":"2021-05-24T12:26:38","subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Hiro,\n\nOn Mon, May 24, 2021 at 02:19:03PM +0900, Hirokazu Honda wrote:\n> On Sun, May 23, 2021 at 9:04 AM Laurent Pinchart wrote:\n> > The LogCategory instances are constructed on first use as static\n> > variables in accessor functions, following the Meyers singleton pattern.\n> > As a result, their destruction order is not guaranteed. This can cause\n> > issues as the global Logger object, constructed in a similar fashion, is\n> > accessed from the LogCategory destructor and may be destroyed first.\n> >\n> > To fix this, keep the same singleton pattern, but allocate the\n> > LogCategory instances dynamically. As they get registered with the\n> > global Logger instance, we can destroy them in the Logger destructor.\n> >\n> > This only avoids destruction order issues between LogCategory and\n> > Logger, and doesn't address yet the fact that LOG() calls from\n> > destructors of global objects may access an already destroyed Logger.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  include/libcamera/internal/log.h |  5 ++---\n> >  src/libcamera/log.cpp            | 32 +++++++++++---------------------\n> >  2 files changed, 13 insertions(+), 24 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/log.h\n> > b/include/libcamera/internal/log.h\n> > index b66bf55bc57d..1032bdd93e7c 100644\n> > --- a/include/libcamera/internal/log.h\n> > +++ b/include/libcamera/internal/log.h\n> > @@ -29,7 +29,6 @@ class LogCategory\n> >  {\n> >  public:\n> >         explicit LogCategory(const char *name);\n> > -       ~LogCategory();\n> >\n> >         const char *name() const { return name_; }\n> >         LogSeverity severity() const { return severity_; }\n> > @@ -48,8 +47,8 @@ extern const LogCategory &_LOG_CATEGORY(name)();\n> >  #define LOG_DEFINE_CATEGORY(name)                                      \\\n> >  const LogCategory &_LOG_CATEGORY(name)()                               \\\n> >  {                                                                      \\\n> > -       static LogCategory category(#name);                             \\\n> > -       return category;                                                \\\n> \n> I would like to have a comment that the created category will be deleted on\n> Logger destruction?\n\nGood point, I'll add that.\n\n\t/* The instance will be deleted by the Logger destructor. */\n\n> With that, this change looks good to me.\n> \n> Reviewed-by: Hirokazu Honda <hiroh@chormium.org>\n\nThank you.\n\n> +       static LogCategory *category = new LogCategory(#name);          \\\n> > +       return *category;                                               \\\n> >  }\n> >\n> >  class LogMessage\n> > diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\n> > index dd991647b9bc..74829a56916e 100644\n> > --- a/src/libcamera/log.cpp\n> > +++ b/src/libcamera/log.cpp\n> > @@ -248,6 +248,8 @@ void LogOutput::writeStream(const std::string &str)\n> >  class Logger\n> >  {\n> >  public:\n> > +       ~Logger();\n> > +\n> >         static Logger *instance();\n> >\n> >         void write(const LogMessage &msg);\n> > @@ -267,7 +269,6 @@ private:\n> >\n> >         friend LogCategory;\n> >         void registerCategory(LogCategory *category);\n> > -       void unregisterCategory(LogCategory *category);\n> >\n> >         std::unordered_set<LogCategory *> categories_;\n> >         std::list<std::pair<std::string, LogSeverity>> levels_;\n> > @@ -369,6 +370,12 @@ void logSetLevel(const char *category, const char\n> > *level)\n> >         Logger::instance()->logSetLevel(category, level);\n> >  }\n> >\n> > +Logger::~Logger()\n> > +{\n> > +       for (LogCategory *category : categories_)\n> > +               delete category;\n> > +}\n> > +\n> >  /**\n> >   * \\brief Retrieve the logger instance\n> >   *\n> > @@ -665,18 +672,6 @@ void Logger::registerCategory(LogCategory *category)\n> \n>         }\n> >  }\n> >\n> > -/**\n> > - * \\brief Unregister a log category from the logger\n> > - * \\param[in] category The log category\n> > - *\n> > - * If the \\a category hasn't been registered with the logger this function\n> > - * performs no operation.\n> > - */\n> > -void Logger::unregisterCategory(LogCategory *category)\n> > -{\n> > -       categories_.erase(category);\n> > -}\n> > -\n> >  /**\n> >   * \\enum LogSeverity\n> >   * Log message severity\n> > @@ -711,11 +706,6 @@ LogCategory::LogCategory(const char *name)\n> >         Logger::instance()->registerCategory(this);\n> >  }\n> >\n> > -LogCategory::~LogCategory()\n> > -{\n> > -       Logger::instance()->unregisterCategory(this);\n> > -}\n> > -\n> >  /**\n> >   * \\fn LogCategory::name()\n> >   * \\brief Retrieve the log category name\n> > @@ -746,12 +736,12 @@ void LogCategory::setSeverity(LogSeverity severity)\n> >   * The default log category is named \"default\" and is used by the LOG() macro\n> >   * when no log category is specified.\n> >   *\n> > - * \\return A pointer to the default log category\n> > + * \\return A reference to the default log category\n> >   */\n> >  const LogCategory &LogCategory::defaultCategory()\n> >  {\n> > -       static const LogCategory category(\"default\");\n> > -       return category;\n> > +       static const LogCategory *category = new LogCategory(\"default\");\n> > +       return *category;\n> >  }\n> >\n> >  /**","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8993BC3200\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 24 May 2021 12:26:44 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 046456891C;\n\tMon, 24 May 2021 14:26:44 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 056C1601AA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 24 May 2021 14:26:42 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6FBA8ED;\n\tMon, 24 May 2021 14:26:41 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"pNc2AvC6\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1621859201;\n\tbh=0Qhmq5SCw5aGshYkVl9OLxo9JQlc9ia8vm+DOUp7Jo0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=pNc2AvC6I8xRa+V5E3sGI2nKv9Y4IUzTcv+9jfxo1K1rPoASLNa/Zenmq/KoKQYYW\n\tF/aiUxyHgQrJEMUsXrV7OdLFCfUPYz0nesiHY/9Ps0wxCRsqctPvttI122EiZ9wk/y\n\t5VwkbgSnAWKCbOGPmHgFvqv6G/+c8lCk1WFvAPmA=","Date":"Mon, 24 May 2021 15:26:38 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Hirokazu Honda <hiroh@chromium.org>","Message-ID":"<YKubfnMd5XFNhAVP@pendragon.ideasonboard.com>","References":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>\n\t<CAO5uPHPAZ-TMQV0N6A3VYiVicn4KXeK4RgWhqomyD_QOA04m8w@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<CAO5uPHPAZ-TMQV0N6A3VYiVicn4KXeK4RgWhqomyD_QOA04m8w@mail.gmail.com>","Subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17506,"web_url":"https://patchwork.libcamera.org/comment/17506/","msgid":"<d09ff6dd-a123-d6b3-12ee-b777ecdd56ff@ideasonboard.com>","date":"2021-06-10T08:34:57","subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 23/05/2021 01:04, Laurent Pinchart wrote:\n> The LogCategory instances are constructed on first use as static\n> variables in accessor functions, following the Meyers singleton pattern.\n> As a result, their destruction order is not guaranteed. This can cause\n> issues as the global Logger object, constructed in a similar fashion, is\n> accessed from the LogCategory destructor and may be destroyed first.\n> \n> To fix this, keep the same singleton pattern, but allocate the\n> LogCategory instances dynamically. As they get registered with the\n> global Logger instance, we can destroy them in the Logger destructor.\n> \n> This only avoids destruction order issues between LogCategory and\n> Logger, and doesn't address yet the fact that LOG() calls from\n> destructors of global objects may access an already destroyed Logger.\n\nAre log categories now the only dynamic thing that could be referenced\nafter the destructor is called?\n\nThis may be well into the direction of hack-on-hack - but as the\nLogger->instance() is static - we know it has a defined region of memory\n- so even after the destructor is called - it is still 'there' (It can't\nbe freed).\n\nSo - when the destructor is called - the LogCategories are now removed -\nbut perhaps that's ok - at that point, we can disable all filtering -\nand any log message that occurs after 'destructor' could be written to\nstd-out - perhaps with some 'emergency' / 'destruct' constant category.\n\n\nAnyway, that's all musings on how to consider the next issues.\n\nIf this helps prevent crashes, then it's worthwhile on it's own.\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nAlthough - now thinking further - Is the crash that can occur because a\nLog is reported with a LogCategory that has been unregistered?\n\nAnd if we can detect that, can we apply the same logic and report the\nlog output as an always print, 'Emergency' or 'Shutdown' category?\n\nIn otherwords, if we can detect the parts we can't access - we should\nstill be able to print the log message without crashing ...\n\n\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/internal/log.h |  5 ++---\n>  src/libcamera/log.cpp            | 32 +++++++++++---------------------\n>  2 files changed, 13 insertions(+), 24 deletions(-)\n> \n> diff --git a/include/libcamera/internal/log.h b/include/libcamera/internal/log.h\n> index b66bf55bc57d..1032bdd93e7c 100644\n> --- a/include/libcamera/internal/log.h\n> +++ b/include/libcamera/internal/log.h\n> @@ -29,7 +29,6 @@ class LogCategory\n>  {\n>  public:\n>  \texplicit LogCategory(const char *name);\n> -\t~LogCategory();\n>  \n>  \tconst char *name() const { return name_; }\n>  \tLogSeverity severity() const { return severity_; }\n> @@ -48,8 +47,8 @@ extern const LogCategory &_LOG_CATEGORY(name)();\n>  #define LOG_DEFINE_CATEGORY(name)\t\t\t\t\t\\\n>  const LogCategory &_LOG_CATEGORY(name)()\t\t\t\t\\\n>  {\t\t\t\t\t\t\t\t\t\\\n> -\tstatic LogCategory category(#name);\t\t\t\t\\\n> -\treturn category;\t\t\t\t\t\t\\\n> +\tstatic LogCategory *category = new LogCategory(#name);\t\t\\\n> +\treturn *category;\t\t\t\t\t\t\\\n>  }\n>  \n>  class LogMessage\n> diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\n> index dd991647b9bc..74829a56916e 100644\n> --- a/src/libcamera/log.cpp\n> +++ b/src/libcamera/log.cpp\n> @@ -248,6 +248,8 @@ void LogOutput::writeStream(const std::string &str)\n>  class Logger\n>  {\n>  public:\n> +\t~Logger();\n> +\n>  \tstatic Logger *instance();\n>  \n>  \tvoid write(const LogMessage &msg);\n> @@ -267,7 +269,6 @@ private:\n>  \n>  \tfriend LogCategory;\n>  \tvoid registerCategory(LogCategory *category);\n> -\tvoid unregisterCategory(LogCategory *category);\n>  \n>  \tstd::unordered_set<LogCategory *> categories_;\n>  \tstd::list<std::pair<std::string, LogSeverity>> levels_;\n> @@ -369,6 +370,12 @@ void logSetLevel(const char *category, const char *level)\n>  \tLogger::instance()->logSetLevel(category, level);\n>  }\n>  \n> +Logger::~Logger()\n> +{\n> +\tfor (LogCategory *category : categories_)\n> +\t\tdelete category;\n> +}\n> +\n>  /**\n>   * \\brief Retrieve the logger instance\n>   *\n> @@ -665,18 +672,6 @@ void Logger::registerCategory(LogCategory *category)\n>  \t}\n>  }\n>  \n> -/**\n> - * \\brief Unregister a log category from the logger\n> - * \\param[in] category The log category\n> - *\n> - * If the \\a category hasn't been registered with the logger this function\n> - * performs no operation.\n> - */\n> -void Logger::unregisterCategory(LogCategory *category)\n> -{\n> -\tcategories_.erase(category);\n> -}\n> -\n>  /**\n>   * \\enum LogSeverity\n>   * Log message severity\n> @@ -711,11 +706,6 @@ LogCategory::LogCategory(const char *name)\n>  \tLogger::instance()->registerCategory(this);\n>  }\n>  \n> -LogCategory::~LogCategory()\n> -{\n> -\tLogger::instance()->unregisterCategory(this);\n> -}\n> -\n>  /**\n>   * \\fn LogCategory::name()\n>   * \\brief Retrieve the log category name\n> @@ -746,12 +736,12 @@ void LogCategory::setSeverity(LogSeverity severity)\n>   * The default log category is named \"default\" and is used by the LOG() macro\n>   * when no log category is specified.\n>   *\n> - * \\return A pointer to the default log category\n> + * \\return A reference to the default log category\n>   */\n>  const LogCategory &LogCategory::defaultCategory()\n>  {\n> -\tstatic const LogCategory category(\"default\");\n> -\treturn category;\n> +\tstatic const LogCategory *category = new LogCategory(\"default\");\n> +\treturn *category;\n>  }\n>  \n>  /**\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 21077C320B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 10 Jun 2021 08:35:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4EB5768931;\n\tThu, 10 Jun 2021 10:35:01 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 242136892B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 10 Jun 2021 10:35:00 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 9DCDC436;\n\tThu, 10 Jun 2021 10:34:59 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"hAlZe7Cr\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1623314099;\n\tbh=qUVdszcqlVnLEWsIjsqjZr0fXmVd1+16c4Ty8uWcMHo=;\n\th=Reply-To:To:References:From:Subject:Date:In-Reply-To:From;\n\tb=hAlZe7Cr/CBGXdvoj/K/TTCeeUfGijJQr7uAXrLmcuI6fzaneIhNGN2fhwVDEXPXI\n\t0oQ8PLVQlgEPCEbnclzow/s18U/oae3fUtgtPLE+NmY9ND3QBFPtE5pw5NkKRqbPJU\n\t18A5w6xJiy5DWY1mh9iCP1++6bmcpPxdNBTY+X1w=","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Organization":"Ideas on Board","Message-ID":"<d09ff6dd-a123-d6b3-12ee-b777ecdd56ff@ideasonboard.com>","Date":"Thu, 10 Jun 2021 09:34:57 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101\n\tThunderbird/78.8.1","MIME-Version":"1.0","In-Reply-To":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Reply-To":"kieran.bingham@ideasonboard.com","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17560,"web_url":"https://patchwork.libcamera.org/comment/17560/","msgid":"<YMhzZzDTXNPhbjkm@pendragon.ideasonboard.com>","date":"2021-06-15T09:31:19","subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Thu, Jun 10, 2021 at 09:34:57AM +0100, Kieran Bingham wrote:\n> On 23/05/2021 01:04, Laurent Pinchart wrote:\n> > The LogCategory instances are constructed on first use as static\n> > variables in accessor functions, following the Meyers singleton pattern.\n> > As a result, their destruction order is not guaranteed. This can cause\n> > issues as the global Logger object, constructed in a similar fashion, is\n> > accessed from the LogCategory destructor and may be destroyed first.\n> > \n> > To fix this, keep the same singleton pattern, but allocate the\n> > LogCategory instances dynamically. As they get registered with the\n> > global Logger instance, we can destroy them in the Logger destructor.\n> > \n> > This only avoids destruction order issues between LogCategory and\n> > Logger, and doesn't address yet the fact that LOG() calls from\n> > destructors of global objects may access an already destroyed Logger.\n> \n> Are log categories now the only dynamic thing that could be referenced\n> after the destructor is called?\n\nI'm not sure to understand your question here. Both the Logger and the\ncategory can still be referenced after being destroyed, if that's what\nyou're asking.\n\n> This may be well into the direction of hack-on-hack - but as the\n> Logger->instance() is static - we know it has a defined region of memory\n> - so even after the destructor is called - it is still 'there' (It can't\n> be freed).\n> \n> So - when the destructor is called - the LogCategories are now removed -\n> but perhaps that's ok - at that point, we can disable all filtering -\n> and any log message that occurs after 'destructor' could be written to\n> std-out - perhaps with some 'emergency' / 'destruct' constant category.\n\nThat's an interesting idea. I fear rabbit holes though :-)\n\n> Anyway, that's all musings on how to consider the next issues.\n> \n> If this helps prevent crashes, then it's worthwhile on it's own.\n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> Although - now thinking further - Is the crash that can occur because a\n> Log is reported with a LogCategory that has been unregistered?\n> \n> And if we can detect that, can we apply the same logic and report the\n> log output as an always print, 'Emergency' or 'Shutdown' category?\n> \n> In otherwords, if we can detect the parts we can't access - we should\n> still be able to print the log message without crashing ...\n\nWe won't be able to process log levels, which means that we'd have to\ndecide at compile time the minimum level that gets printed for those\nmessages. Coupled with the fact that an application may direct the log\nto a file because it wants to use stdout and/or stderr for its own\npurposes (I'm thinking about a machine-readable output), this may become\nannoying.\n\nWhat could possibly be done is dropping those messages instead of\ncrashing, or possibly assert()ing in a controlled way.\n\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  include/libcamera/internal/log.h |  5 ++---\n> >  src/libcamera/log.cpp            | 32 +++++++++++---------------------\n> >  2 files changed, 13 insertions(+), 24 deletions(-)\n> > \n> > diff --git a/include/libcamera/internal/log.h b/include/libcamera/internal/log.h\n> > index b66bf55bc57d..1032bdd93e7c 100644\n> > --- a/include/libcamera/internal/log.h\n> > +++ b/include/libcamera/internal/log.h\n> > @@ -29,7 +29,6 @@ class LogCategory\n> >  {\n> >  public:\n> >  \texplicit LogCategory(const char *name);\n> > -\t~LogCategory();\n> >  \n> >  \tconst char *name() const { return name_; }\n> >  \tLogSeverity severity() const { return severity_; }\n> > @@ -48,8 +47,8 @@ extern const LogCategory &_LOG_CATEGORY(name)();\n> >  #define LOG_DEFINE_CATEGORY(name)\t\t\t\t\t\\\n> >  const LogCategory &_LOG_CATEGORY(name)()\t\t\t\t\\\n> >  {\t\t\t\t\t\t\t\t\t\\\n> > -\tstatic LogCategory category(#name);\t\t\t\t\\\n> > -\treturn category;\t\t\t\t\t\t\\\n> > +\tstatic LogCategory *category = new LogCategory(#name);\t\t\\\n> > +\treturn *category;\t\t\t\t\t\t\\\n> >  }\n> >  \n> >  class LogMessage\n> > diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\n> > index dd991647b9bc..74829a56916e 100644\n> > --- a/src/libcamera/log.cpp\n> > +++ b/src/libcamera/log.cpp\n> > @@ -248,6 +248,8 @@ void LogOutput::writeStream(const std::string &str)\n> >  class Logger\n> >  {\n> >  public:\n> > +\t~Logger();\n> > +\n> >  \tstatic Logger *instance();\n> >  \n> >  \tvoid write(const LogMessage &msg);\n> > @@ -267,7 +269,6 @@ private:\n> >  \n> >  \tfriend LogCategory;\n> >  \tvoid registerCategory(LogCategory *category);\n> > -\tvoid unregisterCategory(LogCategory *category);\n> >  \n> >  \tstd::unordered_set<LogCategory *> categories_;\n> >  \tstd::list<std::pair<std::string, LogSeverity>> levels_;\n> > @@ -369,6 +370,12 @@ void logSetLevel(const char *category, const char *level)\n> >  \tLogger::instance()->logSetLevel(category, level);\n> >  }\n> >  \n> > +Logger::~Logger()\n> > +{\n> > +\tfor (LogCategory *category : categories_)\n> > +\t\tdelete category;\n> > +}\n> > +\n> >  /**\n> >   * \\brief Retrieve the logger instance\n> >   *\n> > @@ -665,18 +672,6 @@ void Logger::registerCategory(LogCategory *category)\n> >  \t}\n> >  }\n> >  \n> > -/**\n> > - * \\brief Unregister a log category from the logger\n> > - * \\param[in] category The log category\n> > - *\n> > - * If the \\a category hasn't been registered with the logger this function\n> > - * performs no operation.\n> > - */\n> > -void Logger::unregisterCategory(LogCategory *category)\n> > -{\n> > -\tcategories_.erase(category);\n> > -}\n> > -\n> >  /**\n> >   * \\enum LogSeverity\n> >   * Log message severity\n> > @@ -711,11 +706,6 @@ LogCategory::LogCategory(const char *name)\n> >  \tLogger::instance()->registerCategory(this);\n> >  }\n> >  \n> > -LogCategory::~LogCategory()\n> > -{\n> > -\tLogger::instance()->unregisterCategory(this);\n> > -}\n> > -\n> >  /**\n> >   * \\fn LogCategory::name()\n> >   * \\brief Retrieve the log category name\n> > @@ -746,12 +736,12 @@ void LogCategory::setSeverity(LogSeverity severity)\n> >   * The default log category is named \"default\" and is used by the LOG() macro\n> >   * when no log category is specified.\n> >   *\n> > - * \\return A pointer to the default log category\n> > + * \\return A reference to the default log category\n> >   */\n> >  const LogCategory &LogCategory::defaultCategory()\n> >  {\n> > -\tstatic const LogCategory category(\"default\");\n> > -\treturn category;\n> > +\tstatic const LogCategory *category = new LogCategory(\"default\");\n> > +\treturn *category;\n> >  }\n> >  \n> >  /**","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 5E08EC3218\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 15 Jun 2021 09:31:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B32E768947;\n\tTue, 15 Jun 2021 11:31:42 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 947DA60297\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Jun 2021 11:31:40 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 21BD5436;\n\tTue, 15 Jun 2021 11:31:40 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"qWwRjo8d\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1623749500;\n\tbh=5o2J4WPUOoEHDKkg+YtcRNkkrL6pnRhX0kT8QlBYQ2A=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=qWwRjo8dB0kkE7s05G0E3FyS7zcB5pE5Nj/Ssgzi7T2QavjeQnIilE7hLTF6sTysE\n\t73CtA732DlR+MTt0w2kAbbfCca3NZ+b6XQGoC62Pk4iHa5lWKF39CO9JCRqVUqwL6Q\n\tS27USmrPrWQ2I/rDtkfs1+aNbs9xvGhnPT3bZNc0=","Date":"Tue, 15 Jun 2021 12:31:19 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YMhzZzDTXNPhbjkm@pendragon.ideasonboard.com>","References":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>\n\t<d09ff6dd-a123-d6b3-12ee-b777ecdd56ff@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<d09ff6dd-a123-d6b3-12ee-b777ecdd56ff@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17565,"web_url":"https://patchwork.libcamera.org/comment/17565/","msgid":"<83735cc6-36a5-683e-411f-9525c2baa7e7@ideasonboard.com>","date":"2021-06-15T10:14:33","subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 15/06/2021 10:31, Laurent Pinchart wrote:\n> Hi Kieran,\n> \n> On Thu, Jun 10, 2021 at 09:34:57AM +0100, Kieran Bingham wrote:\n>> On 23/05/2021 01:04, Laurent Pinchart wrote:\n>>> The LogCategory instances are constructed on first use as static\n>>> variables in accessor functions, following the Meyers singleton pattern.\n>>> As a result, their destruction order is not guaranteed. This can cause\n>>> issues as the global Logger object, constructed in a similar fashion, is\n>>> accessed from the LogCategory destructor and may be destroyed first.\n>>>\n>>> To fix this, keep the same singleton pattern, but allocate the\n>>> LogCategory instances dynamically. As they get registered with the\n>>> global Logger instance, we can destroy them in the Logger destructor.\n>>>\n>>> This only avoids destruction order issues between LogCategory and\n>>> Logger, and doesn't address yet the fact that LOG() calls from\n>>> destructors of global objects may access an already destroyed Logger.\n>>\n>> Are log categories now the only dynamic thing that could be referenced\n>> after the destructor is called?\n> \n> I'm not sure to understand your question here. Both the Logger and the\n> category can still be referenced after being destroyed, if that's what\n> you're asking.\n\nI think I was asking, of these components which are allocated with\nmalloc/new.\n\n\n>> This may be well into the direction of hack-on-hack - but as the\n>> Logger->instance() is static - we know it has a defined region of memory\n>> - so even after the destructor is called - it is still 'there' (It can't\n>> be freed).\n>>\n>> So - when the destructor is called - the LogCategories are now removed -\n>> but perhaps that's ok - at that point, we can disable all filtering -\n>> and any log message that occurs after 'destructor' could be written to\n>> std-out - perhaps with some 'emergency' / 'destruct' constant category.\n> \n> That's an interesting idea. I fear rabbit holes though :-)\n> \n>> Anyway, that's all musings on how to consider the next issues.\n>>\n>> If this helps prevent crashes, then it's worthwhile on it's own.\n>>\n>> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n>>\n>> Although - now thinking further - Is the crash that can occur because a\n>> Log is reported with a LogCategory that has been unregistered?\n>>\n>> And if we can detect that, can we apply the same logic and report the\n>> log output as an always print, 'Emergency' or 'Shutdown' category?\n>>\n>> In otherwords, if we can detect the parts we can't access - we should\n>> still be able to print the log message without crashing ...\n> \n> We won't be able to process log levels, which means that we'd have to\n> decide at compile time the minimum level that gets printed for those\n> messages. Coupled with the fact that an application may direct the log\n> to a file because it wants to use stdout and/or stderr for its own\n> purposes (I'm thinking about a machine-readable output), this may become\n> annoying.\n> \n> What could possibly be done is dropping those messages instead of\n> crashing, or possibly assert()ing in a controlled way.\n\nI guess you could silently drop them too - I assumed logging them by\ndefault was better than dropping them by default, but as you say above -\nit could be a compile time constant.\n\nThe point would be - make sure we don't fail in a messy way ...\n\nAsserting perhaps might be better - as then it will simply tell someone\nthey need to remove or reconsider that print as it can't be guaranteed\nto output....\n\nWhich sounds better perhaps as then they likely will think about the\nshutdown sequences more...\n\n\n\n>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>> ---\n>>>  include/libcamera/internal/log.h |  5 ++---\n>>>  src/libcamera/log.cpp            | 32 +++++++++++---------------------\n>>>  2 files changed, 13 insertions(+), 24 deletions(-)\n>>>\n>>> diff --git a/include/libcamera/internal/log.h b/include/libcamera/internal/log.h\n>>> index b66bf55bc57d..1032bdd93e7c 100644\n>>> --- a/include/libcamera/internal/log.h\n>>> +++ b/include/libcamera/internal/log.h\n>>> @@ -29,7 +29,6 @@ class LogCategory\n>>>  {\n>>>  public:\n>>>  \texplicit LogCategory(const char *name);\n>>> -\t~LogCategory();\n>>>  \n>>>  \tconst char *name() const { return name_; }\n>>>  \tLogSeverity severity() const { return severity_; }\n>>> @@ -48,8 +47,8 @@ extern const LogCategory &_LOG_CATEGORY(name)();\n>>>  #define LOG_DEFINE_CATEGORY(name)\t\t\t\t\t\\\n>>>  const LogCategory &_LOG_CATEGORY(name)()\t\t\t\t\\\n>>>  {\t\t\t\t\t\t\t\t\t\\\n>>> -\tstatic LogCategory category(#name);\t\t\t\t\\\n>>> -\treturn category;\t\t\t\t\t\t\\\n>>> +\tstatic LogCategory *category = new LogCategory(#name);\t\t\\\n>>> +\treturn *category;\t\t\t\t\t\t\\\n>>>  }\n>>>  \n>>>  class LogMessage\n>>> diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp\n>>> index dd991647b9bc..74829a56916e 100644\n>>> --- a/src/libcamera/log.cpp\n>>> +++ b/src/libcamera/log.cpp\n>>> @@ -248,6 +248,8 @@ void LogOutput::writeStream(const std::string &str)\n>>>  class Logger\n>>>  {\n>>>  public:\n>>> +\t~Logger();\n>>> +\n>>>  \tstatic Logger *instance();\n>>>  \n>>>  \tvoid write(const LogMessage &msg);\n>>> @@ -267,7 +269,6 @@ private:\n>>>  \n>>>  \tfriend LogCategory;\n>>>  \tvoid registerCategory(LogCategory *category);\n>>> -\tvoid unregisterCategory(LogCategory *category);\n>>>  \n>>>  \tstd::unordered_set<LogCategory *> categories_;\n>>>  \tstd::list<std::pair<std::string, LogSeverity>> levels_;\n>>> @@ -369,6 +370,12 @@ void logSetLevel(const char *category, const char *level)\n>>>  \tLogger::instance()->logSetLevel(category, level);\n>>>  }\n>>>  \n>>> +Logger::~Logger()\n>>> +{\n>>> +\tfor (LogCategory *category : categories_)\n>>> +\t\tdelete category;\n>>> +}\n>>> +\n>>>  /**\n>>>   * \\brief Retrieve the logger instance\n>>>   *\n>>> @@ -665,18 +672,6 @@ void Logger::registerCategory(LogCategory *category)\n>>>  \t}\n>>>  }\n>>>  \n>>> -/**\n>>> - * \\brief Unregister a log category from the logger\n>>> - * \\param[in] category The log category\n>>> - *\n>>> - * If the \\a category hasn't been registered with the logger this function\n>>> - * performs no operation.\n>>> - */\n>>> -void Logger::unregisterCategory(LogCategory *category)\n>>> -{\n>>> -\tcategories_.erase(category);\n>>> -}\n>>> -\n>>>  /**\n>>>   * \\enum LogSeverity\n>>>   * Log message severity\n>>> @@ -711,11 +706,6 @@ LogCategory::LogCategory(const char *name)\n>>>  \tLogger::instance()->registerCategory(this);\n>>>  }\n>>>  \n>>> -LogCategory::~LogCategory()\n>>> -{\n>>> -\tLogger::instance()->unregisterCategory(this);\n>>> -}\n>>> -\n>>>  /**\n>>>   * \\fn LogCategory::name()\n>>>   * \\brief Retrieve the log category name\n>>> @@ -746,12 +736,12 @@ void LogCategory::setSeverity(LogSeverity severity)\n>>>   * The default log category is named \"default\" and is used by the LOG() macro\n>>>   * when no log category is specified.\n>>>   *\n>>> - * \\return A pointer to the default log category\n>>> + * \\return A reference to the default log category\n>>>   */\n>>>  const LogCategory &LogCategory::defaultCategory()\n>>>  {\n>>> -\tstatic const LogCategory category(\"default\");\n>>> -\treturn category;\n>>> +\tstatic const LogCategory *category = new LogCategory(\"default\");\n>>> +\treturn *category;\n>>>  }\n>>>  \n>>>  /**\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0A2BEC3218\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 15 Jun 2021 10:14:39 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7DE7B6050D;\n\tTue, 15 Jun 2021 12:14:38 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F11576029D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Jun 2021 12:14:36 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6DF80436;\n\tTue, 15 Jun 2021 12:14:36 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"wIZFBPLY\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1623752076;\n\tbh=6DA8vd+VNaKUHwpqltqKMR8BzkR0+mb8VNGojVz5Fcc=;\n\th=Reply-To:Subject:To:Cc:References:From:Date:In-Reply-To:From;\n\tb=wIZFBPLYq7rVzIZz4sCfAH8jz6ZclTFQ2sj0zOXffA8RW78CEfmEiZXnD9QdFHhap\n\t2+OCI8iFUefW3hjpb4lr23VcEGHxnJI+k0saMgJpnqbc9hIBziSuyHK5R/NDo/I9IV\n\toRy8WdD20s055iray225sNSQ4mF+UHSW8jT/mp9I=","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","References":"<20210523000437.28334-1-laurent.pinchart@ideasonboard.com>\n\t<d09ff6dd-a123-d6b3-12ee-b777ecdd56ff@ideasonboard.com>\n\t<YMhzZzDTXNPhbjkm@pendragon.ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Organization":"Ideas on Board","Message-ID":"<83735cc6-36a5-683e-411f-9525c2baa7e7@ideasonboard.com>","Date":"Tue, 15 Jun 2021 11:14:33 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101\n\tThunderbird/78.8.1","MIME-Version":"1.0","In-Reply-To":"<YMhzZzDTXNPhbjkm@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"7bit","Subject":"Re: [libcamera-devel] [PATCH] libcamera: log: Destroy LogCategory\n\tinstances in a controlled way","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Reply-To":"kieran.bingham@ideasonboard.com","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]