Closed Bug 116976 Opened 23 years ago Closed 23 years ago

nsFrame::GetBidiProperty is bad for Big Endian machine

Categories

(Core :: Layout: Text and Fonts, defect)

PowerPC
macOS
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla0.9.8

People

(Reporter: ftang, Assigned: ftang)

References

Details

Attachments

(1 file, 3 obsolete files)

when I debug MacOS X hebrew support with smontagu, we find out one major problem
with bidi code. The nsFrame::GetBidiProperty and SetBidiProperty pair is bad for
Big Endian machinese:

http://lxr.mozilla.org/seamonkey/source/layout/html/base/src/nsFrame.cpp#4104
NS_IMETHODIMP nsFrame::GetBidiProperty(nsIPresContext* aPresContext,
                                  nsIAtom*        aPropertyName,
                                  void**          aPropertyValue,
                                  size_t          aSize) const
{
  if (!aPropertyValue || !aPropertyName) {
    return NS_ERROR_NULL_POINTER;
  }
  if ( (aSize < 1) || (aSize > sizeof(void*) ) ) {
    return NS_ERROR_ILLEGAL_VALUE;
  }

  nsCRT::zero(aPropertyValue, aSize);
  void* val = nsnull;

  nsCOMPtr<nsIPresShell> presShell;
  aPresContext->GetShell(getter_AddRefs(presShell) );

  if (presShell) {
    nsCOMPtr<nsIFrameManager> frameManager;
    presShell->GetFrameManager(getter_AddRefs(frameManager) );

    if (frameManager) {
      frameManager->GetFrameProperty( (nsIFrame*)this, aPropertyName, 0, &val);
      if (val) {
        nsCRT::memcpy(aPropertyValue, &val, aSize);
      }
    }
  }
  return NS_OK;
}

NS_IMETHODIMP nsFrame::SetBidiProperty(nsIPresContext* aPresContext,
                                  nsIAtom*        aPropertyName,
                                  void*           aPropertyValue) 
{
  nsresult rv = NS_ERROR_FAILURE;

  nsCOMPtr<nsIPresShell> shell;
  aPresContext->GetShell(getter_AddRefs(shell) );
  if (shell) {
    nsCOMPtr<nsIFrameManager> frameManager;
    shell->GetFrameManager(getter_AddRefs(frameManager) );
    if (frameManager) {
      rv = frameManager->SetFrameProperty( (nsIFrame*) this, aPropertyName,
aPropertyValue, nsnull);
    }
  }
  return rv;
}

What happen is when the aSize is < 4 and in the big endian machine. The
SetProperty will just copy size of (void*) to the hash table. But the
GetBidiProperty will copy the beginning aSize and return.
In the little endian machine, it is not a big deal. But if the return value is
0x00000001 and on big endian machine and ask for 1 byte return. The
GetBidiProperty will copy the 00 return instead of 0x01 return. Therefore, on
MacOS, the embedding level is always 0.
I think this will always cause problem on other machines, such as AIX or
Solaris. As long as it is big endian machine. 
Status: NEW → ASSIGNED
Target Milestone: --- → mozilla0.9.8
reassign to self
Assignee: mkaply → ftang
Status: ASSIGNED → NEW
Blocks: 104056
Status: NEW → ASSIGNED
ok. this patch compiled and run fine on MacOS X
compiled on Win and Linux. (not run time change for little endian macine)
mkaply can kataki, can you try this patch on AIX and big endian Solaris?
mkply: can r= this one ?
Blocks: 74125
Blocks: 80577
Blocks: 96305
Blocks: 110655
Blocks: 111967
No longer blocks: 110655
Blocks: 81369
Attached patch modified patch (obsolete) — Splinter Review
shanjian: my patch let compiler do the magic since it is the compiler which cast
the PRInt8 it void* eariler. 
Your patch probably will also work under big endian. What will happen to 64 bits
machine ? 
shanjian send the following thorugh private email:
>Frank,
>
>I tried this on my HPUX box, and it does not compile. HPUX does not allow hard 
>cast from void* to PRUint8 and PRUint16. I modified the patch and attached to
bug >report to save a round of email.
Comment on attachment 62884 [details] [diff] [review]
modified patch

The SetBidiProperty interface is broken.  It should take an aSize parameter and
a *pointer* to an integral type, and copy that many bytes from the given
address into whatever intermediate or internal buffer it needs (in this case, a
void* that's passed to SetFrameProperty).

As a quick fix, shanjian's patch is ok, but I'd rather see the interface
methods made symmetric.  There are only a few file's worth of a few calls per
file to SetBidiProperty.

/be
I believe the following three patch should fix most mac os hewbrew problem

big endian issue in nsFrame.cpp
see latest patch in http://bugzilla.mozilla.org/show_bug.cgi?id=116976

big endian issue in nsBidiImp.cpp 
http://bugzilla.mozilla.org/attachment.cgi?id=62917&action=view

turn off hebrew reordering and do not report hint on mac gfx
http://bugzilla.mozilla.org/attachment.cgi?id=62920&action=view
What are the different BiDi properties that are being read and set here? Are they 
always 32 bits or less? Why not just get/set 32-bit values, rather than void*, 
and do the up/down cast in the calling code?
it could be a nsIFrame*. It could be > 32 bits on a 64 bits machine.
Basically, I agree with you, I think we could always get a (void*) , not a 32
bits. and let the caller cast it down to what ever it shoudl be. 
Let's check in shanjian's patch and fix the api on a seperate bug. see bug 117751
could we check in
http://bugzilla.mozilla.org/attachment.cgi?bugid=116976&action=enter for now and
fix the api issue in bug 117751?
Comment on attachment 62884 [details] [diff] [review]
modified patch

r=ftang
Attachment #62884 - Flags: review+
Blocks: 104148
No longer blocks: 104056
jdunn, can you try to compile on those big endian machines you have ?
kataki- do you have big endian machine (solaris?)
the patch compiled on Solaris w/o problem
I can test this on Solaris/SPARC if someone can explain me how I can verify this
...

BTW: Why are we using nsCRT::memcpy() instead of ANSI C memcpy() (this destroys
the optimisations some compiler/OSes can do when using their "built-in" memcpy()
versions) ?
It compiled on HPUX
>BTW: Why are we using nsCRT::memcpy() instead of ANSI C memcpy() (this destroys
>the optimisations some compiler/OSes can do when using their "built-in" memcpy()
>versions) ?

We should always use nsCRT if possible in xp code. If Compiler/OS can do with
their build-in memcpy() can we fix that in nsCRT::memcpy() ?

>I can test this on Solaris/SPARC if someone can explain me how I can verify this

thanks, I already verify it on Solaris.
It should impact the correctness of Hebrew/Arabic display . Hard to explain.
ftang wrote:
> We should always use nsCRT if possible in xp code. If Compiler/OS can do with
> their build-in memcpy() can we fix that in nsCRT::memcpy() ?

Not really. The built-in compiler memcpy() requires to be |inline| because they
look for common optimisations (small fixed[1] size (inline long word block
copies), large fixed size (which calls specfic OS routine for large mem copies,
alignment optimisations etc. etc)

[1]=("fixed" = either constant fixed value or the compiler can figure out that
the variable may only contain a known value/expresson which can be used for
further optimisation).

I would vote to implement a PL_memcpy() which should be a macro to memcpy() on
platforms where memcpy() is not available (is there any ?) ...
I don't believe we need PL_strcpy, nsCRT::memcpy, etc. any longer.  The
rationale for these is almost lost in the mists of time (I dimly recall an HP-UX
memcpy bug from 1996).  jdunn, do you agree?

I see lots of Mozilla code using memcpy, strlen, etc. and porting as well as any
other code.  I see on reason to rub these hold-over "portability worry beads"
any longer.  Sorry I didn't say this earlier.

/be
I can't recall the memcpy issue from '96.
The lastest patch does look ok, however
you should get Shanmu to look at this on Tru64
(unless someone else has done a 64bit build?!?)
However, it looks ok to me.  Shanmu, can you
try to make sure the latest patch compiles on
Tru64?  I have no idea how to test it...

I also agree with Brendan maybe it is time we
go thru and look at removing nsCRT::memcpy's
but if we do, we should do that as a separate
issue since it is going to consume a bunch of 
time (I assume we will do performance analysis
on it as well)
Attachment #62787 - Attachment is obsolete: true
Attachment #62788 - Attachment is obsolete: true
Attachment #62884 - Attachment is obsolete: true
Comment on attachment 63501 [details] [diff] [review]
updated patch ues ::memcpy directly

r=Roland.Mainz@informatik.med.uni-giessen.de
Attachment #63501 - Flags: review+
I am confused.  What is the significance of using 
::memcpy and NOT memcpy?
|::memcpy()| requests explicitly a "_mempy" symbol from the (flat) ANSI-C
namespace.
|memcpy| can be anything... function, macro... what you want (or what the
compiler can offer... :) ...
The latest patch compiled on a Tru64 UNIX machine.
jdunn: agreed, we can leave existing nsCRT::memcpy usage, but I don't see any
reason to add new uses.

sr=brendan@mozilla.org contingent on successful Tru64 testing (code looks good
to me, but test platform coverage is key here).

/be
Ok, but for the record I don't want to keep ANY instances
of nsCRT::memcpy around.  Lets open another bug and use
that one to clean them up (I think that is the consensus.
Comment on attachment 63501 [details] [diff] [review]
updated patch ues ::memcpy directly

jdunn: sorry I was unclear, I meant we don't need to hassle with
nsCRT::memcpy=>memcpy in existing code touched by this or another bug that's
already on file, we can use the new bug ftang kindly filed to do the cleanup,
as you say.

ftang: thanks for filing that!

sr=brendan@mozilla.org.

/be
Attachment #63501 - Flags: superreview+
jdunn: ::memcpy is pure C++ for "call the standard memcpy in the global
namespace, which must conform to the standard."  Calling memcpy (no ::) might
call some other method if we had a default namespace that was not the global or
standard one, or if someone added memcpy to the class whose method contains the
call, or whatever.

Since it would be evil, and prolly break lots of code, for anyone to name any
method memcpy other than the standard global function, this is more a
purity-of-essence or style issue.  It's ok with me to call memcpy either way,
but I defer to the C++ experts (cc'ing dbaron).

/be
Roland: ::memcpy does *not* explicitly request a _memcpy symbol from anywhere,
AFAIK.  I believe you are confusing linker implementation details on Unix-like
systems with the C++ standard.

Please correct me if I am wrong with something from the standard, and (better)
with real-world compilers that treat ::memcpy differently from memcpy (not that
macros expand even when their calls are preceded by punctuation such as ::).

/be
let's keep the memcpy discussion on bug 118135 please.
Blocks: 104060
No longer blocks: 104148
fixed and check in.
Status: ASSIGNED → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
No longer blocks: 104060
according to the discuss of bug 118135
the fix can change ::memcpy to memcpy
In my solaris platform, I apply this patch, it works .
but when I change the patch as below
#if IS_BIG_ENDIAN
       nsCRT::memcpy(aPropertyValue, ((char*)&val)+sizeof(void*) - aSize, 
aSize);
#else
       nsCRT::memcpy(aPropertyValue, &val, aSize);
#endif
it works too.

So I wonder should we change all nsCRT::memcpy to memcpy?
Is it useful? 

Patch works for me on Solaris.
Component: Layout: BiDi Hebrew & Arabic → Layout: Text
QA Contact: zach → layout.fonts-and-text
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: