[libcamera-devel] pipeline: rpi: always initialize the embedded buffer in tryRunPipeline
diff mbox series

Message ID 20240120211508.14742-1-mail@eliasnaur.com
State New
Headers show
Series
  • [libcamera-devel] pipeline: rpi: always initialize the embedded buffer in tryRunPipeline
Related show

Commit Message

Elias Naur Jan. 20, 2024, 9:14 p.m. UTC
Vc4CameraData::findMatchBuffers may return successfully without setting
the embedded buffer. Make sure to initialize the buffer and id to avoid
accessing garbage data.

Without this change, libcamera v0.2.0 usually crashes with an assertion
error:

 ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()

Signed-off-by: Elias Naur <mail@eliasnaur.com>
---
 src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Laurent Pinchart Jan. 21, 2024, 4:07 a.m. UTC | #1
Hi Elias,

Thank you for the patch.

On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via libcamera-devel wrote:
> Vc4CameraData::findMatchBuffers may return successfully without setting
> the embedded buffer. Make sure to initialize the buffer and id to avoid
> accessing garbage data.

How so ? The function starts with

	if (bayerQueue_.empty())
	        return false;

	/*
	 * Find the embedded data buffer with a matching timestamp to pass to
	 * the IPA. Any embedded buffers with a timestamp lower than the
	 * current bayer buffer will be removed and re-queued to the driver.
	 */
	uint64_t ts = bayerQueue_.front().buffer->metadata().timestamp;
	embeddedBuffer = nullptr;

so I don't see how it can leave embeddedBuffer unset if it returns
successfully.

> Without this change, libcamera v0.2.0 usually crashes with an assertion
> error:
> 
>  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()

I've seen this indeed, and will test your patch. Maybe it's due to the
second change, where you set params.buffers.embedded to 0 ?

> Signed-off-by: Elias Naur <mail@eliasnaur.com>
> ---
>  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> index 26102ea7..d76389f3 100644
> --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> @@ -906,7 +906,7 @@ void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
>  
>  void Vc4CameraData::tryRunPipeline()
>  {
> -	FrameBuffer *embeddedBuffer;
> +	FrameBuffer *embeddedBuffer = nullptr;
>  	BayerFrame bayerFrame;
>  
>  	/* If any of our request or buffer queues are empty, we cannot proceed. */
> @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
>  	params.requestControls = request->controls();
>  	params.ipaContext = request->sequence();
>  	params.delayContext = bayerFrame.delayContext;
> +	params.buffers.embedded = 0;
>  
>  	if (embeddedBuffer) {
>  		unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
Elias Naur Jan. 21, 2024, 1:03 p.m. UTC | #2
On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Elias,
>
> Thank you for the patch.
>
> On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via libcamera-devel wrote:
> > Vc4CameraData::findMatchBuffers may return successfully without setting
> > the embedded buffer. Make sure to initialize the buffer and id to avoid
> > accessing garbage data.
>
> How so ? The function starts with
>
>         if (bayerQueue_.empty())
>                 return false;
>
>         /*
>          * Find the embedded data buffer with a matching timestamp to pass to
>          * the IPA. Any embedded buffers with a timestamp lower than the
>          * current bayer buffer will be removed and re-queued to the driver.
>          */
>         uint64_t ts = bayerQueue_.front().buffer->metadata().timestamp;
>         embeddedBuffer = nullptr;
>
> so I don't see how it can leave embeddedBuffer unset if it returns
> successfully.
>
> > Without this change, libcamera v0.2.0 usually crashes with an assertion
> > error:
> >
> >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()
>
> I've seen this indeed, and will test your patch. Maybe it's due to the
> second change, where you set params.buffers.embedded to 0 ?
>

Correct: the fix is the second change; the first change is defensive in case
findMatchBuffers for some reason doesn't set embeddedBuffer in case none
is found.

> > Signed-off-by: Elias Naur <mail@eliasnaur.com>
> > ---
> >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > index 26102ea7..d76389f3 100644
> > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > @@ -906,7 +906,7 @@ void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
> >
> >  void Vc4CameraData::tryRunPipeline()
> >  {
> > -     FrameBuffer *embeddedBuffer;
> > +     FrameBuffer *embeddedBuffer = nullptr;
> >       BayerFrame bayerFrame;
> >
> >       /* If any of our request or buffer queues are empty, we cannot proceed. */
> > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
> >       params.requestControls = request->controls();
> >       params.ipaContext = request->sequence();
> >       params.delayContext = bayerFrame.delayContext;
> > +     params.buffers.embedded = 0;
> >
> >       if (embeddedBuffer) {
> >               unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart Jan. 22, 2024, 7:37 a.m. UTC | #3
Hi Elias,

On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
> On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
> > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via libcamera-devel wrote:
> > > Vc4CameraData::findMatchBuffers may return successfully without setting
> > > the embedded buffer. Make sure to initialize the buffer and id to avoid
> > > accessing garbage data.
> >
> > How so ? The function starts with
> >
> >         if (bayerQueue_.empty())
> >                 return false;
> >
> >         /*
> >          * Find the embedded data buffer with a matching timestamp to pass to
> >          * the IPA. Any embedded buffers with a timestamp lower than the
> >          * current bayer buffer will be removed and re-queued to the driver.
> >          */
> >         uint64_t ts = bayerQueue_.front().buffer->metadata().timestamp;
> >         embeddedBuffer = nullptr;
> >
> > so I don't see how it can leave embeddedBuffer unset if it returns
> > successfully.
> >
> > > Without this change, libcamera v0.2.0 usually crashes with an assertion
> > > error:
> > >
> > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()
> >
> > I've seen this indeed, and will test your patch. Maybe it's due to the
> > second change, where you set params.buffers.embedded to 0 ?
> 
> Correct: the fix is the second change;

Could you please update the commit message to reflect this ? I read it
as indicating that embeddedBuffer could be null, while the issue is that
params.buffers.embedded is not initialized.

> the first change is defensive in case
> findMatchBuffers for some reason doesn't set embeddedBuffer in case none
> is found.

I'm not sure I'd keep that change. I'll let Naush and David decide what
they like best.

> > > Signed-off-by: Elias Naur <mail@eliasnaur.com>
> > > ---
> > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
> > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > index 26102ea7..d76389f3 100644
> > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > @@ -906,7 +906,7 @@ void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
> > >
> > >  void Vc4CameraData::tryRunPipeline()
> > >  {
> > > -     FrameBuffer *embeddedBuffer;
> > > +     FrameBuffer *embeddedBuffer = nullptr;
> > >       BayerFrame bayerFrame;
> > >
> > >       /* If any of our request or buffer queues are empty, we cannot proceed. */
> > > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
> > >       params.requestControls = request->controls();
> > >       params.ipaContext = request->sequence();
> > >       params.delayContext = bayerFrame.delayContext;
> > > +     params.buffers.embedded = 0;
> > >
> > >       if (embeddedBuffer) {
> > >               unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
Naushir Patuck Jan. 22, 2024, 10:18 a.m. UTC | #4
Hi all,


On Mon, 22 Jan 2024 at 07:37, Laurent Pinchart via libcamera-devel <
libcamera-devel@lists.libcamera.org> wrote:
>
> Hi Elias,
>
> On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
> > On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
> > > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via
libcamera-devel wrote:
> > > > Vc4CameraData::findMatchBuffers may return successfully without
setting
> > > > the embedded buffer. Make sure to initialize the buffer and id to
avoid
> > > > accessing garbage data.
> > >
> > > How so ? The function starts with
> > >
> > >         if (bayerQueue_.empty())
> > >                 return false;
> > >
> > >         /*
> > >          * Find the embedded data buffer with a matching timestamp to
pass to
> > >          * the IPA. Any embedded buffers with a timestamp lower than
the
> > >          * current bayer buffer will be removed and re-queued to the
driver.
> > >          */
> > >         uint64_t ts =
bayerQueue_.front().buffer->metadata().timestamp;
> > >         embeddedBuffer = nullptr;
> > >
> > > so I don't see how it can leave embeddedBuffer unset if it returns
> > > successfully.
> > >
> > > > Without this change, libcamera v0.2.0 usually crashes with an
assertion
> > > > error:
> > > >
> > > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in
prepareIsp()
> > >
> > > I've seen this indeed, and will test your patch. Maybe it's due to the
> > > second change, where you set params.buffers.embedded to 0 ?
> >
> > Correct: the fix is the second change;
>
> Could you please update the commit message to reflect this ? I read it
> as indicating that embeddedBuffer could be null, while the issue is that
> params.buffers.embedded is not initialized.
>
> > the first change is defensive in case
> > findMatchBuffers for some reason doesn't set embeddedBuffer in case none
> > is found.
>
> I'm not sure I'd keep that change. I'll let Naush and David decide what
> they like best.

I agree, let's just keep the change to initialising
 params.buffers.embedded.
With this, the change itself looks reasonable so

Reviewed-by: Naushir Patuck <naush@raspberrypi.com>

However... I could have sworn the mojom auto generated class file for
ipa::RPi::PrepareParams would initialize all member variables to 0
(including buffers.embedded) on default construction.  I'm away right now
so I cannot check this myself, but could anybody else check?  I'm somewhat
surprised that this has not been reported more widely...

Thanks,
Naush

>
>
> > > > Signed-off-by: Elias Naur <mail@eliasnaur.com>
> > > > ---
> > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
> > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > index 26102ea7..d76389f3 100644
> > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > @@ -906,7 +906,7 @@ void Vc4CameraData::setCameraTimeout(uint32_t
maxFrameLengthMs)
> > > >
> > > >  void Vc4CameraData::tryRunPipeline()
> > > >  {
> > > > -     FrameBuffer *embeddedBuffer;
> > > > +     FrameBuffer *embeddedBuffer = nullptr;
> > > >       BayerFrame bayerFrame;
> > > >
> > > >       /* If any of our request or buffer queues are empty, we
cannot proceed. */
> > > > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
> > > >       params.requestControls = request->controls();
> > > >       params.ipaContext = request->sequence();
> > > >       params.delayContext = bayerFrame.delayContext;
> > > > +     params.buffers.embedded = 0;
> > > >
> > > >       if (embeddedBuffer) {
> > > >               unsigned int embeddedId =
unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
>
> --
> Regards,
>
> Laurent Pinchart
Laurent Pinchart Jan. 22, 2024, 10:31 a.m. UTC | #5
On Mon, Jan 22, 2024 at 10:18:44AM +0000, Naushir Patuck wrote:
> On Mon, 22 Jan 2024 at 07:37, Laurent Pinchart via libcamera-devel wrote:
> > On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
> > > On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
> > > > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via libcamera-devel wrote:
> > > > > Vc4CameraData::findMatchBuffers may return successfully without setting
> > > > > the embedded buffer. Make sure to initialize the buffer and id to avoid
> > > > > accessing garbage data.
> > > >
> > > > How so ? The function starts with
> > > >
> > > >         if (bayerQueue_.empty())
> > > >                 return false;
> > > >
> > > >         /*
> > > >          * Find the embedded data buffer with a matching timestamp to pass to
> > > >          * the IPA. Any embedded buffers with a timestamp lower than the
> > > >          * current bayer buffer will be removed and re-queued to the driver.
> > > >          */
> > > >         uint64_t ts = bayerQueue_.front().buffer->metadata().timestamp;
> > > >         embeddedBuffer = nullptr;
> > > >
> > > > so I don't see how it can leave embeddedBuffer unset if it returns
> > > > successfully.
> > > >
> > > > > Without this change, libcamera v0.2.0 usually crashes with an assertion
> > > > > error:
> > > > >
> > > > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()
> > > >
> > > > I've seen this indeed, and will test your patch. Maybe it's due to the
> > > > second change, where you set params.buffers.embedded to 0 ?
> > >
> > > Correct: the fix is the second change;
> >
> > Could you please update the commit message to reflect this ? I read it
> > as indicating that embeddedBuffer could be null, while the issue is that
> > params.buffers.embedded is not initialized.
> >
> > > the first change is defensive in case
> > > findMatchBuffers for some reason doesn't set embeddedBuffer in case none
> > > is found.
> >
> > I'm not sure I'd keep that change. I'll let Naush and David decide what
> > they like best.
> 
> I agree, let's just keep the change to initialising  params.buffers.embedded.
> With this, the change itself looks reasonable so
> 
> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>

Elias, would you be able to send a v2 ?

> However... I could have sworn the mojom auto generated class file for
> ipa::RPi::PrepareParams would initialize all member variables to 0 (including
> buffers.embedded) on default construction.  I'm away right now so I cannot
> check this myself, but could anybody else check?  I'm somewhat surprised that
> this has not been reported more widely...

I checked, and the constructor doesn't initialize all fields to 0. I'm
pretty surprised too to be honest.

> > > > > Signed-off-by: Elias Naur <mail@eliasnaur.com>
> > > > > ---
> > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
> > > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > index 26102ea7..d76389f3 100644
> > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > @@ -906,7 +906,7 @@ void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
> > > > >
> > > > >  void Vc4CameraData::tryRunPipeline()
> > > > >  {
> > > > > -     FrameBuffer *embeddedBuffer;
> > > > > +     FrameBuffer *embeddedBuffer = nullptr;
> > > > >       BayerFrame bayerFrame;
> > > > >
> > > > >       /* If any of our request or buffer queues are empty, we cannot proceed. */
> > > > > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
> > > > >       params.requestControls = request->controls();
> > > > >       params.ipaContext = request->sequence();
> > > > >       params.delayContext = bayerFrame.delayContext;
> > > > > +     params.buffers.embedded = 0;
> > > > >
> > > > >       if (embeddedBuffer) {
> > > > >               unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
Elias Naur Jan. 22, 2024, 1:36 p.m. UTC | #6
On Mon, 22 Jan 2024 at 05:31, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Mon, Jan 22, 2024 at 10:18:44AM +0000, Naushir Patuck wrote:
> > On Mon, 22 Jan 2024 at 07:37, Laurent Pinchart via libcamera-devel wrote:
> > > On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
> > > > On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
> > > > > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via libcamera-devel wrote:
> > > > > > Vc4CameraData::findMatchBuffers may return successfully without setting
> > > > > > the embedded buffer. Make sure to initialize the buffer and id to avoid
> > > > > > accessing garbage data.
> > > > >
> > > > > How so ? The function starts with
> > > > >
> > > > >         if (bayerQueue_.empty())
> > > > >                 return false;
> > > > >
> > > > >         /*
> > > > >          * Find the embedded data buffer with a matching timestamp to pass to
> > > > >          * the IPA. Any embedded buffers with a timestamp lower than the
> > > > >          * current bayer buffer will be removed and re-queued to the driver.
> > > > >          */
> > > > >         uint64_t ts = bayerQueue_.front().buffer->metadata().timestamp;
> > > > >         embeddedBuffer = nullptr;
> > > > >
> > > > > so I don't see how it can leave embeddedBuffer unset if it returns
> > > > > successfully.
> > > > >
> > > > > > Without this change, libcamera v0.2.0 usually crashes with an assertion
> > > > > > error:
> > > > > >
> > > > > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in prepareIsp()
> > > > >
> > > > > I've seen this indeed, and will test your patch. Maybe it's due to the
> > > > > second change, where you set params.buffers.embedded to 0 ?
> > > >
> > > > Correct: the fix is the second change;
> > >
> > > Could you please update the commit message to reflect this ? I read it
> > > as indicating that embeddedBuffer could be null, while the issue is that
> > > params.buffers.embedded is not initialized.
> > >
> > > > the first change is defensive in case
> > > > findMatchBuffers for some reason doesn't set embeddedBuffer in case none
> > > > is found.
> > >
> > > I'm not sure I'd keep that change. I'll let Naush and David decide what
> > > they like best.
> >

I don't like uninitialized values in general, but I suppose fixing
those is better done
by, say, compiler flags.

> > I agree, let's just keep the change to initialising  params.buffers.embedded.
> > With this, the change itself looks reasonable so
> >
> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
>
> Elias, would you be able to send a v2 ?
>

Done.

Elias
Naushir Patuck Jan. 24, 2024, 9:17 a.m. UTC | #7
On Mon, 22 Jan 2024 at 10:31, Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> On Mon, Jan 22, 2024 at 10:18:44AM +0000, Naushir Patuck wrote:
> > On Mon, 22 Jan 2024 at 07:37, Laurent Pinchart via libcamera-devel wrote:
> > > On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
> > > > On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
> > > > > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via
> libcamera-devel wrote:
> > > > > > Vc4CameraData::findMatchBuffers may return successfully without
> setting
> > > > > > the embedded buffer. Make sure to initialize the buffer and id
> to avoid
> > > > > > accessing garbage data.
> > > > >
> > > > > How so ? The function starts with
> > > > >
> > > > >         if (bayerQueue_.empty())
> > > > >                 return false;
> > > > >
> > > > >         /*
> > > > >          * Find the embedded data buffer with a matching timestamp
> to pass to
> > > > >          * the IPA. Any embedded buffers with a timestamp lower
> than the
> > > > >          * current bayer buffer will be removed and re-queued to
> the driver.
> > > > >          */
> > > > >         uint64_t ts =
> bayerQueue_.front().buffer->metadata().timestamp;
> > > > >         embeddedBuffer = nullptr;
> > > > >
> > > > > so I don't see how it can leave embeddedBuffer unset if it returns
> > > > > successfully.
> > > > >
> > > > > > Without this change, libcamera v0.2.0 usually crashes with an
> assertion
> > > > > > error:
> > > > > >
> > > > > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in
> prepareIsp()
> > > > >
> > > > > I've seen this indeed, and will test your patch. Maybe it's due to
> the
> > > > > second change, where you set params.buffers.embedded to 0 ?
> > > >
> > > > Correct: the fix is the second change;
> > >
> > > Could you please update the commit message to reflect this ? I read it
> > > as indicating that embeddedBuffer could be null, while the issue is
> that
> > > params.buffers.embedded is not initialized.
> > >
> > > > the first change is defensive in case
> > > > findMatchBuffers for some reason doesn't set embeddedBuffer in case
> none
> > > > is found.
> > >
> > > I'm not sure I'd keep that change. I'll let Naush and David decide what
> > > they like best.
> >
> > I agree, let's just keep the change to initialising
>  params.buffers.embedded.
> > With this, the change itself looks reasonable so
> >
> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
>
> Elias, would you be able to send a v2 ?
>
> > However... I could have sworn the mojom auto generated class file for
> > ipa::RPi::PrepareParams would initialize all member variables to 0
> (including
> > buffers.embedded) on default construction.  I'm away right now so I
> cannot
> > check this myself, but could anybody else check?  I'm somewhat surprised
> that
> > this has not been reported more widely...
>
> I checked, and the constructor doesn't initialize all fields to 0. I'm
> pretty surprised too to be honest.
>

Curiosity got the better of me.  In the
https://git.libcamera.org/libcamera/libcamera.git/ build tree,
the following bit of code gets generated in raspberrpyi_ipa_interface.h:

---
struct BufferIds
{
public:
#ifndef __DOXYGEN__
    BufferIds()
    {
    }

    BufferIds(uint32_t _bayer, uint32_t _embedded, uint32_t _stats)
        : bayer(_bayer), embedded(_embedded), stats(_stats)
    {
    }
#endif

    uint32_t bayer;
    uint32_t embedded;
    uint32_t stats;
};
---

However, building from https://github.com/raspberrypi/libcamera/ generates
the following:

---
struct BufferIds
{
public:
#ifndef __DOXYGEN__
    BufferIds()
        : bayer(0), embedded(0), stats(0)
    {
    }

    BufferIds(uint32_t _bayer, uint32_t _embedded, uint32_t _stats)
        : bayer(_bayer), embedded(_embedded), stats(_stats)
    {
    }
#endif

    uint32_t bayer;
    uint32_t embedded;
    uint32_t stats;
};
---

So at some point in time, the fields were explicitly initialised to 0 and
things were working as expected.  The RPi tree definitely does not have any
changes to the mojom generation code, so I can't say what caused this
change, but it should hopefully be easy enough to bisect and find the root
case.

Regards,
Naush




>
> > > > > > Signed-off-by: Elias Naur <mail@eliasnaur.com>
> > > > > > ---
> > > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
> > > > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > > index 26102ea7..d76389f3 100644
> > > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
> > > > > > @@ -906,7 +906,7 @@ void
> Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
> > > > > >
> > > > > >  void Vc4CameraData::tryRunPipeline()
> > > > > >  {
> > > > > > -     FrameBuffer *embeddedBuffer;
> > > > > > +     FrameBuffer *embeddedBuffer = nullptr;
> > > > > >       BayerFrame bayerFrame;
> > > > > >
> > > > > >       /* If any of our request or buffer queues are empty, we
> cannot proceed. */
> > > > > > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
> > > > > >       params.requestControls = request->controls();
> > > > > >       params.ipaContext = request->sequence();
> > > > > >       params.delayContext = bayerFrame.delayContext;
> > > > > > +     params.buffers.embedded = 0;
> > > > > >
> > > > > >       if (embeddedBuffer) {
> > > > > >               unsigned int embeddedId =
> unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
>
> --
> Regards,
>
> Laurent Pinchart
>
Naushir Patuck Jan. 24, 2024, 9:32 a.m. UTC | #8
On Wed, 24 Jan 2024 at 09:17, Naushir Patuck <naush@raspberrypi.com> wrote:

>
>
> On Mon, 22 Jan 2024 at 10:31, Laurent Pinchart <
> laurent.pinchart@ideasonboard.com> wrote:
>
>> On Mon, Jan 22, 2024 at 10:18:44AM +0000, Naushir Patuck wrote:
>> > On Mon, 22 Jan 2024 at 07:37, Laurent Pinchart via libcamera-devel
>> wrote:
>> > > On Sun, Jan 21, 2024 at 08:03:49AM -0500, Elias Naur wrote:
>> > > > On Sat, 20 Jan 2024 at 23:07, Laurent Pinchart wrote:
>> > > > > On Sat, Jan 20, 2024 at 04:14:49PM -0500, Elias Naur via
>> libcamera-devel wrote:
>> > > > > > Vc4CameraData::findMatchBuffers may return successfully without
>> setting
>> > > > > > the embedded buffer. Make sure to initialize the buffer and id
>> to avoid
>> > > > > > accessing garbage data.
>> > > > >
>> > > > > How so ? The function starts with
>> > > > >
>> > > > >         if (bayerQueue_.empty())
>> > > > >                 return false;
>> > > > >
>> > > > >         /*
>> > > > >          * Find the embedded data buffer with a matching
>> timestamp to pass to
>> > > > >          * the IPA. Any embedded buffers with a timestamp lower
>> than the
>> > > > >          * current bayer buffer will be removed and re-queued to
>> the driver.
>> > > > >          */
>> > > > >         uint64_t ts =
>> bayerQueue_.front().buffer->metadata().timestamp;
>> > > > >         embeddedBuffer = nullptr;
>> > > > >
>> > > > > so I don't see how it can leave embeddedBuffer unset if it returns
>> > > > > successfully.
>> > > > >
>> > > > > > Without this change, libcamera v0.2.0 usually crashes with an
>> assertion
>> > > > > > error:
>> > > > > >
>> > > > > >  ipa_base.cpp:397 assertion "it != buffers_.end()" failed in
>> prepareIsp()
>> > > > >
>> > > > > I've seen this indeed, and will test your patch. Maybe it's due
>> to the
>> > > > > second change, where you set params.buffers.embedded to 0 ?
>> > > >
>> > > > Correct: the fix is the second change;
>> > >
>> > > Could you please update the commit message to reflect this ? I read it
>> > > as indicating that embeddedBuffer could be null, while the issue is
>> that
>> > > params.buffers.embedded is not initialized.
>> > >
>> > > > the first change is defensive in case
>> > > > findMatchBuffers for some reason doesn't set embeddedBuffer in case
>> none
>> > > > is found.
>> > >
>> > > I'm not sure I'd keep that change. I'll let Naush and David decide
>> what
>> > > they like best.
>> >
>> > I agree, let's just keep the change to initialising
>>  params.buffers.embedded.
>> > With this, the change itself looks reasonable so
>> >
>> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
>>
>> Elias, would you be able to send a v2 ?
>>
>> > However... I could have sworn the mojom auto generated class file for
>> > ipa::RPi::PrepareParams would initialize all member variables to 0
>> (including
>> > buffers.embedded) on default construction.  I'm away right now so I
>> cannot
>> > check this myself, but could anybody else check?  I'm somewhat
>> surprised that
>> > this has not been reported more widely...
>>
>> I checked, and the constructor doesn't initialize all fields to 0. I'm
>> pretty surprised too to be honest.
>>
>
> Curiosity got the better of me.  In the
> https://git.libcamera.org/libcamera/libcamera.git/ build tree,
> the following bit of code gets generated in raspberrpyi_ipa_interface.h:
>
> ---
> struct BufferIds
> {
> public:
> #ifndef __DOXYGEN__
>     BufferIds()
>     {
>     }
>
>     BufferIds(uint32_t _bayer, uint32_t _embedded, uint32_t _stats)
>         : bayer(_bayer), embedded(_embedded), stats(_stats)
>     {
>     }
> #endif
>
>     uint32_t bayer;
>     uint32_t embedded;
>     uint32_t stats;
> };
> ---
>
> However, building from https://github.com/raspberrypi/libcamera/
> generates the following:
>
> ---
> struct BufferIds
> {
> public:
> #ifndef __DOXYGEN__
>     BufferIds()
>         : bayer(0), embedded(0), stats(0)
>     {
>     }
>
>     BufferIds(uint32_t _bayer, uint32_t _embedded, uint32_t _stats)
>         : bayer(_bayer), embedded(_embedded), stats(_stats)
>     {
>     }
> #endif
>
>     uint32_t bayer;
>     uint32_t embedded;
>     uint32_t stats;
> };
> ---
>
> So at some point in time, the fields were explicitly initialised to 0 and
> things were working as expected.  The RPi tree definitely does not have any
> changes to the mojom generation code, so I can't say what caused this
> change, but it should hopefully be easy enough to bisect and find the root
> case.
>

And that points to the commit:

commit d17de86904f03f1d5a4d5d20af518e70c4758969
Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Date:   Thu Jan 4 17:15:48 2024 +0200

    utils: ipc: Update mojo

    Update mojo from commit

    9be4263648d7d1a04bb78be75df53f56449a5e3a "Updating trunk VERSION from
6225.0 to 6226.0"

    from the Chromium repository.

    The update-mojo.sh script was used for this update.

    Bug: https://bugs.libcamera.org/show_bug.cgi?id=206
    Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
    Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
    Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>



>
> Regards,
> Naush
>
>
>
>
>>
>> > > > > > Signed-off-by: Elias Naur <mail@eliasnaur.com>
>> > > > > > ---
>> > > > > >  src/libcamera/pipeline/rpi/vc4/vc4.cpp | 3 ++-
>> > > > > >  1 file changed, 2 insertions(+), 1 deletion(-)
>> > > > > >
>> > > > > > diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
>> b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
>> > > > > > index 26102ea7..d76389f3 100644
>> > > > > > --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
>> > > > > > +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
>> > > > > > @@ -906,7 +906,7 @@ void
>> Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
>> > > > > >
>> > > > > >  void Vc4CameraData::tryRunPipeline()
>> > > > > >  {
>> > > > > > -     FrameBuffer *embeddedBuffer;
>> > > > > > +     FrameBuffer *embeddedBuffer = nullptr;
>> > > > > >       BayerFrame bayerFrame;
>> > > > > >
>> > > > > >       /* If any of our request or buffer queues are empty, we
>> cannot proceed. */
>> > > > > > @@ -945,6 +945,7 @@ void Vc4CameraData::tryRunPipeline()
>> > > > > >       params.requestControls = request->controls();
>> > > > > >       params.ipaContext = request->sequence();
>> > > > > >       params.delayContext = bayerFrame.delayContext;
>> > > > > > +     params.buffers.embedded = 0;
>> > > > > >
>> > > > > >       if (embeddedBuffer) {
>> > > > > >               unsigned int embeddedId =
>> unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
>>
>

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
index 26102ea7..d76389f3 100644
--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp
+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp
@@ -906,7 +906,7 @@  void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs)
 
 void Vc4CameraData::tryRunPipeline()
 {
-	FrameBuffer *embeddedBuffer;
+	FrameBuffer *embeddedBuffer = nullptr;
 	BayerFrame bayerFrame;
 
 	/* If any of our request or buffer queues are empty, we cannot proceed. */
@@ -945,6 +945,7 @@  void Vc4CameraData::tryRunPipeline()
 	params.requestControls = request->controls();
 	params.ipaContext = request->sequence();
 	params.delayContext = bayerFrame.delayContext;
+	params.buffers.embedded = 0;
 
 	if (embeddedBuffer) {
 		unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);