2015-01-01 4 views
0

Я получаю исключения SIGSEGV (11) в многоплатформенных приложениях с, казалось бы, простым кодом. Кажется, отладчик ведет меня в другое место каждый раз, когда это происходит. Поэтому я собрал простое приложение, чтобы продемонстрировать это. Это не происходит в Windows, но это происходит на всех других платформах. Windows отлично работает. Это единственный пример, который я могу воссоздать каждый раз и демонстрировать ниже, из библиотеки XSuperObject.Получение ошибок SIGSEGV (11) во многих местах

Запустите новое пустое многоплатформенное приложение и добавьте только одну кнопку.

DFM

object Form1: TForm1 
    Left = 0 
    Top = 0 
    Caption = 'Form1' 
    ClientHeight = 259 
    ClientWidth = 310 
    FormFactor.Width = 320 
    FormFactor.Height = 480 
    FormFactor.Devices = [Desktop] 
    DesignerMasterStyle = 0 
    object Button1: TButton 
    Position.X = 136.000000000000000000 
    Position.Y = 96.000000000000000000 
    TabOrder = 0 
    Text = 'Button1' 
    OnClick = Button1Click 
    end 
end 

Теперь добавьте только обработчик для OnClick события этой кнопки.

КОД

unit uMain; 

interface 

uses 
    System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
    FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, 
    XSuperObject; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    public 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.fmx} 

uses 
    IOUtils; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    O: ISuperObject; 
    L: TStringList; 
    FN: String; 
begin 
    FN:= TPath.Combine(TPath.GetHomePath, 'MyApp'); 
    ForceDirectories(FN); 
    FN:= TPath.Combine(FN, 'Test.json'); 
    O:= SO; 
    O.S['foo']:= 'bar'; 
    L:= TStringList.Create; 
    try 
    L.Text:= O.AsJSON(True); 
    L.SaveToFile(FN); 
    finally 
    L.Free; 
    end; 
    O:= TSuperObject.ParseFile(FN); // <-- SIGSEGV (11) happens here 
end; 

end. 

На тесте с OSX, например, нажатие кнопки вызывает исключение:

Project SIGSEGVTest raised exception class SIGSEGV (11). 

Когда я нажимаю на Break, он принимает меня в какой-то System.Character.inc файл на линии 1394, которая, как представляется, представляет собой кучу двоичных данных:

db $59,$40,$00,$00,$00,$00,$00,$40,$8F,$40,$00,$00,$00,$00,$00 

В некоторых случаях я получаю это исключение повторно за то, что кажется бесконечным. Я не могу проследить, откуда он. Мне не повезло в этом, все, что я нахожу, либо на другом языке, и без ответа, либо на другом паскале IDE (например, Lazarus). Время от времени, в том же сценарии, что и выше, приложение просто блокируется, а не дает это исключение. Также иногда отладчик не принимает меня нигде, когда я нажимаю Break.

Я понимаю, что означает исключение (по сути, такое же, как Access Violation), но почему я получаю это исключение на всех платформах, отличных от Windows?

ПРИМЕЧАНИЕ

мне удалось исправить это в одном месте в прошлом, используя дженерики TList<>, а не традиционный осуждается TList. Но это всего лишь одно, и я изо всех сил пытаюсь выяснить причину, по которой я получаю это исключение во многих местах. Это сражалось уже несколько недель.

Я использую Delphi XE7 Update 2, и моя копия XSuperObject была обновлена ​​прямо сейчас с последней, но не удачей.

Я также установил последнюю версию Fix Pack IDE и все еще не повезло.

ОБНОВЛЕНИЕ

Когда, например, работает этот же приложение изнутри тренажера IOS, (IOS 7.1) без отладки, я получаю следующее:

Access violation at address 0060907D, accessing address 00000000. 

UPDATE

Вот отчет аварии из OSX (слишком большой, чтобы поместиться здесь):

http://pastebin.com/0Tg7pNn8

UPDATE

Это почти похоже на указатель s как-то развращаются. В большинстве случаев, которые я видел до сих пор, это происходит, когда я обращаюсь к указателю, который должен быть инициализирован. Например, когда у меня был классический TList, он позволял мне использовать его просто отлично, за исключением случаев, когда я пытался прочитать один из указателей, и у меня была такая же ошибка. Тот же самый точный код отлично работает в Windows. Например, MyObj:= TMyObj(MyTList[0]);, где я вижу правильный указатель, есть, но все равно производит это исключение. К сожалению, поскольку я пытался воспроизвести этот конкретный сценарий, я не могу.

UPDATE

я просто наконец-то удалось пошагово XSuperObject библиотека (ранее я получал другие странные вопросы, пытаясь установить контрольную точку пошагово). Он ломает на линии 587, который находится внутри следующего конструктора:

constructor TBaseJSON<T, Typ>.Create(JSON: String; const CheckDate: Boolean); 
type PInterface = ^IInterface; 
var 
    JVal: IJSONAncestor; 
    PIntf: PInterface; 
begin 
    FCheckDate := CheckDate; 
    if (Self.InheritsFrom(TSuperArray)) and (Trim(JSON) = '{}') then JSON := '[]'; 
    JVal := TJSONObject.ParseJSONValue(JSON, FCheckDate); 
    if JVal.QueryInterface(GetTypeData(TypeInfo(T)).Guid, FJSONObj) = S_OK then // <-- Happens here 
    FInterface := TValue.From<T>(FJSONObj).AsInterface 
    else 
    FCasted := JVal 
end; 
+0

Теперь, когда я оглядываюсь назад на моей прошлую работе, я понял, что я получил вокруг этого точно такой же ошибки в мое производственное приложение, сначала загрузив его в список строк, а затем разобрав его. Кажется, единственный способ. Я все равно хотел бы знать, почему. –

+0

Вам нужно найти код, который дает ошибку –

+0

@David Мне просто удалось пройти через библиотеку 'XSuperObject'.См. Мое обновление выше. Я ожидал, что кто-то еще должен был столкнуться с этим раньше и знает, что происходит, но я думаю, что я единственный человек в мире, с которым это происходит? –

ответ

2

Это ошибка в XSuperObject. Он сбой, когда файл JSON начинается с спецификации Юникода. Вы должны сохранить файл в формате JSON без BOM, но в Unicode:

L.WriteBOM := False; 
L.SaveToFile(FN, TEncoding.UTF8); 

Но вы по-прежнему вылетать, если вы получите файл в формате JSON, который имеет спецификацию. Для того чтобы избежать этого, вы можете залатать TSuperObject.ParseStream следующим образом:

class function TSuperObject.ParseStream(Stream: TStream): TSuperObject; 
var 
    Strm: TStringList; 
begin 
    Strm := TStringList.Create; 
    try 
    Strm.LoadFromStream(Stream); 
    Result := TSuperObject.Create(Strm.Text); 
    finally 
    Strm.Free; 
    end; 
end; 

Это только быстрый обходной путь. Лучший подход должен более внимательно рассмотреть кодировку JSON-файла.

Когда файл сохранен на OSX, это выглядит следующим образом:

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 

00000000 EF BB BF 7B 0D 0A 20 20 22 66 6F 6F 22 3A 22 62 {.. "foo":"b 
00000010 61 72 22 0D 0A 7D 0D 0A       ar"..}.. 

Первые 3 байта является BOM, что вызывает проблемы для XSuperObject. Сбой происходит из-за того, что JVal равен нулю в строке 587 во второй раз, когда он попадает в эту строку.

Update:

RFC 7159 говорит, что реализация JSON не должны добавить метку порядка байтов в начале. Но они могут игнорировать его, если он есть. Поэтому даже если возможность обрабатывать спецификацию не является требованием, она не должна сбой в этом случае.

Кодирование JSON должна быть обнаружено, глядя на файл вместо (это объясняется в устаревшем RFC 4327)

+0

Это не ошибка. Файлы JSON не должны иметь спецификаций. –

+0

Я должен согласиться с тем, что файлы JSON не должны иметь спецификаций. Но парсер не должен терпеть крах с нарушением прав доступа, если кто-то нарушил это правило. –

+0

Это справедливая точка. Ваше предложенное решение неверно. Запишите файл без спецификации. –

Смежные вопросы