코드 품질이 낮으면 예측할 수 없는 동작이 발생합니다. 사용자 입장에서는 사용 편의성이 떨어지는 것으로 나타나는 경우가 많습니다. 공격자에게는 예상치 못한 방법으로 시스템에 부담을 줄 수 있는 기회가 됩니다.
getChunk == NULL
은 getChunk
이 프로그램에 정의된 함수의 이름이므로 항상 false가 됩니다.
if (getChunk == NULL)
return ERR;
char* getName() {
char name[STR_MAX];
fillInName(name);
return name;
}
class AccessLevel{
public static final int ROOT = 0;
//...
public static final int NONE = 9;
}
//...
class User {
private static int access;
public User(){
access = AccessLevel.ROOT;
}
public static int getAccessLevel(){
return access;
}
//...
}
class RegularUser extends User {
private static int access;
public RegularUser(){
access = AccessLevel.NONE;
}
public static int getAccessLevel(){
return access;
}
public static void escalatePrivilege(){
access = AccessLevel.ROOT;
}
//...
}
//...
class SecureArea {
//...
public static void doRestrictedOperation(User user){
if (user instanceof RegularUser){
if (user.getAccessLevel() == AccessLevel.ROOT){
System.out.println("doing a privileged operation");
}else{
throw new RuntimeException();
}
}
}
}
User
또는 RegularUser
클래스가 아닌 user
인스턴스에 대해 getAccessLevel()
메서드를 호출하므로 이 조건에서는 항상 true
가 반환됩니다. 그리고 이 if/else
블록 부분으로 진입하기 위해 instanceof
를 사용했더라도 제한된 작업이 수행됩니다.serialPersistentFields
를 올바르게 사용하려면 private
, static
및 final
로 선언되어야 합니다.serialPersistentFields
배열에서 지정하여 클래스에 대해 Serializable 필드를 수동으로 정의할 수 있습니다. 이 기능은 serialPersistentFields
가 private
, static
및 final
로 선언된 경우에만 작동합니다.serialPersistentFields
선언은 private
, static
및 final
이 아니기 때문에 Serializable
필드를 정의하는 데 사용되지 않습니다.
class List implements Serializable {
public ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("myField", List.class) };
...
}
java.util.Arrays.equals().
대신 배열에 대해 Object.equals()
를 호출합니다.Object.equals()
호출은 잘못된 것입니다. 이와 같이 호출하면 배열 요소가 아니라 배열 주소가 같은지를 확인하기 때문입니다. 일반적으로는 java.util.Arrays.equals()
를 대신 호출해야 합니다. Object.equals()
함수를 사용하여 두 배열 확인을 시도합니다.
...
int[] arr1 = new int[10];
int[] arr2 = new int[10];
...
if (arr1.equals(arr2)){
//treat arrays as if identical elements
}
...
pthread_cleanup_push()
를 사용하여 함수 routine
을 호출 스레드의 정리 스택으로 푸시하고 반환합니다. pthread_cleanup_push()
와 해당 파트너 함수인 pthread_cleanup_pop()
은 IBM AIX가 아닌 플랫폼에서 매크로로 구현되므로 pthread_cleanup_push()
에 의해 생성되는 데이터 구조는 이후의 pthread_cleanup_pop()
호출에 액세스할 수 없게 됩니다. 코드가 컴파일에 실패하거나 이러한 함수가 매크로로 구현되는 모든 플랫폼에서는 런타임 시 코드가 올바로 작동하지 않습니다.
void helper() {
...
pthread_cleanup_push (routine, arg);
}
void clean_up()
{
char tmp[256];
...
free(tmp);
return;
}
System.Object.Equals()
를 오버라이드합니다.
public boolean Equals(string obj) {
...
}
System.Object.Equals()
가 object
유형의 인수를 받기 때문에 해당 메서드는 호출되지 않습니다.Object.equals()
를 오버라이드합니다.
public boolean equals(Object obj1, Object obj2) {
...
}
Object.equals()
가 하나의 인수만 받기 때문에 Example 1
의 메서드는 호출되지 않습니다.ISerializable
인터페이스를 구현하지만 [Serializable]
속성을 선언하지 않는 클래스는 직렬화되지 않습니다.[Serializable]
속성을 선언하는 모든 개체의 serialization을 허용합니다. .NET 프레임워크에 의해 정의된 기본 serialization 메서드를 사용하여 클래스를 직렬화할 수 있으면 개체를 정확하게 직렬화해야 할 필요와 직렬화하기 위한 충분한 조건이 충족됩니다. 클래스가 사용자 지정 serialization 메서드를 사용해야 하는 경우 ISerializable
인터페이스도 구현해야 합니다. 그러나, 이 경우에도 클래스는 [Serializable]
속성을 선언해야 합니다.CustomStorage
클래스는 ISerializable
인터페이스를 구현합니다. 그러나, [Serializable]
속성의 선언이 실패하므로 직렬화되지 않습니다.
public class CustomStorage: ISerializable {
...
}
java.io.Serializable
을 구현하는 inner class를 사용하면 outer class에서 문제가 발생하고 정보가 누출될 수 있습니다.
...
class User implements Serializable {
private int accessLevel;
class Registrator implements Serializable {
...
}
}
Example 1
에서 inner class Registrator
를 serialize하면 outer class User
의 accessLevel
필드도 serialize됩니다.synchronized
메서드를 선언했고 여러 스레드가 동일한 인스턴스에 접근할 때 올바른 동작을 보장합니다. 또한 모든 오버라이드 메서드는 synchronized
로 선언되어야 합니다. 그렇지 않으면 예기치 못한 동작이 발생할 수도 있습니다.Foo
클래스는 Bar
클래스를 오버라이드하지만 synchronizedMethod
메서드를 synchronized
로 선언하지 않습니다.
public class Bar {
public synchronized void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
public class Foo extends Bar {
public void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
Foo
의 인스턴스가 Bar
유형으로 배정될 수 있습니다. 같은 인스턴스를 서로 다른 두 스레드에 지정하고 synchronizedMethod
를 반복 실행하면 동작을 예측할 수 없게 됩니다.obj.Equals(null)
는 항상 false가 됩니다.Equals()
메서드를 사용하여 개체를 null
과 비교합니다. Equals()
메서드의 약정이 항상 false로 반환되도록 비교해야 합니다.obj.equals(null)
는 항상 false가 됩니다.equals()
메서드를 사용하여 개체를 null
과 비교합니다. 이 비교는 개체가 null
이 아니기 때문에 항상 false를 반환합니다. (개체가 null
이면 프로그램에 NullPointerException
이 발생합니다).main()
함수에서 pthread_create()
를 호출하여 생성된 스레드는 해당 스레드가 pthread_exit()
을 호출하기 전에 상위 프로세스의 실행이 완료되면 비정상적으로 조기 종료됩니다. pthread_exit()
를 호출하면 상위 프로세스가 모든 해당 스레드의 실행이 완료될 때까지 그대로 유지됩니다. 또는 상위 프로세스가 모든 하위 스레드에서 pthread_join
을 호출할 수 있으며 프로세스가 끝나기 전에 완료할 수 있도록 합니다.pthread_create()
를 사용하여 스레드를 생성하고 정상적으로 종료되도록 합니다. 하위 스레드가 main()
함수가 반환될 때 까지 해당 실행을 완료하지 않는 경우, 비정상적인 조기 종료가 발생합니다.
void *Simple(void *threadid)
{
...
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
int rc;
pthread_t pt;
rc = pthread_create(&pt, NULL, Simple, (void *)t);
if (rc){
exit(-1);
}
}
readObject()
메서드는 재정의할 수 있는 함수를 호출합니다.readObject()
는 생성자로 사용되므로 이 함수가 종료될 때까지는 개체 초기화가 완료되지 않습니다. 따라서 Serializable
클래스의 readObject()
함수가 오버라이드 가능 함수를 호출하면 개체가 완전히 초기화되기 전에 오버라이드 메서드가 개체 상태에 접근할 수 있습니다.readObject()
함수는 오버라이드할 수 있는 메서드를 호출합니다.
...
private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
checkStream(ois);
ois.defaultReadObject();
}
public void checkStream(ObjectInputStream stream){
...
}
checkStream()
함수와 이 함수를 포함하는 클래스는 final
및 public이 아니므로 함수를 오버라이드할 수 있습니다. 이로 인해 공격자는 checkStream()
함수를 오버라이드하여 역직렬화 중에 개체에 접근할 수 있습니다.private readonly
목록 변수를 반환하면 호출 코드가 목록의 콘텐트를 수정할 수 있기 때문에 사실상 목록 쓰기 액세스 권한을 부여하게 되어 private readonly
로 선언한 프로그래머의 의도와는 반대가 됩니다.private readonly
로 선언된 _item
목록이 포함되어 있습니다.
class Order
{
private readonly List<string> _item = new List<string>();
public IEnumerable<string> Item { get { return _item; } }
public Order()
{
/*class initialize */
}
/*some important function......*/
}
Marker child = MarkerManager.getMarker("child");
Marker parent = MarkerManager.getMarker("parent");
child.addParents(parent);
parent.addParents(child);
String toInfinity = child.toString();
toString()
을 호출할 때 스택 오버플로 예외(스택 소진)를 트리거합니다. 이 예외는 자식과 부모 간의 순환 링크로 인해 발생합니다.String
개체와 비교하는 작업은 불안정하므로 수행해서는 안 됩니다.String
개체에 비교하려면 먼저 해당 값을 String
개체로 변경해야 합니다. 일반적으로 Double.toString()
과 같은 함수를 통해 변경합니다. 부동 소수점 변수의 값과 유형에 따라 String
개체로 변환할 때 해당 값은 "NaN", "Infinity", "-Infinity"가 되거나, 0이 포함된 후행 소수점을 일정 수만큼 포함하거나, 지수 필드를 포함할 수 있습니다. 16진수 문자열로 변환하는 경우에도 표현이 매우 달라질 수 있습니다.String
과 비교합니다.
...
int initialNum = 1;
...
String resultString = Double.valueOf(initialNum/10000.0).toString();
if (s.equals("0.0001")){
//do something
...
}
...
if
문에 대한 조건을 만족할 수 없습니다. s
에 null이 아닌 값을 지정할 수 있는 경로에서만, return
문이 있는 동안 s
가 null이 아닌 값이어야 합니다.
String s = null;
if (b) {
s = "Yes";
return;
}
if (s != null) {
Dead();
}