Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::os::unix::fs::MetadataExt::size() silently truncates file size on Android #28978

Closed
eefriedman opened this issue Oct 12, 2015 · 10 comments · Fixed by #31551
Closed

std::os::unix::fs::MetadataExt::size() silently truncates file size on Android #28978

eefriedman opened this issue Oct 12, 2015 · 10 comments · Fixed by #31551
Labels
O-android Operating system: Android

Comments

@eefriedman
Copy link
Contributor

The implementation of size() looks like this:

fn size(&self) -> raw::off_t { self.as_raw_stat().st_size as raw::off_t }

The field st_size has type c_longlong, and the type raw::off_t has type i32 on 32-bit Android. The combination doesn't work well.

@alexcrichton
Copy link
Member

There's not really a whole lot we can do here. Options are:

  1. Have a different trait definition on Android
  2. Create our own typedef which does the "right thing" on android
  3. Closes as WONTFIX and say that the raw as_raw_stat should be used in situations like this instead.

@eefriedman
Copy link
Contributor Author

Making raw::off_t an i64 is probably the least bad solution; it probably matches what we will do on Linux. See https://internals.rust-lang.org/t/pre-rfc-rust-and-large-file-support-lfs/2777 .

@alexcrichton
Copy link
Member

Unfortunately off_t on Android is defined to be a long which I believe is i32

@eefriedman
Copy link
Contributor Author

There isn't any hard requirement that raw::off_t has to be equivalent to the C off_t (or libc::off_t). Granted, it might be kind of confusing.

@alexcrichton
Copy link
Member

I would personally be worried about someone binding a C API that looked like:

off_t foo(ptr_t *p);

Where when transcribed into Rust with the raw module it wouldn't actually be correct. This is where defining our own typedef, though, may not be the end of the world.

@cuviper
Copy link
Member

cuviper commented Oct 12, 2015

Are you sure Android off_t is only long?

It sure looks like bionic's sys/types.h makes off_t configuration dependent:

#if defined(__USE_FILE_OFFSET64) || defined(__LP64__)
typedef int64_t off_t;
typedef off_t loff_t;
typedef loff_t off64_t;
#else
/* This historical accident means that we had a 32-bit off_t on 32-bit architectures. */
typedef __kernel_off_t off_t;
typedef __kernel_loff_t loff_t;
typedef loff_t off64_t;
#endif

Where __USE_FILE_OFFSET64 is defined over in cdef.h by the user's _FILE_OFFSET_BITS.

FWIW, I confirmed on my Nexus 9, lib/libc.so does have variants covering off_t differences, e.g. lseek and lseek64. (That's the 32-bit ARM library, vs. lib64/libc.so for aarch64.) It's nice that struct stat is defined in an always-64bit manner though.

So I wouldn't worry about someone binding some other C API with off_t -- that's already fraught with danger. I think this falls exactly into my LFS goal that @eefriedman linked on internals.

@eefriedman
Copy link
Contributor Author

Note that Android only got __USE_FILE_OFFSET64 recently, and it has limitations; see https://android.googlesource.com/platform/bionic/+/68dc20d41193831a94df04b994ff2f601dd38d10%5E!/

@cuviper
Copy link
Member

cuviper commented Oct 12, 2015

Ah, that's too bad. At least they've had most of the explicit LFS functions for a while, around late 2010, as well as 64-bit loff_t and off64_t. And I still maintain it's a bad idea for others to be using off_t in a C API.

@alexcrichton
Copy link
Member

Ah yeah the headers I was looking at didn't have these #defines (something about android version 18?). Although it's probably not the end of the world on Android as a platform just yet!

@alexcrichton
Copy link
Member

I've now opened an RFC which I hope will help enable us to fix this issue in a "backwards-compatible" fashion

alexcrichton added a commit to alexcrichton/rust that referenced this issue Feb 13, 2016
This commit is an implementation of [RFC 1415][rfc] which deprecates all types
in the `std::os::*::raw` modules.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1415-trim-std-os.md

Many of the types in these modules don't actually have a canonical platform
representation, for example the definition of `stat` on 32-bit Linux will change
depending on whether C code is compiled with LFS support or not. Unfortunately
the current types in `std::os::*::raw` are billed as "compatible with C", which
in light of this means it isn't really possible.

To make matters worse, platforms like Android sometimes define these types as
*smaller* than the way they're actually represented in the `stat` structure
itself. This means that when methods like `DirEntry::ino` are called on Android
the result may be truncated as we're tied to returning a `ino_t` type, not the
underlying type.

The commit here incorporates two backwards-compatible components:

* Deprecate all `raw` types that aren't in `std::os::raw`
* Expand the `std::os::*::fs::MetadataExt` trait on all platforms for method
  accessors of all fields. The fields now returned widened types which are the
  same across platforms (consistency across platforms is not required, however,
  it's just convenient).

and two also backwards-incompatible components:

* Change the definition of all `std::os::*::raw` type aliases to
  correspond to the newly widened types that are being returned on each
  platform.
* Change the definition of `std::os::*::raw::stat` on Linux to match the LFS
  definitions rather than the standard ones.

The breaking changes here will specifically break code that assumes that `libc`
and `std` agree on the definition of `std::os::*::raw` types, or that the `std`
types are faithful representations of the types in C. An [audit] has been
performed of crates.io to determine the fallout which was determined two be
minimal, with the two found cases of breakage having been fixed now.

[audit]: rust-lang/rfcs#1415 (comment)

---

Ok, so after all that, we're finally able to support LFS on Linux! This commit
then simultaneously starts using `stat64` and friends on Linux to ensure that we
can open >4GB files on 32-bit Linux. Yay!

Closes rust-lang#28978
Closes rust-lang#30050
Closes rust-lang#31549
bors added a commit that referenced this issue Feb 14, 2016
This commit is an implementation of [RFC 1415][rfc] which deprecates all types
in the `std::os::*::raw` modules.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1415-trim-std-os.md

Many of the types in these modules don't actually have a canonical platform
representation, for example the definition of `stat` on 32-bit Linux will change
depending on whether C code is compiled with LFS support or not. Unfortunately
the current types in `std::os::*::raw` are billed as "compatible with C", which
in light of this means it isn't really possible.

To make matters worse, platforms like Android sometimes define these types as
*smaller* than the way they're actually represented in the `stat` structure
itself. This means that when methods like `DirEntry::ino` are called on Android
the result may be truncated as we're tied to returning a `ino_t` type, not the
underlying type.

The commit here incorporates two backwards-compatible components:

* Deprecate all `raw` types that aren't in `std::os::raw`
* Expand the `std::os::*::fs::MetadataExt` trait on all platforms for method
  accessors of all fields. The fields now returned widened types which are the
  same across platforms (consistency across platforms is not required, however,
  it's just convenient).

and two also backwards-incompatible components:

* Change the definition of all `std::os::*::raw` type aliases to
  correspond to the newly widened types that are being returned on each
  platform.
* Change the definition of `std::os::*::raw::stat` on Linux to match the LFS
  definitions rather than the standard ones.

The breaking changes here will specifically break code that assumes that `libc`
and `std` agree on the definition of `std::os::*::raw` types, or that the `std`
types are faithful representations of the types in C. An [audit] has been
performed of crates.io to determine the fallout which was determined two be
minimal, with the two found cases of breakage having been fixed now.

[audit]: rust-lang/rfcs#1415 (comment)

---

Ok, so after all that, we're finally able to support LFS on Linux! This commit
then simultaneously starts using `stat64` and friends on Linux to ensure that we
can open >4GB files on 32-bit Linux. Yay!

Closes #28978
Closes #30050
Closes #31549
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-android Operating system: Android
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants