Project

General

Profile

Bug #9354

Invalid handle (3135) error is thrown insted of the 10068 error.

Added by Artur Școlnic over 1 year ago. Updated 5 months ago.

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

90%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

Related issues

Related to Database - Feature #9545: confirm/add table parameter support Review

History

#2 Updated by Artur Școlnic over 1 year ago

start.p

new MyClass():my_class:mtd().

MyClass.cls
class MyClass:
define public variable my_class as class MyClass.
method void mtd():
    message "executing...".
end method.
end class.


The error Invalid handle. Not initialized or points to a deleted object. (3135) is thrown in FWD, the correct error message is:
Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN). (10068)

#3 Updated by Artur Școlnic over 1 year ago

This issue is derived from #9271-11.

#4 Updated by Alexandru Lungu over 1 year ago

  • Assignee set to Eduard Marcu

#5 Updated by Eduard Marcu over 1 year ago

  • Status changed from New to WIP

#6 Updated by Eduard Marcu over 1 year ago

  • % Done changed from 0 to 20

I can reproduce the issue. The problem is in object.ref:

   public T ref()
   {
      if (isUnknown())
      {
         String msg = "Invalid handle.  Not initialized or points to a deleted object";
         ErrorManager.recordOrThrowError(3135, msg, false);

         // TODO: is there any scenario where we can actually return null in silent error mode?
         //       (If so, that is very bad.)
         return null;
      }

      return ref;
   }

We need to make a distinction between chained and unchained objects so that both of these snippets throw the correct error:

new MyClass():my_class:mtd().

10068
define var obj as MyClass no-undo.
obj:mtd().

3135

#7 Updated by Eduard Marcu over 1 year ago

  • % Done changed from 20 to 50
class MyClass:
define public variable my_class as class MyOtherClass.
method void mtd1():
    message "executing...".
end method.
end class.

class MyOtherClass:
method void mtd():
    message "executing...".
end method.
end class.

Let's look at the following OE cases:

I:

new MyClass():my_class:mtd().

FWD & OE Output: Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN). (10068)

II:

define var obj as MyClass no-undo.
obj:mtd1(). 

FWD & OE Output: Invalid handle. Not initialized or points to a deleted object. (3135)

III:

def var x as MyClass no-undo.
x:my_class:mtd().

FWD & OE Output: Invalid handle. Not initialized or points to a deleted object. (3135) then another window with Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN). (10068)

My changes:

=== modified file 'rules/convert/oo_calls.rules'
--- old/rules/convert/oo_calls.rules    2023-10-31 13:04:48 +0000
+++ new/rules/convert/oo_calls.rules    2024-12-12 13:10:29 +0000
@@ -419,8 +419,23 @@
                                          lastid)
                </action>
             </rule>
-            
-            <action>lastid = createJavaAst(java.method_call, "ref", lastid)</action>
+
+
+
+            <rule>copy.type == prog.object_invocation and downPath(copy, prog.object_invocation)
+               <action on="true">
+                  lastid = createJavaAst(java.method_call, "chainedRef", lastid)
+               </action>
+               <rule on="false">copy.type == prog.object_invocation and upPath(copy, prog.object_invocation)
+                  <action on="true">
+                     lastid = createJavaAst(java.method_call, "firstChainedRef", lastid)
+                  </action>
+                  <action on="false">
+                     lastid = createJavaAst(java.method_call, "ref", lastid)
+                  </action>
+               </rule>
+            </rule>
+
             <action>ref1.putAnnotation("peerid", lastid)</action>

             <!-- unqualified method invocations as the first referent, this can only happen for

=== modified file 'src/com/goldencode/p2j/util/object.java'
--- old/src/com/goldencode/p2j/util/object.java    2024-03-24 09:17:59 +0000
+++ new/src/com/goldencode/p2j/util/object.java    2024-12-12 13:32:36 +0000
@@ -265,6 +265,39 @@

       return ref;
    }
+
+   public T chainedRef()
+   {
+      if (isUnknown())
+      {
+         String msg = "Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN)";
+         ErrorManager.recordOrThrowError(10068, msg, false);
+
+         // TODO: is there any scenario where we can actually return null in silent error mode?
+         //       (If so, that is very bad.)
+         return null;
+      }
+
+      return ref;
+   }
+
+   public T firstChainedRef()
+   {
+      if (isUnknown())
+      {
+         String msg1 = "Invalid handle.  Not initialized or points to a deleted object";
+
+         String msg2 = "Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a " +
+            "user-defined type and valid (not UNKNOWN)";
+
+         ErrorManager.recordOrThrowError(new int[] { 3135, 10068 }, new String[] { msg1, msg2 }, false);
+         // TODO: is there any scenario where we can actually return null in silent error mode?
+         //       (If so, that is very bad.)
+         return null;
+      }
+
+      return ref;
+   }

    /**
     * Compares this instance with the specified instance and returns -1 if this instance is less than the

Should I:
A) Make a single ref method with a flag parameter that takes care of all the cases? (i.e normal ref, chainedRef, firstChainedRef)
B) Have two refs: the original ref and chainedRef with a flag parameter that takes care of chainedRef & firstChainedRef

#8 Updated by Alexandru Lungu over 1 year ago

I think your approach is right. Please consider:

define var obj as MyClass no-undo.
obj = new MyClass().
obj:gen():gen():test():test().
message "finish".

class MyClass:
   method MyClass gen():
      return new MyClass().
   end.
   method MyClass test():
      return ?.
   end.
end.

Note how there is a way larger chain. But this results only in the Lead attributes in a chained-attribute expression exception. Please do some extra investigation with such construct to ensure your path is right - from my POV it is.

Should I:
A) Make a single ref method with a flag parameter that takes care of all the cases? (i.e normal ref, chainedRef, firstChainedRef)
B) Have two refs: the original ref and chainedRef with a flag parameter that takes care of chainedRef & firstChainedRef

I like the second version more. Maybe use ref(), chainedRef() (which will call chainedRef(false) underneath) and chainedRef(true) (which means the first ref in the chain). The overloading will help generating less code, defaulting the no-flag to false-flag.

Greg, any other suggestion?

#9 Updated by Greg Shah over 1 year ago

I like the second version more. Maybe use ref(), chainedRef() (which will call chainedRef(false) underneath) and chainedRef(true) (which means the first ref in the chain). The overloading will help generating less code, defaulting the no-flag to false-flag.

I think this is probably the best approach. I like it better than the firstChainedRef() method.

#10 Updated by Eduard Marcu over 1 year ago

For the progress code given by Alex: obj:gen():gen():test():test().

     [java] Caused by: java.lang.NullPointerException: Cannot invoke "com.goldencode.ast.Aast.getId()" because the return value of "com.goldencode.ast.Aast.getChildAt(int)" is null
     [java]     at com.goldencode.expr.CE16173.execute(Unknown Source)
     [java]     at com.goldencode.expr.Expression.execute(Expression.java:398)

=== modified file 'rules/convert/oo_calls.rules'
--- old/rules/convert/oo_calls.rules    2023-10-31 13:04:48 +0000
+++ new/rules/convert/oo_calls.rules    2024-12-13 14:33:07 +0000
@@ -419,8 +419,26 @@
                                          lastid)
                </action>
             </rule>
-            
-            <action>lastid = createJavaAst(java.method_call, "ref", lastid)</action>
+
+
+
+            <rule>copy.type == prog.object_invocation and downPath(copy, prog.object_invocation)
+               <action on="true">
+                  lastid = createJavaAst(java.method_call, "chainedRef", lastid)
+               </action>
+               <rule on="false">copy.type == prog.object_invocation and upPath(copy, prog.object_invocation)
+                  <action on="true">
+                     lastid = createJavaAst(java.method_call, "chainedRef", lastid)
+                  </action>
+                  <action on="true">
+                     createJavaAst(java.bool_true, "", getAst(lastid).getChildAt(0).getId())
+                  </action>
+                  <action on="false">
+                     lastid = createJavaAst(java.method_call, "ref", lastid)
+                  </action>
+               </rule>
+            </rule>
+
             <action>ref1.putAnnotation("peerid", lastid)</action>

             <!-- unqualified method invocations as the first referent, this can only happen for

=== modified file 'src/com/goldencode/p2j/util/object.java'
--- old/src/com/goldencode/p2j/util/object.java    2024-03-24 09:17:59 +0000
+++ new/src/com/goldencode/p2j/util/object.java    2024-12-13 08:07:59 +0000
@@ -265,6 +265,33 @@

       return ref;
    }
+
+   public T chainedRef()
+   {
+      return chainedRef(false);
+   }
+
+   public T chainedRef(boolean isFirst)
+   {
+      if(isUnknown())
+      {
+         String msg1 = "Invalid handle.  Not initialized or points to a deleted object";
+         String msg2 = "Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a " +
+            "user-defined type and valid (not UNKNOWN)";
+         if(isFirst)
+         {
+            ErrorManager.recordOrThrowError(new int[] { 3135, 10068 }, new String[] { msg1, msg2 }, false);
+         }
+         else
+         {
+            ErrorManager.recordOrThrowError(10068, msg2, false);
+         }
+         return null;
+      }
+
+      return ref;
+   }
+

    /**
     * Compares this instance with the specified instance and returns -1 if this instance is less than the


If we remove java.bool_true action the jast tree would look like this:

<ast col="0" id="240518168642" line="0" text="chainedRef" type="METHOD_CALL">
                            <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:426"/>
                            <ast col="0" id="240518168643" line="0" text="test" type="METHOD_CALL">
                              <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:381"/>
                              <ast col="0" id="240518168644" line="0" text="chainedRef" type="METHOD_CALL">
                                <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:426"/>
                                <ast col="0" id="240518168645" line="0" text="gen" type="METHOD_CALL">
                                  <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:381"/>
                                  <ast col="0" id="240518168646" line="0" text="chainedRef" type="METHOD_CALL">
                                    <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:426"/>
                                    <ast col="0" id="240518168647" line="0" text="gen" type="METHOD_CALL">
                                      <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:381"/>
                                      <ast col="0" id="240518168648" line="0" text="chainedRef" type="METHOD_CALL">
                                        <annotation datatype="java.lang.String" key="byrule" value="convert/oo_calls.rules:430"/>
                                        <ast col="0" id="240518168649" line="0" text="obj" type="REFERENCE">
                                          <annotation datatype="java.lang.Long" key="peerid" value="94489280559"/>
                                          <annotation datatype="java.lang.String" key="peerid-byrule" value="convert/variable_references.rules:1018"/>
                                          <annotation datatype="java.lang.String" key="byrule" value="convert/variable_references.rules:1018"/>

It seems that <ast col="0" id="240518168649" line="0" text="obj" type="REFERENCE"> is added after my attempt at setting chainedRef to true.

I think what is needed is to put an annotation when chainedRef should be true and after a REFERENCE gets added to jast, we verify the existence of that annotation and add java.bool_true node to jast.

#11 Updated by Greg Shah over 1 year ago

I think what is needed is to put an annotation when chainedRef should be true and after a REFERENCE gets added to jast, we verify the existence of that annotation and add java.bool_true node to jast.

Correct. You must defer the creation of the boolean node until after the reference obj is created.

#12 Updated by Eduard Marcu over 1 year ago

  • % Done changed from 50 to 70

There are some prints for debugging reasons.

=== modified file 'rules/convert/oo_calls.rules'
--- old/rules/convert/oo_calls.rules    2023-10-31 13:04:48 +0000
+++ new/rules/convert/oo_calls.rules    2024-12-16 14:02:55 +0000
@@ -419,8 +419,31 @@
                                          lastid)
                </action>
             </rule>
-            
-            <action>lastid = createJavaAst(java.method_call, "ref", lastid)</action>
+
+
+
+            <rule>copy.type == prog.object_invocation and downPath(copy, prog.object_invocation)
+               <action on="true">
+                  lastid = createJavaAst(java.method_call, "chainedRef", lastid)
+               </action>
+               <rule on="false">copy.type == prog.object_invocation and upPath(copy, prog.object_invocation)
+                  <action on="true">
+                     lastid = createJavaAst(java.method_call, "chainedRef", lastid)
+                  </action>
+                  <action on="true">
+                     copy.putAnnotation("first-chained-ref", #(java.lang.Boolean) true)
+                  </action>
+                  <action on="true">
+                     print("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY")
+                  </action>
+                  <action on="false">
+                     lastid = createJavaAst(java.method_call, "ref", lastid)
+                  </action>
+               </rule>
+            </rule>
+
+
+
             <action>ref1.putAnnotation("peerid", lastid)</action>

             <!-- unqualified method invocations as the first referent, this can only happen for

=== modified file 'rules/convert/variable_references.rules'
--- old/rules/convert/variable_references.rules    2024-07-30 07:32:38 +0000
+++ new/rules/convert/variable_references.rules    2024-12-16 14:28:02 +0000
@@ -667,7 +667,7 @@
             </rule>
          </rule>
       </rule>
-         
+
       <!-- convert variable references, bypass widget references and handles referenced into
            TABLE-HANDLE FOR -->
       <rule>evalLib("variables")                            and
@@ -1016,7 +1016,21 @@

                   <!-- emit variable/accessor -->
                   <action>createPeerAst(methodType, methodTxt, lastid)</action>
-                  
+
+                  <rule>parent.type == prog.var_class
+                     <action>
+                        print("######")
+                     </action>
+                  </rule>
+                  <rule>copy.parent.type == prog.object_invocation and
+                        #(java.lang.Boolean) copy.parent.getAnnotation("first-chained-ref")
+                     <action>
+                        printf("%d", this.type)
+                     </action>
+                     <action>
+                        lastid = createJavaAst(java.bool_true, "", lastid)
+                     </action>
+                  </rule>
                   <rule>numImmediateChildren == 0 and copy.isAnnotation("wrapNodeId")
                      <!-- simple vars: emit the 'io' = true parameter here -->
                      <action>lastid = copy.getAnnotation("wrapNodeId")</action>

=== modified file 'src/com/goldencode/p2j/util/object.java'
--- old/src/com/goldencode/p2j/util/object.java    2024-03-24 09:17:59 +0000
+++ new/src/com/goldencode/p2j/util/object.java    2024-12-13 08:07:59 +0000
@@ -265,6 +265,33 @@

       return ref;
    }
+
+   public T chainedRef()
+   {
+      return chainedRef(false);
+   }
+
+   public T chainedRef(boolean isFirst)
+   {
+      if(isUnknown())
+      {
+         String msg1 = "Invalid handle.  Not initialized or points to a deleted object";
+         String msg2 = "Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a " +
+            "user-defined type and valid (not UNKNOWN)";
+         if(isFirst)
+         {
+            ErrorManager.recordOrThrowError(new int[] { 3135, 10068 }, new String[] { msg1, msg2 }, false);
+         }
+         else
+         {
+            ErrorManager.recordOrThrowError(10068, msg2, false);
+         }
+         return null;
+      }
+
+      return ref;
+   }
+

    /**
     * Compares this instance with the specified instance and returns -1 if this instance is less than the


This works fine on #9354-8 and #9354-7 II and III but on I it fails because it doesn't manage to set the first chainedRef to true. I need to find a better place for lastid = createJavaAst(java.bool_true, "", lastid) to take place.

#13 Updated by Eduard Soltan 5 months ago

  • Related to Feature #9545: confirm/add table parameter support added

#14 Updated by Eduard Soltan 5 months ago

  • Assignee changed from Eduard Marcu to Eduard Soltan

I will take this over as there some tests in tests/table/parameter which have the same root cause as this one.

#15 Updated by Eduard Soltan 5 months ago

  • % Done changed from 70 to 90

Committed on 9354a, rev. 16442, patch from #9354-12 + some additional fixes. I have tested CHUI conversion and build (will convert large GUI application today).

Also available in: Atom PDF