# Possible bug in CC needs confirmation

Hello, Sage community. I just noticed what I believe is a bug in the implementation of CC, but I would like to receive confirmation.

When I try the following:

'hello' in RR

I get the natural answer: False. However, if I try the same with CC:

'hello' in CC

I get the following error message:

NameError: name 'hello' is not defined

Just in case, I am using SageMath v8.8, specifically, the binary version downloaded from the mirrors.

Can somebody confirm this is a bug? Thanks in advance!

edit retag close merge delete

I would qualify this as "garbage in > garbage out"..

( 2019-07-05 02:39:22 -0500 )edit

I am sorry, @FrédéricC, but I didn't understand your comment. Can you elaborate, please?

( 2019-07-05 09:07:36 -0500 )edit
2

I disagree. I think it is a bug.

( 2019-07-05 11:14:05 -0500 )edit

Sort by » oldest newest most voted

I think it is a bug, so thank you for pointing it out.

Generally when seeking help or clarification on an error, it is best to post the full traceback. Even if it looks like meaningless gibberish to you, it does not look meaningless to the developers. In this case I get:

sage: 'hello' in CC
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-2a4614162c6a> in <module>()
----> 1 'hello' in CC

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__conta_ (build/cythonized/sage/structure/parent.c:9863)()
1090             return True
1091         try:
-> 1092             x2 = self(x)
1093             EQ = (x2 == x)
1094             if EQ is True:

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/rings/complex_field.pyc in __call__(self, x, im)
385         if im is not None:
386             x = x, im
--> 387         return Parent.__call__(self, x)
388
389     def _element_constructor_(self, x):

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/parent.pyx in sage.structure.parent.Parent.__call_uild/cythonized/sage/structure/parent.c:9197)()
898         if mor is not None:
899             if no_extra_args:
--> 900                 return mor._call_(x)
901             else:
902                 return mor._call_with_args(x, args, kwds)

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaonvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4556)()
160                 print(type(C), C)
161                 print(type(C._element_constructor), C._element_constructor)
--> 162             raise
163
164     cpdef Element _call_with_args(self, x, args=(), kwds={}):

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/structure/coerce_maps.pyx in sage.structure.coerce_maps.DefaonvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4448)()
155         cdef Parent C = self._codomain
156         try:
--> 157             return C._element_constructor(x)
158         except Exception:
159             if print_warnings:

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/rings/complex_field.pyc in _element_constructor_(self, x)
411                 # efficient way to do this.  -- Martin Albrecht
412                 return ComplexNumber(self,
--> 413                             sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()}))
414
415             late_import()

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/misc/sage_eval.pyc in sage_eval(source, locals, cmds, prepar
201         return locals['_sage_eval_returnval_']
202     else:
--> 203         return eval(source, sage.all.__dict__, locals)
204
205

/home/embray/src/sagemath/sage/local/lib/python2.7/site-packages/sage/all.pyc in <module>()

NameError: name 'hello' is not defined

Sage definitely shouldn't be throwing seemingly bizarre NameErrors in such cases.

Looking two frames up we see a fragment of a strange comment ending with "efficient way to do this." so let's start there in sage/rings/complex_field.py, line 413 or thereabout:

389     def _element_constructor_(self, x):
390         """
391         Construct a complex number.
392
393         EXAMPLES::
394
395             sage: CC((1,2)) # indirect doctest
396             1.00000000000000 + 2.00000000000000*I
397
398         Check that :trac:14989 is fixed::
399
400             sage: QQi = NumberField(x^2+1, 'i', embedding=CC(0,1))
401             sage: i = QQi.order(QQi.gen()).gen(1)
402             sage: CC(i)
403             1.00000000000000*I
404
405         """
406         if not isinstance(x, (RealNumber, tuple)):
407             if isinstance(x, ComplexDoubleElement):
408                 return ComplexNumber(self, x.real(), x.imag())
409             elif isinstance(x, str):
410                 # TODO: this is probably not the best and most
411                 # efficient way to do this.  -- Martin Albrecht
412                 return ComplexNumber(self,
413                             sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()}))

Okay, so the full comment was not all that helpful. But I can still kind of see what's happening here. When you do something like x in F where F is some field, and x is some element that may or may not belong to that field, one of the first things it will do is try to convert x to an element of F if possible.

This process passes through CC._element_constructor_, where it seems if x is not already a RealNumber, a (real, imag) tuple, or a ComplexDoubleElement, it will check if x was a string. Then there is some code which, as far as I can tell, is trying to see if the string is a valid string representation of a complex number (using either i or I as the complex unit). It is doing this by calling eval on the given string. It's expecting that you're going to try to do something like '1+2*i' in CC (which, incidentally, returns False for some reason, so it doesn't even work as expected). But this is double bad because it could fail in all sorts of ways beyond just giving a NameError. For example:

sage: '@@@@@@@@@@@@@@@@' in CC
File "<string>", line 1
@@@@@@@@@@@@@@@@
^
SyntaxError: invalid syntax

Or

sage: # DON'T TRY THIS AT HOME
sage: # NO, REALLY
sage: # 'import shutil; shutil.rmtree(sage.__path__[0])' in CC

So yes, I think this is a bug. sage_eval has no business being used in this context, and I suspect this code isn't even tested.

more

1

Apparently there's an issue for this opened 11 years ago: https://trac.sagemath.org/ticket/2877 I agree that the sage REPL is inherently unsafe just due to being a general purpose programming language (Python) in general. But this is obviously unsafe for any code that happens to use Sage in non-interactive contexts, and in general it's just fragile, surprising, and and problem-prone. Don't use eval like this!!!

( 2019-07-05 11:44:33 -0500 )edit

Less dramatic is

sage: 'print("True")' in CC

:-)

( 2019-07-11 14:41:53 -0500 )edit