[Mono-bugs] [Bug 623114] New: MonoTouch App Fails on the iPhone with illogical stack trace and works on the Simulator

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Fri Jul 16 15:26:29 EDT 2010


http://bugzilla.novell.com/show_bug.cgi?id=623114

http://bugzilla.novell.com/show_bug.cgi?id=623114#c0


           Summary: MonoTouch App Fails on the iPhone with illogical stack
                    trace and works on the Simulator
    Classification: Mono
           Product: MonoTouch
           Version: unspecified
          Platform: Other
        OS/Version: Mac OS X 10.6
            Status: NEW
          Severity: Critical
          Priority: P5 - None
         Component: Runtime
        AssignedTo: mono-bugs at lists.ximian.com
        ReportedBy: rafael.teixeira at opencs.com.br
         QAContact: mono-bugs at lists.ximian.com
          Found By: Development
           Blocker: ---


Description of Problem:

An application that communicates over the web, uses encryption and saves/reads
local files with encrypted text blobs, is failing to write to the files, while
running in the device, aborting with some exceptions on stack frames that
couldn't possibly be being called. It works normally on the iPhone Simulator.

Adding code to help debug (as we can't make the soft debugger to work over the
firewall between our wifi network and our hardwired development network)
sometimes changes the place the exception occurs in unpredictable ways 

>From the symptoms it looks like native code generation is doing something wrong
with the circularly constrained hierarchy of of generics-based classes. See
below

Steps to reproduce the problem:
1. Compile App for Simulator
2. Deploy to simulator
3. Runs, fill in the needed info, expects download, results oK
4. Compile App for iPhone
5. Deploy to iPhone 3G, running iOS 4.0
6. Runs, fill in the needed info, expects download, fail to save and complete
the process

Actual Results:

It breaks on a call to something that is not being called. So it stops the
process of saving the downloaded information.

Expected Results:
To simply write the received data an go on.

How often does this happen? 
Currently always, even if the app is completely uninstalled first.

Additional Information:

The circularly constrained code is (partial):

namespace OpenCS.MTrusted.iPhone.Core.Storage
{
    public class Account : SerializableAsText<Account>
    {
        public Account ()
        {
        }

        public override string UniqueName {
            get { return Name.Replace(" ", ""); }
        }

        public override string AsText {
            get { return Name + '\n' + SerializedToken; }
            set {
                string[] parts = value.Split('\n');
                Name = parts[0];
                SerializedToken = parts[1];
            }
        }

        public string Name { get; set; }

        public int EnterpriseId { get; set; }

        public string SerializedToken { get; set; }
    }

    public class Enterprise : SerializableAsText<Enterprise, Account>
    {
..
            }

    public abstract class SerializableAsText
    {
        public abstract string UniqueName { get; }
        public abstract string AsText { get; set; }
        public virtual SerializableAsText Parent { get; set; }
        public abstract void Save ();
        public abstract void Delete ();

        internal bool Modified { get; set; }
        internal bool Deleted { get; set; }    
        internal IPersister Persister { get; set; }

        protected SerializableAsText() { Deleted = false; }

        public override bool Equals (object obj)
        {
            SerializableAsText other = obj as SerializableAsText;
            return other != null &&
                other.UniqueName == UniqueName &&
                other.AsText == AsText;
        }

        public override int GetHashCode ()
        {
            return UniqueName.GetHashCode ();
        }
    }

    public abstract class SerializableAsText<T> : SerializableAsText where T :
SerializableAsText, new()
    {
        private const string DeletedPrefix = "Deleted-";

        public override void Save ()
        {
            Console.WriteLine("Saving " + FullPath);
            using (StreamWriter sw = new StreamWriter (FullPath, false,
Encoding.UTF8)) {
                if (Deleted)
                    sw.Write(DeletedPrefix);
                sw.WriteLine(AsText);
                sw.Close();
                Persister.Register(FileName);
            }
            Modified = false;
        }

        public override void Delete ()
        {
            Deleted = true;
            Save();
        }

        protected internal static T Load (string path, IPersister persister)
        {
            Console.WriteLine("Loading " + path);
            using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) {
                string serializedValue = sr.ReadToEnd();
                T it = new T();
                it.Persister = persister;
                if (serializedValue.StartsWith(DeletedPrefix)) {
                    it.Deleted = true;
                    serializedValue =
serializedValue.Substring(DeletedPrefix.Length);
                }
                it.AsText = serializedValue;
                it.Modified = false;
                sr.Close();
                return it;
            }
        }

        private static string FileMask (SerializableAsText parent)
        {
            return Compose(parent, "*", typeof(T).Name.ToLowerInvariant());
        }

        public static IList<T> List (SerializableAsText parent, IPersister
persister)
        {
            List<T> entities = new List<T>();
            foreach (string path in persister.GetPaths(parent, FileMask
(parent))) {
                try {
                    T entity = Load(path, persister);
                    if (!entity.Deleted) {
                        entity.Parent = parent;
                        entities.Add(entity);
                    }
                } catch (Exception e) {
                    Console.WriteLine("Error while loading data from '{0}':
{1}", path, e);
                }
            }
            return entities;
        }

        internal string FullPath {
            get { return Persister.FullPath(FileName); }
        }
        private string FileName {
            get { return Compose(Parent, UniqueName, Extension); }
        }
        protected static string Extension {
            get { return typeof(T).Name.ToLowerInvariant(); }
        }
        protected static string Compose (SerializableAsText parent, string
middle, string extension)
        {
            if (parent == null)
                return middle + "." + extension;
            return parent.UniqueName + "." + middle + "." + extension;
        }
    }

    public abstract class SerializableAsText<T, C> : SerializableAsText<T>
where T : SerializableAsText<T, C>, new() where C : SerializableAsText<C>,
new()
    {
        public abstract IList<C> Children { get; set; }

        public override void Delete ()
        {
            base.Delete();
            if (Children != null)
                foreach (SerializableAsText child in Children)
                    child.Delete();
        }

        public static IList<T> ListAll (IPersister persister)
        {
            IList<T> entities = SerializableAsText<T>.List(null, persister);
            foreach (T entity in entities)
                entity.Children = SerializableAsText<C>.List(entity,
persister);
            return entities;
        }

    }
}

It fails when calling the Save() method on Enterprise (inherited from
SerializableAsText<T,C>), which doesn't appear in the Stack Trace but is the
only real candidate as the last meaningful frame in the stack trace is on this
method on another class (called the StorageManager)

        public void SaveEnterprise (Enterprise e)
        {        
            if (e == null) {
                throw new ArgumentNullException();
            }

            e.Persister = persister;        
            e.Save();
        }

I`ll try to hand copy below the stack trace I have put in an AlertView in the
iPhone, that I can't debug by network difficulties as I've stated before.

System.IndexOutOfRangeException: Array index is out of range at
OpenCS.MTrusted.iPhone.Core.Crypto.PBEGenerator.UpdateCounter(Int32 round) ...
at
OpenCS.MTrusted.iPhone.Core.Crypto.PBEGenerator.PBKDF2(System.Byte[] salt,
Int32 round) ... at
OpenCS.MTrusted.iPhone.Core.Storage.StorageManager.SaveEnterprise(OpenCS.MTrusted.iPhone.Core.Storage.Enterprise
e) ...

Another important detail: These classes are built into a library project
(OpenCS.MTrusted.iPhone.Core) referenced from the MonoTouch iPhone Application
project (OpenCS.MTrusted.iPhone)

-- 
Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.


More information about the mono-bugs mailing list