[prev in list] [next in list] [prev in thread] [next in thread]
List: e-lang
Subject: Re: [e-lang] Bug in 0.8.28d:
From: "Mark S. Miller" <markm () caplet ! com>
Date: 2004-06-10 19:42:55
Message-ID: 6.1.0.6.2.20040610120952.042d06d8 () caplet ! com
[Download RAW message or body]
Notice of non-upwards compatibility since 0.8.27:
At 06:30 PM 6/9/2004 Wednesday, Mark S. Miller wrote:
> Those using E's persistence should avoid 0.8.28d and wait for 0.8.28e, due
> to a bug MarcS just found, whose symptoms look as follows:
>
>
> > # problem: Can't setReadOnly
> > "c:/elang/scripts/donutServices/sugarMint/mint.vat"
> >
> > #
> > # - static FileSugar#setReadOnly(OneArgFunc)
> > # . <file:c:/elang/scripts/donutServices/sugarMint/mint.vat>.setReadOnly(null)
> >
> > # @ setReadOnly/1: \
> > <jar:file:/C:/elang/e.jar!/org/erights/e/extern/persist/makeAtomicFile.emaker#:span::55:16::55:26>
> >
This bug appeared first after 0.8.27 as a result of noticing a problem with
the java.io.File API, fixing it in a way that introduced a non-upwards
compatibility, and then fixing the client code in makeAtomicFile.emaker in
wrong manner.
The problem in java.io.File is that the methods
createNewFile/0, delete/0, mkdir/0, mkdirs/0, renameTo/1,
setLastModified/1, and setReadOnly/0
are declared as returning a boolean, where these methods indicate certain
failures by returning false rather than throwing an exception. Since this is
not the normal Java or E convention, this was quite accident prone, and in
fact there were several places in our source tree where we were calling
these without checking their return result, under the assumption that any
problems would cause a non-local exit. Were were accidentally masking failures.
By 0.8.28d, these are suppressed, and corresponding sugar methods have been
added with an additional optional ejector argument. All these now do a
non-local exit on a failure (when the original returns false) according to
this optional ejector argument, i.e., an "ejection". If the extra argument
is null, then an exception is thrown. Otherwise, the argument is invoked as
a one-argument function (it's run/1 method is invoked), under the assumption
that it is an ejector (a dynamic extent continuation, as made by an escape
expression), in which case it would not return. (If the run/1 call does
return, the sugar method throws an exception anyway. See
http://www.erights.org/javadoc/org/erights/e/elib/prim/Thrower.html#eject .)
If the original throws, then the sugar method likewise throws. These are not
turned into ejections.
The mkdir/1 and mkdirs/1 sugar methods first check if the file already
exists and is already a directory, in which case they still return false,
since they didn't create the directory. Otherwise, they fail as above. If
they succeed at making the directory, they still return true.
The bug introduced into makeAtomicFile is that it was changed saying
nowFile.setReadOnly()
prevFile.setReadOnly()
to
nowFile.setReadOnly(null)
prevFile.setReadOnly(null)
However, the files in question might not exist at this point in the program,
in which case the error is no longer masked. In this case, we don't want to
do a non-local exit, so, in E 0.8.28e it's been changed to:
if (nowFile.exists()) { nowFile.setReadOnly(null) }
if (prevFile.exists()) { prevFile.setReadOnly(null) }
As a result, if the file does exist but we fail to setReadOnly, we'll still
fail.
Had we instead done a:
escape ignore {
nowFile.setReadOnly(ignore)
} catch _ {}
escape ignore {
prevFile.setReadOnly(ignore)
} catch _ {}
we would mask all failures which would cause the builtin setReadOnly/0 to
return false. If setReadOnly/0 throws a problem, the above code would
still terminate by throwing that problem.
--
Text by me above is hereby placed in the public domain
Cheers,
--MarkM
_______________________________________________
e-lang mailing list
e-lang@mail.eros-os.org
http://www.eros-os.org/mailman/listinfo/e-lang
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic