The DataCAD Developer Network (DDN) is an online resource for information and support for DCAL® (DataCAD Applications Language) developers as well as anyone interested in creating fonts, toolbars, hatch patterns, or linetypes for use in DataCAD.
#76557 by dhs
Mon Jun 24, 2019 2:58 pm
I am experiencing a problem where a call to Ent_Extent is causing a crash in subsequent logic. This is not causing me an immediate issue as I have implemented alternative logic that does not crash (in fact my new logic is probably more efficient as it utilises extents that have already been calculated), but just wondering if anybody can provide any insight as to why ent_extent might be causing the crash described below ...

I have a procedure that calls several other procedures (some of which are nested within my procedure ... one of the nested procedures is called repeatedly and uses ent_extent without any problems). The section of code below occurs toward the end of my procedure.
- If I comment out the ent_extent call on line 25 then there is no crash (as expected the subsequent drag box does not display correctly but otherwise no problems).
- if I leave the ent_extent call in the code then it returns correct values for botleft and topright, and the code continues to process correctly until the end of the procedure is reached. At the end of the procedure DataCAD becomes unresponsive (for several seconds on my rather slow laptop) and then crashes (the whole program exits, not just the current drawing).

Code: Select all00    // report entities have been created, but now need to be placed in the correct positions on the drawing
01    for row := 0 to ReportRows.Count-1 do begin
02      for col := 1 to 10 do begin
03        if col = 1 then begin
04          xpos := ReportTopLeft.x;
05          if doLines then
06            xpos := xpos + SpaceLR;
07        end
08        else begin
09          xpos := xpos + ColWidths[col-1] + 2*SpaceLR;
10        end;
11        if ent_get (ent, ReportRows[row].ColAdrs[col]) then begin
12          if (ReportRows[row].RowType in [SUBTOTSROW, TOTSROW]) and (col = ReportRows[row].FirstNonBlank) then begin
13            ent.txtpnt.x := xpos + ColWidths[col];
14            ent.txtpnt.y := ypos;
15            ent.txttype.justification := TEXT_JUST_RIGHT;
16          end
17          else begin
18            ent.txtpnt.x := xpos;
19            ent.txtpnt.y := ypos;
20          end;
21          ent_update (ent);
22          if TopLeftSet then
23            ent_draw (ent, drmode_white)
24          else begin    // set report exents for subsequent DragBoxMov when placing report
25            ent_extent (ent, botleft, topright);    //ent, botleft, and topright are all locally declared variables
26            l^.Pnt1.x := min (botleft.x, l^.Pnt1.x);
27            l^.Pnt1.y := min (botleft.y, l^.Pnt1.y);
28            l^.Pnt2.x := max (topright.x, l^.Pnt2.x);
29            l^.Pnt2.y := max (topright.y, l^.Pnt2.y);
30          end;
31        end;
32      end;
33
34      ypos := ypos - SpaceBelow[ReportRows[row].RowType];
35      if row < (ReportRows.Count-1) then begin
36        ypos := ypos - SpaceAbove[ReportRows[row+1].RowType] - ReportRows[row+1].RowHeight;
37      end;
38    end;


Don't know if the issue might be a bug with the ent_extent call (it is used is many other places in the macro without any issues), or even a bug with Delphi itself. Both seem unlikely, but I can't see any issues with my code.
Perhaps somebody else may be able to spot an issue or at least throw some light on a possible cause of the crash.

Thanks in advance,
David H.
#76572 by dhs
Wed Jun 26, 2019 10:49 pm
Have come across another instance where a call to ent_extent appears to be causing a subsequent crash (same symptoms as before).

In this new instance I was able to do my own extent calculations based on the entity type: fortunately the code only needed to cater for 2d lines and text entities so I based my calculations on points returned by a call to txtbox for text entities, and on linpt1 and linpt2 for 2d line entities.

Replacing the ent_extent call with this new logic fixed the crash, so I am beginning to be pretty certain that there is a bug of some sort in the DCAL ent_extent procedure... (even though I have used it elsewhere in the same macro and those calls are not causing a problem)

Rgds,
David H.
#83540 by dhs
Sun Mar 23, 2025 1:16 pm
I used ent_extent in my Spaces macro since my previous post on this topic, and it did not cause any problems. But when testing a new version of Shadow macro over the last few days I have been seeing some unexpected crashes ... I removed the ent_extent calls and the crashes stopped.
In Spaces it would only have been used on polylines and/or polygons, but the tests over the last few days involved mainly slabs. Perhaps the ent_extent issues are related to some entity types only?
I'm testing in the latest version of DataCAD (23.00.05.02).

p.s. Spaces is the source where I replaced ent_extent with txtbox for text entities (as per my previous post on this topic, but I left ent_extent where it was used on polylines etc.). So that also supports the contention that the ent_extent issues relate to some entity types only...
#83564 by dhs
Fri Apr 18, 2025 4:19 pm
Perhaps the ent_extent issues are related to some entity types only

Not so - I am experiencing crashes when ent_extent is used on a large number of polygons. My test involved a sphere that had been exploded to polygons (produced 666 polygons - perhaps that is an omen, as with 36 divisions I would only have expected 648). My logic was trying to find the overall extents of entities that had a particular attribute (the 666 polygons are the only ones satisfying this attribute test). It seemed that a large number of ent_extent calls were processing ok and it was crashing around the 150th call. To aid my debugging I added a dialog message to display every 15th iteration. It now fails with an EIntOverflow exception (integer overflow) the first time it tries to display that message (i.e. 15th iteration).
The code for the loop is shown below:
Code: Select all    MyModeInit (mode);
    mode_lyr (mode, lyr_all);
    mode_atr (mode, MyAttrName);
    adr := ent_first (mode);
    var tempent : entity;
    while ent_get (ent, adr, false) do begin
      adr := ent_next (ent, mode);
      if atr_entfind (ent, MyAttrName, atr) and (atr.atrtype = atr_int) and
         ((atr.int and CastAtrVal) > 0) then begin
        if (count = 0) then begin
          tempent := ent;
          ent_extent (tempent, lowleft, topright);
          //MyEntextent (tempent, lowleft, topright);
        end
        else begin
          tempent := ent;
          ent_extent (tempent, lowleft2, topright2);
          //MyEntextent (tempent, lowleft2, topright2);
          lowleft.x := min (lowleft.x, lowleft2.x);
          lowleft.y := min (lowleft.y, lowleft2.y);
          lowleft.z := min (lowleft.z, lowleft2.z);
          topright.z := max (topright.z, topright2.z);
          topright.y := max (topright.y, topright2.y);
          topright.x := max (topright.x, topright2.x);
        end;
        count := count + 1;
        if (count mod 15) = 0 then
           MessageDlg ('Count Progress: ' + inttostr(count), mtInformation, [mbOK], 0);   // fails with integer overflow exception 1st time it processes this line
      end;
    end;

Interestingly, using debugger to evaluate 'inttostr(count)' shows the expected result ('15') immediately before the MessageDlg call.

In the above code you will notice that I have commented out a call to 'MyEntExtent' (which is a call to my own procedure which caters for a few entity types including polygons). When that call is included (and the ext_extent call commented out) then the loop (and the whole macro) processes without any problem (I commented my own call and put ent_extent back in to reproduce the exception so I could write this post).
I can only conclude that ent_extent is causing some sort of memory corruption that causes a subsequent operation to throw an exception (I was seeing an access violation when I ran it before adding the MessageDlg code).

You will notice that I use 'MyModeInit' instead of mode_init in the above code. This is because in the past I found that mode_init was corrupting a variable declared adjacent to the mode variable (Dave G was unable to reproduce it at the time, but I wrote my own version of mode_init that overcame the problems I was seeing - it was a pretty simple solution and my MyModeInit code is shown below). I wondered if ent_init had a similar problem so tried turning off optimization and adding fillers around the variables passed to ent_extent, but this did not fix the issue.
The copying of ent to tempent was also added in case ent_extent was corrupting ent (which presumable could have caused a problem the next time ent_next was called (as ent is passed as a parameter to that call)), but using a copy of ent did not fix the problem.

The code for MyModeInit procedure is shown below:
Code: Select all{$OPTIMIZATION OFF}
{$HINTS OFF}
procedure MyModeInit (var mode : mode_type);
var
  filler : byte;  // without this filler a mode_init call can currupt
                  // memory adjacent to the mode variable.
  mymode : mode_type;
begin
  mode_init(mymode);
  mode := mymode;
end;
{$HINTS ON}
{$OPTIMIZATION ON}

Who is online

Users browsing this forum: No registered users and 3 guests

About DataCAD Forum

The DataCAD Forum is a FREE online community we provide to enhance your experience with DataCAD.

We hope you'll visit often to get answers, share ideas, and interact with other DataCAD users around the world.

DataCAD

Software for Architects Since 1984