Re: [PATCH] Fix undefined behaviour

Klaus Schmidinger <[email protected]> Mon, 5 Dec 2022 16:08:45 +0100
Newsgroups gmane.linux.vdr
Message-ID <[email protected]>
On 04.12.22 13:19, Marko Mäkelä wrote:
> ...
> 0001-Fix-GCC-8.3.0-fsanitize-undefined.patch
> 
>>From b69ff7105d4bb8d933f0214f34b103fda8e8b155 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= <[email protected]>
> Date: Sun, 4 Dec 2022 13:42:57 +0200
> Subject: [PATCH] Fix GCC 8.3.0 -fsanitize=undefined
> 
> ...
> device.c:251:31: runtime error: variable length array bound evaluates to non-positive value 0
> ...
> diff --git a/device.c b/device.c
> index 4e987389..a770aa90 100644
> --- a/device.c
> +++ b/device.c
> @@ -248,7 +248,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
>   {
>     // Collect the current priorities of all CAM slots that can decrypt the channel:
>     int NumCamSlots = CamSlots.Count();
> -  int SlotPriority[NumCamSlots];
> +  int SlotPriority[std::max(NumCamSlots, 1)];
>     int NumUsableSlots = 0;
>     bool InternalCamNeeded = false;
>     if (Channel->Ca() >= CA_ENCRYPTED_MIN) {

If NumCamSlots is 0, SlotPriority[] is never accessed.
So why allocate memory for it if it is never used?

> dvbplayer.c:984:11: runtime error: member access within address 0x02a388d0 which does not point to an object of type 'cDvbPlayerControl'
> ...
> diff --git a/dvbplayer.c b/dvbplayer.c
> index 2ee846b6..72bc46ad 100644
> --- a/dvbplayer.c
> +++ b/dvbplayer.c
> @@ -981,8 +981,9 @@ bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
>   // --- cDvbPlayerControl -----------------------------------------------------
>   
>   cDvbPlayerControl::cDvbPlayerControl(const char *FileName, bool PauseLive)
> -:cControl(player = new cDvbPlayer(FileName, PauseLive))
> +:cControl(new cDvbPlayer(FileName, PauseLive))
>   {
> +  player = static_cast<cDvbPlayer*>(cControl::player);
>   }
>   
>   cDvbPlayerControl::~cDvbPlayerControl()
> ...
> transfer.c:71:11: runtime error: member access within address 0x020f0428 which does not point to an object of type 'cTransferControl'
> diff --git a/transfer.c b/transfer.c
> index 88931e58..b888910a 100644
> --- a/transfer.c
> +++ b/transfer.c
> @@ -68,8 +68,9 @@ void cTransfer::Receive(const uchar *Data, int Length)
>   cDevice *cTransferControl::receiverDevice = NULL;
>   
>   cTransferControl::cTransferControl(cDevice *ReceiverDevice, const cChannel *Channel)
> -:cControl(transfer = new cTransfer(Channel), true)
> +:cControl(new cTransfer(Channel), true)
>   {
> +  transfer = static_cast<cTransfer*>(player);
>     ReceiverDevice->AttachReceiver(transfer);
>     receiverDevice = ReceiverDevice;
>   }

Instead if typecasting I guess I'll rather do it this way:

--- ./dvbplayer.c       2022/01/13 21:41:41     5.1
+++ ./dvbplayer.c       2022/12/05 14:29:50
@@ -981,8 +981,10 @@
  // --- cDvbPlayerControl -----------------------------------------------------

  cDvbPlayerControl::cDvbPlayerControl(const char *FileName, bool PauseLive)
-:cControl(player = new cDvbPlayer(FileName, PauseLive))
+:cControl(NULL, PauseLive)
  {
+  player = new cDvbPlayer(FileName, PauseLive);
+  SetPlayer(player);
  }

  cDvbPlayerControl::~cDvbPlayerControl()
--- ./player.h  2020/05/18 16:47:29     5.0
+++ ./player.h  2022/12/05 14:30:24
@@ -107,6 +107,7 @@
           ///< Deletion of the marks themselves is handled separately, calling
           ///< this function merely tells the player to no longer display the
           ///< marks, if it has any.
+  void SetPlayer(cPlayer *Player) { player = Player; }
    double FramesPerSecond(void) const { return player ? player->FramesPerSecond() : DEFAULTFRAMESPERSECOND; }
    bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) const { return player ? player->GetIndex(Current, Total, SnapToIFrame) : false; }
    bool GetFrameNumber(int &Current, int &Total) const { return player ? player->GetFrameNumber(Current, Total) : false; }
--- ./transfer.c        2017/12/07 15:00:33     5.0
+++ ./transfer.c        2022/12/05 14:36:39
@@ -68,8 +68,10 @@
  cDevice *cTransferControl::receiverDevice = NULL;

  cTransferControl::cTransferControl(cDevice *ReceiverDevice, const cChannel *Channel)
-:cControl(transfer = new cTransfer(Channel), true)
+:cControl(NULL, true)
  {
+  transfer = new cTransfer(Channel);
+  SetPlayer(transfer);
    ReceiverDevice->AttachReceiver(transfer);
    receiverDevice = ReceiverDevice;
  }

> diff --git a/font.c b/font.c
> index 8b37798c..c78b1a15 100644
> --- a/font.c
> +++ b/font.c
> @@ -74,7 +74,8 @@ cGlyph::cGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData)
>     rows = GlyphData->bitmap.rows;
>     pitch = GlyphData->bitmap.pitch;
>     bitmap = MALLOC(uchar, rows * pitch);
> -  memcpy(bitmap, GlyphData->bitmap.buffer, rows * pitch);
> +  if (int bytes = rows * pitch)
> +    memcpy(bitmap, GlyphData->bitmap.buffer, bytes);
>   }
>   
>   cGlyph::~cGlyph()

If (rows * pitch) is 0, nothing is copied.
Why the extra check?

> osd.h:301:37: runtime error: signed integer overflow: -2147483647 - 2147483647 cannot be represented in type 'int'
> ...
> diff --git a/osd.h b/osd.h
> index 77722662..7a293321 100644
> --- a/osd.h
> +++ b/osd.h
> @@ -298,8 +298,8 @@ public:
>   struct tArea {
>     int x1, y1, x2, y2;
>     int bpp;
> -  int Width(void) const { return x2 - x1 + 1; }
> -  int Height(void) const { return y2 - y1 + 1; }
> +  int Width(void) const { return x2 < 0 ? 0 : x2 - x1 + 1; }
> +  int Height(void) const { return y2 < 0 ? 0 : y2 - y1 + 1; }
>     bool Intersects(const tArea &Area) const { return !(x2 < Area.x1 || x1 > Area.x2 || y2 < Area.y1 || y1 > Area.y2); }
>     };
>   

If x2 ever becomes negative, something else must have gone wrong.
So I think this check here is moot.

> diff --git a/sections.c b/sections.c
> index 51a2823c..4d90b19c 100644
> --- a/sections.c
> +++ b/sections.c
> @@ -180,7 +180,7 @@ void cSectionHandler::Action(void)
>              startFilters = false;
>              }
>           int NumFilters = filterHandles.Count();
> -        pollfd pfd[NumFilters];
> +        pollfd pfd[std::max(NumFilters, 1)];
>           for (cFilterHandle *fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
>               int i = fh->Index();
>               pfd[i].fd = fh->handle;

If NumFilters is 0, pfd[] is never accessed.
So why allocate memory for it if it is never used?

Klaus


_______________________________________________
vdr mailing list
[email protected]
https://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr