Project

General

Profile

Bug #5241

NPE in LogicalTerminal.refreshBuffers

Added by Vladimir Tsichevski about 3 years ago. Updated about 3 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:

clientstack.txt Magnifier (3.44 KB) Vladimir Tsichevski, 04/05/2021 07:08 PM

serverstack.txt Magnifier (2.16 KB) Vladimir Tsichevski, 04/05/2021 07:08 PM

History

#1 Updated by Vladimir Tsichevski about 3 years ago

  1. Convert, compile and run two procedures below.
  2. Exit the main window by pressing ESC twice.

The program bumps into NPE in LogicalTerminal.refreshBuffers.

main.p:

SESSION:SYSTEM-ALERT-BOXES = TRUE.
RUN browse.p.
WAIT-FOR CLOSE OF THIS-PROCEDURE.

browse.p (the example from #5240-1 not minimalistic):

DEF TEMP-TABLE tt FIELD f1 AS CHARACTER FORMAT "x(32)".
CREATE tt.

OPEN QUERY q FOR EACH tt.

DEFINE BROWSE brws
   QUERY q DISPLAY tt.f1
   ENABLE ALL
   WITH TITLE "Browse" 
   SIZE 70 BY 7.

DEF FRAME fr brws WITH TITLE "Frame" SIZE 70 BY 15 NO-LABELS.
ENABLE ALL WITH FRAME fr.

brws:SELECT-ROW(1).
tt.f1:SCREEN-VALUE IN BROWSE brws = "16122021".
WAIT-FOR CLOSE OF THIS-PROCEDURE.

The problematic method looks as follows:

   public static void refreshBuffers(ScreenBuffer[] buffer)
   {
      if (buffer != null)
      {
         GenericFrame frame = getWidgetForId(buffer[0].getBaseId()).getFrame();

         handleScreenBuffers(frame, buffer, false);
      }
   }

Here getWidgetForId(buffer[0].getBaseId()) returns null.

From the stack traces I gather that the client sends the screen buffers update event to the server for the widget which is already unregistered on the server.

I suppose, we may just do nothing in this situation. The fixed method may look like:

   public static void refreshBuffers(ScreenBuffer[] buffer)
   {
      if (buffer == null)
      {
         return;
      }

      final GenericWidget<?> widget = getWidgetForId(buffer[0].getBaseId());
      if(widget == null)
      {
         return;
      }

      GenericFrame frame = widget.getFrame();

      handleScreenBuffers(frame, buffer, false);
   }

#2 Updated by Greg Shah about 3 years ago

I don't object to that safety code, it makes sense to add.

But I worry that there is a deeper problem here which could lead to this kind of unexpected situation in other places. Why is the client trying to continue operation when the frame is gone already? What is the user input that was done in this example?

#3 Updated by Vladimir Tsichevski about 3 years ago

Greg Shah wrote:

I don't object to that safety code, it makes sense to add.

But I worry that there is a deeper problem here which could lead to this kind of unexpected situation in other places.

Exactly so. I consider this patch just as a code to avoid client crash. I do not know if this situation is expected or signals an error.

IMO we must avoid any potential null pointer situation at any cost. The potential nullness is a part of a type, types which allow null value and which do not must be considered as two different types. If a type allows nulls, the docs should specify exact situations when and why nulls are allows. In general, nullable types should be avoided.

Why is the client trying to continue operation when the frame is gone already? What is the user input that was done in this example?

Only as I described earlier. Press ESC key two times.

Also available in: Atom PDF