Ursache ist ein ungeprüfter Typecast.

Nick schrieb:

Für C-Programmierer müsste man mal ein Programm schreiben, das sowas überprüft.

Man wird davon ausgehen können, daß der Kram nicht in C geschrieben ist. Die im Artikel erwähnte NegativeArraySizeException ist etwas, was es in Java gibt ...

Neuzeitlichere Compiler wie z.B. Clang/llvm haben eine deutlich bessere Quelltextprüfung, die lint nicht mehr unbedingt erforderlich machen.

Harald K. schrieb:

ist etwas, was es in Java gibt

und die engine für Java ist in C geschrieben.

Harald K. schrieb:

Neuzeitlichere Compiler wie z.B. Clang/llvm haben eine deutlich bessere Quelltextprüfung,

Sowas lässt sich leicht schreiben, wenn man noch nie lint verwendet hat (Unterstellung). Lint kann so richtig nerven, bis jetzt ist mir das noch nicht bei C-Compilern untergekommen.

Nick schrieb:

und die engine für Java ist in C geschrieben

Hier ist eher das Problem, dass Java keine unsigned integer Typen kennt.

Der Array-Konstruktor kriegt deshalb seine Längenangabe "signed" und muss sich zur Laufzeit mit einer Exception gegen negative Array-Längen wehren.

in C erwartet malloc ein (unsigned) size_t, negative Angaben sind also nicht möglich.

Macht es aber nicht besser, das ungeprüft übernommene Lägenfeld aus der WAP-Message wäre dann ein Out-of-Memory Fehler zur Laufzeit, wenn nicht behandelt mit demselben Resultat wie in Java.

Sowohl Java als auch C sind stark typisierte Sprachen. Die Typen werden natürlich auch geprüft. Nur hat man hier halt einen expliziten Typcast gemacht. In Rust wäre etwas vergleichbares vermutlich, das "unsafe" Keyword zu nutzen. Irgend ein zusätzlicher Linter wäre hier auch nutzlos. Ein Linter ist eher was für dynamisch typisierte Sprachen.

https://en.wikipedia.org/wiki/Type_safety

Ich hab schon ewig keine Java mehr verwendet. Dass man damit casten kann habe ich wohl vergessen. Aber es kann (vermutlich) nur casten auf kleinere Typen (64 -> 32 Bit).

Daniel A. schrieb:

Ein Linter ist eher was für dynamisch typisierte Sprachen.

Weder C noch Java sind dynamische Sprachen. lint wurde ursprünglich für C entwickelt und das aus gutem Grund. Java ist u.a. angetreten um die Probleme von C zu verhindern.

Persönliche Seite

Naja eigentlich kann keine Sprache vor so einem Problem schützen. Java schützt ja schon indem es eben eine Exception wirft. Selbst mit unsigned Typen wäre eine zu große Array-Größe ebenso problematisch und würde in einer Exception resultieren. Genau das macht übrigens Kotlin, welches (u.a.) auf der JVM läuft aber unsigned Typen bietet.

Natürlich muss man alle extern rein kommenden Daten immer prüfen, ganz besonders wenn man sie als Allokationsgröße oder Index verwendet. Weiterhin muss man beim Interpretieren von solchen Nachrichten sowieso die Exceptions abfangen, und dann im Fehlerfall die Nachricht ignorieren und mit der nächsten Nachricht weiter machen, statt den ganzen Service abstürzen zu lassen. Irgendwas kann halt immer schief gehen, Exceptions lassen sich nicht wirklich 100% verhindern - der Sinn von Exceptions ist ja sowieso, dass man sauber drauf reagieren kann, in dem Fall halt indem man die Nachricht ignoriert (und eine Log-Meldung ausgibt). Es sind also eigentlich zwei Fehler, wäre es nur an einer dieser Stellen gut umgesetzt gäbe es hier kein Problem.

Man fragt sich ein bisschen warum es so lange dauert, ein "if(x > 0)" sowie ein "try-catch" einzubauen und warum das in alten Android-Versionen gar nicht möglich sein soll.

Nick schrieb:

Aber es kann (vermutlich) nur casten auf kleinere Typen (64 -> 32 Bit).

Also die Zahl-Typen kann man in Java in alle Richtungen hin und her casten, natürlich ggf. mit Datenverlust. Klassen kann man downcasten, also wenn man eine Referenz vom Typ einer Basisklasse hat, die auf eine Instanz einer abgeleiteten Klasse referenziert, kann man sie auf den Typ der abgeleiteten Klasse umwandeln. Konzeptuell recht ähnlich zu C++.

: Bearbeitet durch User

Nick schrieb:

Sowas lässt sich leicht schreiben, wenn man noch nie lint verwendet hat (Unterstellung). Lint kann so richtig nerven, bis jetzt ist mir das noch nicht bei C-Compilern untergekommen.

Ich kenne lint; ich habe lint schon verwendet, als C89 noch ganz, ganz frisch war (da in der Variante "flexe-lint" von Gimpel). Ich kenne aber auch clang/llvm; genauer: ich arbeite damit.

Nick schrieb:

Ich hab schon ewig keine Java mehr verwendet. Dass man damit casten kann habe ich wohl vergessen. Aber es kann (vermutlich) nur casten auf kleinere Typen (64 -> 32 Bit).

Ich geb dirr mal ein Beispiel von einem Cast, der in Java erlaubt ist:

1
class A {
2
    public void do_a(){
3
        System.out.println("A");
4
    }
5
};
6

7
class B {
8
    public void do_b(){
9
        System.out.println("B");
10
    }
11
};
12

13
class Main {
14
    public static void main(String[] args) {
15
        Object obj = new B();
16
        if(obj instanceof A){
17
            A x = (A)obj;
18
            x.do_a();
19
        }else if(obj instanceof B){
20
            B x = (B)obj;
21
            x.do_b();
22
        }else{
23
            System.out.println("nope");
24
        }
25
    }
26
}

Macht man den instanceof Check nicht, und Castet falsch, endet man halt mit einer Exception.
Wenn man die Option hat, sind natürlich andere Optionen, wie z.B. interfaces oft besser. Und so eine Exception kann sogar erwünscht sein, die abzufangen statt vorher zu prüfen ist auch ein valider Style:

1
interface Doable {
2
    public void doit();
3
};
4

5
class A implements Doable {
6
    public void doit(){
7
        System.out.println("A");
8
    }
9
};
10

11
class B implements Doable {
12
    public void doit(){
13
        System.out.println("B");
14
    }
15
};
16

17
class Main {
18
    public static void main(String[] args) {
19
        Object obj = new A();
20
        try {
21
            Doable x = (Doable)obj;
22
            x.doit();
23
        } catch(ClassCastException e){
24
            System.out.println("nope");
25
        }
26
   }
27
}

Harald K. schrieb:

Ich kenne lint; ich habe lint schon verwendet, als C89 noch ganz, ganz frisch war

Naja, bei <= c89 gab folgendes bei Compilern höchstens eine Warnung, wurde dann halt implizit Konvertiert. Aber bei allen mir bekannten heutigen Compilern, ab c99, produziert es einen harten Fehler:

1
struct A { int x; };
2
struct B { int x; };
3

4
int main(){
5
    struct A a = {0};
6
    struct B* x = &a;
7
}

Bei c89 hatte man also wirklich nicht viel von der statischen Typisierung, da konnte ein linter noch Sinn machen. Aber bei allem danach ist ein Linter nur noch dafür gut, komplett valide Programme anzumotzen und zu nerven, falls er den modernen C code überhaupt zu Parsen vermag.
Bei Dynamischen Sprachen sind Linter hingegen oft die einzige Möglichkeit, type checking statisch unabhängig von der Ausführung zu machen, daher kann das dort noch Sinn machen. Wobei, man kann auch sagen, damit verliert man den Vorteil der Dynamischen Typisierung, sich nicht immer mit den Typen herumschlagen zu müssen.

Wo auch immer man sie nutzt, Linter nerven hauptsächlich nur, das ist Fakt.

Daniel A. schrieb:

1
    Object obj = new B();
2
    if(obj instanceof A){

Macht man den instanceof Check nicht, und Castet falsch, endet man halt mit einer Exception.

Das ist (zumindest für mich) kein cast. Da wird der Typ abgefragt und dann auch der richtige Typ verwendet.

Daniel A. schrieb:

Doable x = (Doable)obj;

Das schon. Aber es gibt zwei Arten von casts: Implizip und explizip.

Implizip ist z.B. wenn man einen int32 auf einen int64 zuweist, denn das ist zulässig und führt nicht zu Fehlern.
Explizip wäre dann die andere Richtung. Und das kann zu Fehlern führen und man muss es auch explizip so schreiben. i32 = (int32_t)i64

Norbert schrieb:

Roland F. schrieb:

Norbert schrieb:

Hab' direkt erst einmal WAP-Push abgeschaltet.

Wie macht man das?

Hab's in den c't Kommentaren gefunden. Nachrichten(Messenger) · Einstellungen · weitere Einstellungen · WAP-Push Aus

Unter Android 16 finde ich WAP-Push und kann es auf AUS stellen.

Unter Android 15 finde ich WAP-Push nicht mehr. Mein S21 kam wohl damals mit Android 11 neu heraus und sollte laut Wicki bis Android 15 noch Updates erhalten.

mfg Klaus

Nein, ich habe normalerweise "-std=c17 -Wall -Wextra -pedantic -Werror" als Compiler Optionen. Wobei, manchmal deaktiviere ich manche Warnungen schon, wenn ich z.B. absichtlich nicht alle struct Felder initialisiere oder so.
Wenn man den Compiler, statt einen separaten Linter verwendet, interpretieren die den Code wenigstens nicht beide unterschiedlich. (Und ja, mit meinem Code kommt so mancher linter oft nicht zurecht).

PS: -Wall -Wextra -pedantic -Werror aktiviert noch nicht alle Warnungen, es gibt welche, die zu häufig unerwünscht wären, oder falsch positive generieren würden, die man explizit einschalten müsste. So Compiler Warnungen sind fiel Praxisnäher und Brauchbarer, als was separate Linter normalerweise so absondern.

: Bearbeitet durch User

Nick schrieb:

Aber es gibt zwei Arten von casts: Implizip und explizip.

Die Java Language Specification kennt kein implizites Casten. Casten ist immer explizit, man muß es hinschreiben.

Implizip ist z.B. wenn man einen int32 auf einen int64 zuweist

Das ist kein Casten sondern eine implizite Konvertierung, genauer eine Widening Primitive Conversion. Siehe 5.1.2 in https://docs.oracle.com/javase/specs/jls/se27/jls27.pdf.

Antwort schreiben

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.