Jump to content
sp0987

Access Violation and Invalid Pointer exception while accessing files from web pages

Recommended Posts

I am writing an HTTP server (TIdHTTPServer) program that services GET requests for images. This 'OnCommandGet ' procedure of Httpserver, calls other procedures to do various tasks, and then finally gets back to the client via TIdHTTPResponseInfo. 

 

 

procedure TVRMEditor.HTTPServerCommandGet(AContext: TIdContext;
  req: TIdHTTPRequestInfo; res: TIdHTTPResponseInfo);
var
  act, DocExt: string;
begin
  try
    res.SERVER := 'VRM Editor';
    res.ContentType := 'text/html;charset="UTF-8"';
    res.ResponseNo := 200;

   
    act := UpperCase(copy(req.Document, 2, Length(req.Document) - 1));
    DocExt := UpperCase(ExtractFileExt(act));

    self.Log(fcomp_name + ': ' + copy(req.RawHTTPCommand, 1,
      Length(req.RawHTTPCommand) - 9), allowed); -- allowed is a flag to print all the req commands when set to true

    if DocExt = '.MAX' then
    begin
      self.ProcessResponse(req, res);
    end
    else
      self.SendFileToClient(req, res); -- access all the js/css/jpg/css files which are needed to open a web page

  except
    on E: Exception do
    begin
      self.Log(req.URI + ' : ' + req.Document + sLineBreak + E.ClassName + ' : '
        + E.Message);     
    end;
  end;
end;

 

When the Allowed flag is set to true, it prints al the request commands and opens the webpage without any error. 

If it sets to false, am getting AV / Invalid pointer and couldn't open the page. Am not sure whether you can get the log, but you can see the exceptions.

 

 

Allowed = true.log

Allowed=false.log

Share this post


Link to post

Hi,

 

From what i see, and i am guessing here, that exception is not from this code you pasted, but from one or two different places not shown here:

One raised EInvalidPointer : Invalid pointer operation
The other raised EAccessViolation : Access violation at address 0047C27C in module 'VRMEditor.exe'. Read of address FFFFFFFx

The second exception does look like managed type variable wrongly or unsafely accessed, in other words it was uninitialized yet there was something trying to access or may be just clean it up, or it could be overwritten on the stack and had corrupted value and the exception was triggered in the hidden part of "end;", (aka clean up) 

 

Try to extended logging within  self.Log(... itself , there most likely your broken code, track memory corruption too.

Share this post


Link to post
Posted (edited)

There is no way for us to diagnose the problem with just the log files alone. Clearly there is a problem inside of your Log() or SendFileToClient() methods, but you didn't show any of that code.

 

The Access Violation is telling you the exactly memory address of the code that crashed, 0047C27C. Run the server inside the debugger and jump to that address and see what code is actually running there. 

 

On a side note, your OnCommandGet handler is catching and swallowing all exceptions. Don't do that. Indy uses exceptions for error handling, and certain exceptions should be handled by the server itself. For instance, so it knows when to shut down the calling thread when the client disconnects. So, at the very least, you should rethrow any caught exception that derives from EIdException. 

Edited by Remy Lebeau

Share this post


Link to post

procedure TVRMEditor.SendFileToClient(req: TIdHTTPRequestInfo;
  res: TIdHTTPResponseInfo);
var
  doc, ext, Data, fname, err: String;
  b: boolean;
  rlst: TStringList;
begin
  Data := '';
  fname := req.Document;
  doc := ExpandFilename(self.RootDir + fname);
  if not FileExists(doc) then
  begin
    self.Log(fcomp_name + ': ' + fname + ' not in editor''s webroot!',
      LogServer);
    doc := ExpandFilename(fclirootdir + '\webroot\' + fname);
    if not FileExists(doc) then
    begin
      self.Log(fcomp_name + ': ' + fname + ' not found in any webroot!');
      doc := '';
    end;
  end;

  if doc <> '' then
  begin
    ext := UpperCase(ExtractFileExt(fname));
    b := (ext = '.CSS') or (ext = '.HTM') or (ext = '.HTML') or (ext = '.JS');
    if not b then
    begin
      res.ContentType := fMIMEMap.GetFileMIMEType(doc);
      res.ContentStream := TFileStream.Create(doc, fmOpenRead or fmShareCompat);
    end
    else
    begin
      try
        rlst := TStringList.Create;
        GetConstantGroup('Global_Skin', rlst);
        Data := LoadDataFromFile(doc);

        Data := ReplaceAllStringParams(Data, [rlst], '#S', '#', true);
        if not ReplaceForIncludFiles(Data, err, rlst, true) then
          self.Log(' #Include Replace Error: ' + err);

        res.ContentType := fMIMEMap.GetFileMIMEType(doc);
        res.ContentStream := TStringStream.Create(Data);
      finally
        rlst.Free;
      end;
    end;
  end;
end;

 

Code to sendfiletoclient

 

Share this post


Link to post
8 hours ago, sp0987 said:

Code to sendfiletoclient

What about the code for Log()? Since that is the function you were complaining about earlier.

 

Which function exactly is the exception actually being raised in?

Share this post


Link to post

Procedure GLog(Msg: String);

var
  gLogger: TFileLogger = nil;
begin
  if Assigned(gLogger) and Assigned(gLogger.Memo) then
  begin
    gLogger.fmLock.Enter;
    gLogger.Memo.Lines.BeginUpdate;
    while gLogger.Memo.Lines.Count > 600 do
      gLogger.Memo.Lines.Delete(0);
    gLogger.Memo.Lines.Add(Msg);
    gLogger.Memo.Lines.EndUpdate;
    gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0);
    gLogger.fmLock.Leave;
  end;

  _Log(Msg);
end;

 

 

Upon my observation, when log prints all the requests from web page, there was no AV/ Invalid pointer Exception. Am not sure that log function was the culprit...

Share this post


Link to post
Posted (edited)
4 hours ago, sp0987 said:

var
  gLogger: TFileLogger = nil;
begin
  if Assigned(gLogger) and Assigned(gLogger.Memo) then

First, Delphi doesn't allow you to initialize variables in a 'var' block.  And second, even if you could, your variable is initialized to nil and not assigned to something else, so the Assigned() checked will ALWAYS return False. 

 

But, even if the above was working ok...

4 hours ago, sp0987 said:

    gLogger.fmLock.Enter;
    gLogger.Memo.Lines.BeginUpdate;
    while gLogger.Memo.Lines.Count > 600 do
      gLogger.Memo.Lines.Delete(0);
    gLogger.Memo.Lines.Add(Msg);
    gLogger.Memo.Lines.EndUpdate;
    gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0);
    gLogger.fmLock.Leave;

TIdHTTPServer is a multi-threaded component, its events are fired in worker threads, and you can't access UI controls directly in worker threads.  So, if you are calling Log() in your server's events, then the above code can easily be crashing.  You MUST not access UI controls from outside of the main UI thread.  Use TThread.Synchronize() or equivalent to run this code block in the UI thread, using a mutex lock is not sufficient.

 

Try this:

Procedure GLog(Msg: String);
begin
  if Assigned(gLogger) and Assigned(gLogger.Memo) then
  begin
    TThread.Synchronize(nil,
    procedure
    begin
      if Assigned(gLogger) and Assigned(gLogger.Memo) then
      begin
        gLogger.Memo.Lines.BeginUpdate;
        try
          while gLogger.Memo.Lines.Count > 600 do
            gLogger.Memo.Lines.Delete(0);
          gLogger.Memo.Lines.Add(Msg);
        finally
          gLogger.Memo.Lines.EndUpdate;
        end;
        gLogger.Memo.Perform(EM_SCROLLCARET, 0, 0);
      end;
    end);
  end;
  _Log(Msg);
end; 

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×